MCDLabs.Utility.SqlHelper.TableHint
1.0.3
dotnet add package MCDLabs.Utility.SqlHelper.TableHint --version 1.0.3
NuGet\Install-Package MCDLabs.Utility.SqlHelper.TableHint -Version 1.0.3
<PackageReference Include="MCDLabs.Utility.SqlHelper.TableHint" Version="1.0.3" />
<PackageVersion Include="MCDLabs.Utility.SqlHelper.TableHint" Version="1.0.3" />
<PackageReference Include="MCDLabs.Utility.SqlHelper.TableHint" />
paket add MCDLabs.Utility.SqlHelper.TableHint --version 1.0.3
#r "nuget: MCDLabs.Utility.SqlHelper.TableHint, 1.0.3"
#:package MCDLabs.Utility.SqlHelper.TableHint@1.0.3
#addin nuget:?package=MCDLabs.Utility.SqlHelper.TableHint&version=1.0.3
#tool nuget:?package=MCDLabs.Utility.SqlHelper.TableHint&version=1.0.3
MCDLabs.Utility.SqlHelper.TableHint
Açıklama
MCDLabs.Utility.SqlHelper.TableHint, Entity Framework Core 9.0+ ile SQL Server table hints (tablo ipuçları) kullanmanızı sağlayan güçlü bir kütüphanedir. Bu kütüphane, LINQ sorguları yazarken doğrudan SQL Server table hints uygulamanıza olanak tanır ve sorgu performansını optimize etmenize yardımcı olur.
Özellikler
✅ Entity Framework Core 9.0+ Desteği - En yeni EF Core sürümleri ile tam uyumluluk
✅ Fluent API - Sorgulanabilir nesneler üzerinde doğrudan hint uygulama
✅ Kapsamlı Hint Desteği - 20+ SQL Server table hint
✅ Async/Sync Destek - Hem senkron hem de asenkron sorgulamayı destekler
✅ Performans Optimizasyonu - Sorgu planlayıcısına ipuçları vererek performansı artırın
✅ InMemory Provider Uyarısı - InMemory provider kullananlar için otomatik hata bildirimi
Desteklenen Table Hints
| Hint | Açıklama |
|---|---|
FORCESCAN |
Sorgu planlayıcısını tablo taraması yapmaya zorlar |
FORCESEEK |
Sorgu planlayıcısını dizin araması yapmaya zorlar |
HOLDLOCK |
Satırı sorgu bitene kadar kilitli tutar |
NOLOCK |
Kilit olmadan okuma (Dirty Read izin verir) |
NOWAIT |
Kilit beklemeyi devre dışı bırakır |
PAGLOCK |
Sayfa düzeyinde kilitler |
ROWLOCK |
Satır düzeyinde kilitler |
TABLOCK |
Tablo düzeyinde paylaşımlı kilit |
TABLOCKX |
Tablo düzeyinde özel kilit |
READCOMMITTED |
READ COMMITTED izolasyon seviyesi |
READUNCOMMITTED |
READ UNCOMMITTED izolasyon seviyesi |
REPEATABLEREAD |
REPEATABLE READ izolasyon seviyesi |
SERIALIZABLE |
SERIALIZABLE izolasyon seviyesi |
SNAPSHOT |
SNAPSHOT izolasyon seviyesi |
UPDLOCK |
Güncelleştirme kilitler |
XLOCK |
Özel kilit |
READPAST |
Kilitli satırları atlar |
READCOMMITTEDLOCK |
READ COMMITTED LOCK izolasyon seviyesi |
Kurulum
NuGet Paketi
dotnet add package MCDLabs.Utility.SqlHelper.TableHint
veya Package Manager Console:
Install-Package MCDLabs.Utility.SqlHelper.TableHint
Hızlı Başlangıç
1. DbContext Yapılandırması
DbContext'inizi yapılandırırken interceptor'u ekleyin:
using MCD.EFCore.TableHint.Extensions;
var optionsBuilder = new DbContextOptionsBuilder<YourDbContext>();
optionsBuilder
.UseSqlServer(connectionString)
.UseNoLockInterceptor(); // Interceptor'u ekleyin
var context = new YourDbContext(optionsBuilder.Options);
2. LINQ Sorgularında Hint Uygulama
Tüm Tablolara Otomatik Hint Uygulama
applyToAllEntities: true parametresi kullanarak DbContext'teki TÜM entity türlerine otomatik olarak hint uygulayabilirsiniz:
// DbContext'teki tüm tablolara NOLOCK hint'ini otomatik uygula
var users = dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK, applyToAllEntities: true)
.Where(u => u.IsActive)
.ToList();
// Kısa syntax (applyToAllEntities parametresi olarak true geçir)
var orders = dbContext.Orders
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK, true)
.Where(o => o.TotalAmount > 100)
.ToList();
Avantajları:
- Manuel olarak her tablo için
typeof()belirtmek zorunda değilsiniz - DbContext'teki tüm tabloları otomatik olarak kapsar
- Include edilen related entities'ler de hint'i alır
Temel Kullanım (Tek Tablo)
var users = dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK)
.Where(u => u.IsActive)
.ToList();
Birden Fazla Hint Kombinasyonu
var users = dbContext.Users
.WithHint(dbContext,
SqlServerTableHintFlags.NOLOCK | SqlServerTableHintFlags.ROWLOCK)
.Where(u => u.Age > 18)
.ToList();
Belirli Tip İçin Hint Uygulama
// Sadece User tablosu için NOLOCK uygula
var result = dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK, typeof(User))
.Include(u => u.Orders)
.ToList();
Birden Fazla Tablo İçin Hint Uygulama
// Hem User hem de Order tabloları için NOLOCK uygula
var result = dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK,
typeof(User), typeof(Order))
.Include(u => u.Orders)
.ToList();
3. Async Sorgular
var users = await dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK)
.Where(u => u.IsActive)
.ToListAsync();
Mimarı
Temel Bileşenler
1. BaseQueryHookAction (Abstractions/BaseQueryHookAction.cs)
Tüm hook eylemlerinin temel sınıfı. Hint bilgilerini yönetir.
public abstract class BaseQueryHookAction
{
public abstract string GetKey();
public abstract bool IsOf(Type type);
}
2. TableHintBuilder (Abstractions/TableHintBuilder.cs)
Table hint'leri tanımlamak için temel builder sınıfı.
public abstract class TableHintBuilder : BaseQueryHookAction
{
public string Hint { get; set; }
public SqlServerTableHintFlags SqlServerTableHint { get; set; }
}
3. QueryHookCommandInterceptor (Infrastructure/Interceptor/QueryHookCommandInterceptor.cs)
EF Core komut interceptor'u. SQL komutlarını değiştirir ve hint'leri enjekte eder.
Temel Görevleri:
- SQL komutlarını yakalar
- Hint bilgilerini çıkarır
- Target table adlarını belirler
- SQL'e table hints ekler
4. QueryHookManager (Infrastructure/QueryHookManager.cs)
Hook eylemlerini yönetir ve Cache'ler.
public static class QueryHookManager
{
public static IQueryable<T> Hook<T>(
IQueryable<T> query,
DbContext context,
BaseQueryHookAction hookAction)
}
5. WithHintExtensions (Infrastructure/WithHintExtensions.cs)
LINQ sorguları üzerine WithHint() extension method'u sağlar.
public static class WithHintExtensions
{
public static IQueryable<T> WithHint<T>(
this IQueryable<T> source,
DbContext context,
SqlServerTableHintFlags hint,
params Type[] types)
}
İş Akışı
LINQ Query
↓
WithHint() Extension Method çağrılır
↓
Hook Action (TableHintBuilder<T>) oluşturulur
↓
QueryHookManager.Hook() - Hint Cache'e eklenir
↓
Query TagWith() ile işaretlenir (MCD_EFCORE: prefix ile)
↓
Sorgu Çalıştırılır
↓
QueryHookCommandInterceptor.ReaderExecuting() tetiklenir
↓
SQL Komutundan Tag Çıkarılır
↓
Target Tablo Adları Belirlenir
↓
Table Hints SQL'e Eklenir
↓
Değiştirilmiş SQL Komut Çalıştırılır
↓
Sonuçlar Döndürülür
İleri Seviye Kullanım
Özel Hint Mesajları
// Özel hint mesajı ile sorgu
var users = dbContext.Users
.Where(u => u.Department == "Sales")
.ToList();
// SQL'de görülecek hint:
// FROM [Users] WITH (NOLOCK, ROWLOCK)
Join Sorguları
var result = (from u in dbContext.Users.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK)
join o in dbContext.Orders.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK)
on u.Id equals o.UserId
select new { u.Name, o.OrderDate })
.ToList();
Include ile Birlikte Kullanım
var users = dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK, typeof(User), typeof(Order))
.Include(u => u.Orders)
.Include(u => u.Addresses)
.ToList();
Önemli Notlar ⚠️
InMemory Provider Uyarısı
Bu kütüphane sadece gerçek veritabanı sağlayıcıları (SQL Server, PostgreSQL, MySQL vb.) ile çalışır. InMemory provider kullanıyorsanız aşağıdaki hata alırsınız:
NotSupportedException: EFCore InMemory provider, interceptor
gerektiren query hook uzantılarını desteklemez.
Çözüm: Unit test'lerinizde InMemory provider yerine Testcontainers veya test veritabanı kullanın.
Weak Reference Caching
Kütüphane ConditionalWeakTable kullanarak DbContext örneklerine bağlı hint cache'i tutar. DbContext serbest bırakıldığında, otomatik olarak garbage collection'a gider.
Kilit Seviyeleri
Hint uygulanırken dikkatli olun:
- NOLOCK: Performans en yüksek ama "Dirty Read" riski var
- TABLOCK: Tüm tabloyu kilitler, diğer sorgular bekler
- FORCESEEK/FORCESCAN: Sorgu planlayıcısı seçimini override eder
Örnek Senaryolar
Senaryo 1: Yoğun Okuma Işlemleri
public async Task<IEnumerable<UserDto>> GetActiveUsersAsync()
{
return await dbContext.Users
.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK)
.Where(u => u.IsActive)
.Select(u => new UserDto
{
Id = u.Id,
Name = u.Name,
Email = u.Email
})
.ToListAsync();
}
Senaryo 2: Raporlama Sorguları
public async Task<SalesReport> GetSalesReportAsync(DateTime startDate)
{
var sales = await dbContext.Orders
.WithHint(dbContext, SqlServerTableHintFlags.FORCESEEK)
.Where(o => o.CreatedDate >= startDate)
.GroupBy(o => o.SalesPersonId)
.Select(g => new {
SalesPersonId = g.Key,
TotalAmount = g.Sum(o => o.Amount)
})
.ToListAsync();
return new SalesReport { Sales = sales };
}
Senaryo 3: Belirli Kilit Stratejisi
public async Task<bool> TransferFundsAsync(int fromAccountId, int toAccountId, decimal amount)
{
using var transaction = await dbContext.Database.BeginTransactionAsync();
try
{
// Hesapları UPDLOCK ile kilitler
var fromAccount = await dbContext.Accounts
.WithHint(dbContext, SqlServerTableHintFlags.UPDLOCK)
.FirstOrDefaultAsync(a => a.Id == fromAccountId);
var toAccount = await dbContext.Accounts
.WithHint(dbContext, SqlServerTableHintFlags.UPDLOCK)
.FirstOrDefaultAsync(a => a.Id == toAccountId);
fromAccount.Balance -= amount;
toAccount.Balance += amount;
await dbContext.SaveChangesAsync();
await transaction.CommitAsync();
return true;
}
catch
{
await transaction.RollbackAsync();
return false;
}
}
Sorun Giderme
Problem: "DbContext not found" hatası
Çözüm: WithHint() çağrısında DbContext örneğini doğru şekilde geçirdiğinizden emin olun:
// ❌ Yanlış
var users = dbContext.Users.WithHint(null, SqlServerTableHintFlags.NOLOCK);
// ✅ Doğru
var users = dbContext.Users.WithHint(dbContext, SqlServerTableHintFlags.NOLOCK);
Problem: Hint SQL'de görünmüyor
Çözüm:
- Interceptor'un DbContext yapılandırmasında kayıtlı olduğundan emin olun
- SQL Server profiler ile gerçek SQL komutunu kontrol edin
- InMemory provider kullanmadığınızdan emin olun
Problem: "NotSupportedException" hatası
Çözüm: InMemory provider kullanıyorsanız, gerçek bir SQL Server veritabanı bağlantısı kullanın.
Performans İpuçları
- NOLOCK Kullanın: Salt okunur sorgularda
NOLOCKkullanarak performansı artırın - FORCESEEK/FORCESCAN: Sorgu planlayıcısı suboptimal seçim yapıyorsa kullanın
- Uygun Kilit Seviyeleri:
ROWLOCKvePAGLOCKtablo kilitleri yerine tercih edin - Endeks Stratejisi: Hint'ler endeks stratejisini tamamlar, endeksleri optimize edin
Gereksinimler
- .NET Runtime: .NET 9.0 veya daha yeni
- Entity Framework Core: 9.0.8 veya daha yeni
- Veritabanı: SQL Server 2016 veya daha yeni
Versiyon Tarihi
| Versiyon | Tarih | Değişiklikler |
|---|---|---|
| 1.0.2 | 2026-05-17 | Başlangıç sürümü |
| 1.0.1 | - | - |
| 1.0.0 | - | - |
Lisans
Bu proje MIT Lisansı altında lisanslanmıştır. Ayrıntılar için LICENSE dosyasına bakın.
Yazar
Mert Can Düldül
Katkılar
Katkılar açıktır! Lütfen pull request gönderin veya issue açın.
İletişim & Destek
- NuGet Paketi: MCDLabs.Utility.SqlHelper.TableHint
- GitHub: MERT_CAN_DÜLDÜL
Kaynaklar
- SQL Server Table Hints Dokumentasyonu
- Entity Framework Core Interceptors
- SQL Server Kilit Mekanizması
Sürüm: 1.0.2
Son Güncelleme: 17 Mayıs 2026
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- Microsoft.EntityFrameworkCore (>= 9.0.8)
- Microsoft.EntityFrameworkCore.Relational (>= 9.0.8)
- Microsoft.EntityFrameworkCore.SqlServer (>= 9.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.