EF Core'da AutoInclude: İlişkili Verileri Her Sorguda Otomatik Yüklemek
Umut Yalçın
25 Mar 2026

Entity Framework Core ile çalışırken ilişkili verileri yüklemek için genellikle .Include() metodunu kullanırız. Ancak bazı entity'lerde belirli bir navigation property'yi her zaman yüklemek isteriz. İşte tam bu noktada AutoInclude devreye giriyor.
Klasik Yaklaşım: Include ile Manuel Yükleme
Önce standart eager loading'i hatırlayalım. Diyelim ki bir Theme entity'miz var ve her sorguда ColorScheme'ini getirmek istiyoruz:
csharp
// Her sorguda Include yazmak zorunda kalıyoruz
var themes = await context.Themes
.Include(t => t.ColorScheme)
.ToListAsync();Bu yaklaşımda sorun şu: Uygulamanın farklı yerlerinde Theme sorgulandığında .Include(t => t.ColorScheme) yazmayı unutursak, ColorScheme null gelir ve potansiyel hatalar oluşur.
AutoInclude ile Model Konfigürasyonu
AutoInclude, bu tekrar eden .Include() yazma zorunluluğunu ortadan kaldırır. Konfigürasyon bir kez OnModelCreating içinde yapılır:
public class AppDbContext : DbContext
{
public DbSet<Theme> Themes { get; set; }
public DbSet<ColorScheme> ColorSchemes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ColorScheme, Theme sorgulandığında her zaman otomatik yüklenecek
modelBuilder.Entity<Theme>()
.Navigation(e => e.ColorScheme)
.AutoInclude();
}
}Entity Tanımları
public class Theme
{
public int Id { get; set; }
public string Name { get; set; }
// Bu navigation property artık AutoInclude ile geliyor
public ColorScheme ColorScheme { get; set; }
}
public class ColorScheme
{
public int Id { get; set; }
public string PrimaryColor { get; set; }
public string SecondaryColor { get; set; }
public string FontColor { get; set; }
}AutoInclude Sonrası Sorgular
Konfigürasyon yapıldıktan sonra artık .Include() yazmana gerek yok:
// Include yazmadan ColorScheme otomatik gelir
var themes = await context.Themes.ToListAsync();
foreach (var theme in themes)
{
// ColorScheme null değil, otomatik yüklendi
Console.WriteLine($"Theme: {theme.Name}");
Console.WriteLine($"Primary Color: {theme.ColorScheme.PrimaryColor}");
}Filtreleme ile Kullanım
// Where, OrderBy gibi işlemlerle birlikte de sorunsuz çalışır
var darkThemes = await context.Themes
.Where(t => t.Name.Contains("Dark"))
.OrderBy(t => t.Name)
.ToListAsync();
// darkThemes içindeki her Theme'in ColorScheme'i yüklü gelirAutoInclude'un Kapsamı
AutoInclude'un önemli bir özelliği şudur: Entity hangi yolla sonuçlara dahil olursa olsun AutoInclude devreye girer. Yani başka bir entity üzerinden navigation ile gelen Theme nesneleri de otomatik olarak ColorScheme'ini getirir.
public class UserSettings
{
public int Id { get; set; }
public string UserId { get; set; }
// Theme başka bir entity üzerinden geliyor
public Theme SelectedTheme { get; set; }
}// UserSettings sorgulanırken Include(u => u.SelectedTheme) ile Theme gelirse,
// Theme'in ColorScheme'i de AutoInclude sayesinde otomatik yüklenir.
var userSettings = await context.UserSettings
.Include(u => u.SelectedTheme) // Theme geliyor
// SelectedTheme.ColorScheme'i ayrıca Include etmene gerek yok!
.ToListAsync();IgnoreAutoIncludes: Gerektiğinde Devre Dışı Bırakma
Bazı durumlarda AutoInclude'u istemeyebilirsin. Örneğin sadece tema isimlerini listeleyeceksin ve ColorScheme verisine ihtiyacın yok — bu durumda gereksiz JOIN'den kaçınmak için IgnoreAutoIncludes() kullanılır:
// ColorScheme yüklenmez, daha performanslı sorgu üretilir
var themeNames = await context.Themes
.IgnoreAutoIncludes()
.Select(t => new { t.Id, t.Name })
.ToListAsync();Oluşturulan SQL Farkı
AutoInclude aktif (normal sorgu):
SELECT t.Id, t.Name, cs.Id, cs.PrimaryColor, cs.SecondaryColor, cs.FontColor
FROM Themes t
LEFT JOIN ColorSchemes cs ON cs.Id = t.ColorSchemeIdIgnoreAutoIncludes ile:
SELECT t.Id, t.Name
FROM Themes tDikkat: Owned Types ile İlişki
EF Core'da owned type olarak tanımlanmış navigation property'ler, IgnoreAutoIncludes kullansanız dahi her zaman yüklenir. Bu EF Core'un bir convention'ıdır:
csharp
public class Order
{
public int Id { get; set; }
// Owned type — AutoInclude devre dışı bırakılamaz
public Address ShippingAddress { get; set; }
}
modelBuilder.Entity<Order>().OwnsOne(o => o.ShippingAddress);// IgnoreAutoIncludes kullansanız da ShippingAddress yine gelir
var orders = await context.Orders
.IgnoreAutoIncludes()
.ToListAsync();Gerçek Dünya Senaryosu: Çok Katmanlı AutoInclude
Birden fazla entity için aynı anda AutoInclude tanımlayabilirsiniz:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Kullanıcı her sorgulandığında profil resmi gelsin
modelBuilder.Entity<User>()
.Navigation(u => u.ProfilePhoto)
.AutoInclude();
// Ürün her sorgulandığında ana kategori gelsin
modelBuilder.Entity<Product>()
.Navigation(p => p.Category)
.AutoInclude();
// Sipariş detayları her zaman para birimi ile gelsin
modelBuilder.Entity<OrderItem>()
.Navigation(oi => oi.Currency)
.AutoInclude();
}Ne Zaman AutoInclude Kullanmalısın?
Navigation property her zaman gerekli => AutoInclude kullan
Sadece bazı sorgularda gerekli => Manuel Include daha iyi
Performans kritik, bazen ihtiyaç yok => AutoInclude + IgnoreAutoIncludes kombinasyonu
Özet
AutoInclude, EF Core'da tekrar eden .Include() çağrılarını model seviyesinde merkezi olarak yönetmeni sağlar. Özellikle bir navigation property'nin domain kuralı gereği her zaman yüklenmesi gerektiği durumlarda kodunu DRY (Don't Repeat Yourself) prensibiyle temiz tutar. Gerektiğinde IgnoreAutoIncludes() ile kolayca devre dışı bırakılabildiği için esnekliği de korur.