yalcinumut
Back to all posts

EF Core'da AutoInclude: İlişkili Verileri Her Sorguda Otomatik Yüklemek

UY

Umut Yalçın

25 Mar 2026

5 min
C#
Entity Framework
EF Core'da AutoInclude: İlişkili Verileri Her Sorguda Otomatik Yüklemek

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ü gelir

AutoInclude'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.ColorSchemeId

IgnoreAutoIncludes ile:

SELECT t.Id, t.Name
FROM Themes t

Dikkat: 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.