Entity Framework Core Loading Types (Yükleme Tipleri)

Entity Framework (EF), veritabanı nesnelerini uygulama nesnelerine yüklemek için çeşitli yöntemler sunar. Bu yükleme yöntemleri, verilerin nasıl alındığı ve ilişkisel veritabanı yapılarının nasıl doldurulduğu konusunda bizlere farklı yaklaşımlar sunar. Aşağıda EF-Core üzerinde bulunan temel yükleme çeşitlerinin bir listesi verilmiştir.

  1. Eager Loading (Hemen Yükleme):
    • Eager loading, birincil nesne ile ilişkili tüm verilerin tek bir sorgu ile yüklendiği bir yükleme türüdür. Bu işlem, .Include() metodu veya .ThenInclude() metodu kullanılarak gerçekleştirilir. Eager loading kullanıldığında, ilişkili veriler ilk sorgu ile alınır ve ilişkili nesneler bağlantılıdır. Bu, veritabanına ek sorgular göndermeden tüm ilişkili verilere erişmenizi sağlar.
  2. Lazy Loading (Geç Yükleme):
    • Lazy loading, ilişkili verilere erişildiğinde yüklemenin gerçekleştiği bir yükleme türüdür. İlişkili verilere ilk erişim anında, o ilişkilendirilmiş nesnelerin veri tabanından çekilmesini sağlar. Bu, genellikle performans açısından maliyetli olabilir, ancak verilerin nerede ve ne zaman kullanılacağından emin olunmadığında kullanışlıdır.
  3. Explicit Loading (Bilinçli Yükleme):
    • Explicit loading, ilişkili verileri özel bir sorgu ile yüklemenizi sağlar. .Load() veya .LoadAsync() metodları kullanılarak yapılır. Bu yöntem, ilişkili verilere erişim anınızı kontrol etmenizi ve sadece ihtiyaç duyduğunuz zaman ilişkili verileri yüklemenizi sağlar.
  4. Projection Loading (Yansıma Yükleme):
    • Projection loading, yalnızca ihtiyaç duyduğunuz sütunları ve verileri almak için kullanılır. Bu, Select() metodu veya LINQ sorguları kullanılarak yapılır. Bu sayede yalnızca belirli alanları sorgu sonucunda alırsınız ve diğer veriler yüklenmez, bu da performans açısından avantajlı olabilir.
  5. Explicit Loading with Filters (Filtreli Bilinçli Yükleme):
    • Explicit loading with filters, belirli bir kriteri karşılayan ilişkili verileri yüklemek için kullanılır. .Where() ve .Load() yöntemleri kullanılarak filtreler tanımlanır ve yalnızca filtrelenen veriler yüklenir.

Performans

  1. Eager Loading (Hemen Yükleme):
    • Performans maliyeti yüksektir çünkü tüm ilişkili verileri tek bir sorgu ile getirir.
    • Ancak, verilere erişim anında ek sorgular gönderme gerekliliği ortadan kaldırır.
  2. Lazy Loading (Geç Yükleme):
    • İlk erişim anında veritabanına ek sorgular gönderir, bu da performans maliyetine neden olabilir.
    • İlişkili verilere tekrar tekrar erişildiğinde bu maliyet artabilir.
  3. Explicit Loading (Bilinçli Yükleme):
    • İlişkili verileri ihtiyaç duyulduğu zaman yükler, bu nedenle performans açısından daha tasarruflu olabilir.
    • Ancak, verilere erişim anınızı daha fazla kontrol edebilirsiniz.
  4. Projection Loading (Yansıma Yükleme):
    • Yalnızca belirli alanları ve verileri alır, bu nedenle performans açısından avantajlıdır.
    • Yalnızca gereken verileri almanıza olanak tanır.
  5. Explicit Loading with Filters (Filtreli Bilinçli Yükleme):
    • Belirli bir kriteri karşılayan ilişkili verileri yükler, bu nedenle gereksiz veri alımını önler.
    • Tasarruflu bir yükleme yöntemidir.

Tercih

  1. Eager Loading (Hemen Yükleme):
    • Kullanılabilirse, birincil nesne ile ilişkili tüm verilere anında erişim gerekiyorsa tercih edilebilir.
    • Özellikle ilişkili verilere sürekli olarak erişiliyorsa ve bu verilerin tümünü aynı anda çekmek veritabanı maliyetini azaltabilir.
  2. Lazy Loading (Geç Yükleme):
    • İlişkili verilere nadiren veya isteğe bağlı erişim gerekiyorsa kullanışlıdır.
    • İlişkili verilerin yüklenmesinin gerektiğinden emin olunmadığında tercih edilebilir.
    • Büyük veri setleriyle çalışıldığında veritabanı maliyetini azaltabilir.
  3. Explicit Loading (Bilinçli Yükleme):
    • İlişkili verilere erişim anını daha fazla kontrol etmek ve yalnızca ihtiyaç duyduğunuzda yüklemek istiyorsanız kullanışlıdır.
    • Birden çok ilişkili veri setini aynı anda yüklemek gerektiğinde veya filtrelerle belirli verileri yüklemek istediğinizde tercih edilebilir.
  4. Projection Loading (Yansıma Yükleme):
    • Yalnızca belirli alanları veya verileri almak istediğinizde kullanışlıdır.
    • Performans açısından avantajlıdır çünkü yalnızca ihtiyaç duyduğunuz verileri çekersiniz.
  5. Explicit Loading with Filters (Filtreli Bilinçli Yükleme):
    • Belirli bir kriteri karşılayan ilişkili verileri yüklemek gerektiğinde kullanışlıdır.
    • İlişkili verilerin belirli bir koşulu karşılaması gerektiğinde tercih edilebilir.

Eager Loading Nedir?

Eager loading, ilişkili verileri ana sorgu ile birlikte yüklemeyi amaçlar ve bu sayede veritabanından gereksinim duyulan verileri tek bir sorgu ile çeker. Bu yöntem, veritabanı erişimi ve performansı iyileştirmeye yardımcı olabilir.

Eager loading, ilişkili nesnelerin (tabloların) bağlantılı olduğu durumlarda oldukça faydalıdır. Özellikle “N-1” ilişkilerde, birincil nesne ile ilişkili olan tüm ikincil nesneleri (birincil ve ikincil tablolar arasındaki ilişkili verileri) tek bir sorgu ile almanızı sağlar.

Eager loading’i kullanmak için genellikle .Include() veya .ThenInclude() metotları kullanılır.

*Not: Tüm örneklerimiz standart Category ve Product entitlerimizin olduğu ve (1-N) ilişki bulunduğu bir senaryo üzerinden örneklendirilmiştir.

//Method Syntax ile Eager Loading-1
var products1 = context.Products.Include("Category");

foreach (var item in products1)
{
     Console.WriteLine("Kategori Adı: " + item.Category.CategoryName + " - " + item.ProductName);
}

//Method Syntax ile Eager Loading-2
var products2 = context.Products.Include(p => p.Category).Where(p => p.CategoryRefId == 2);

foreach (var item in products2)
{
     Console.WriteLine("Kategori Adı: " + item.Category.CategoryName + " - " + item.ProductName);
}

//Query Syntax ile Eager Loading-1
var products3 = from p in context.Products.Include("Category") select p;

foreach (var item in products3)
{
     Console.WriteLine("Kategori Adı: " + item.Category.CategoryName + " - " + item.ProductName);
}

//ThenInclude ile Eager Loading
//ThenInclude, birden çok  alt ilişkileri yükleme yeteneği sağlar. Derinlemesine ilişkili verileri çekmek için kullanışlıdır ve ağ trafiği ve veri tabanı maliyetini optimize eder.

var products4 = context.Categories.Include(p => p.Products).ThenInclude(p => p.ProductDetail);

foreach (var category in product4)
{
    Console.WriteLine("Kategori Adı: " + category.CategoryName);
    foreach (var product in category.Products)
    {
         Console.WriteLine("Ürün Adı: " + product.ProductName + "Ürün Detay: " + product.ProductDetail.Color);
     }
}

Eager Loading aşağıdaki SQL sorgu biçimini veritabanında yürütecektir:

SELECT [p].[Id], [p].[CategoryRefId], [p].[CreateDate], [p].[DeleteDate], [p].[ProductName], [p].[ProductPrice], [p].[ProductStock], [p].[Status], [p].[UpdateDate], [c].[Id], [c].[CategoryName], [c].[CategoryUrl], [c].[CreateDate], [c].[DeleteDate], [c].[Status], [c].[UpdateDate]
FROM [Products] AS [p]
INNER JOIN [Categories] AS [c] ON [p].[CategoryRefId] = [c].[Id]

Lazy Loading Nedir?

Lazy loading, ilişkili verilere yalnızca ilk erişim anında yükleme yapmayı amaçlar. Yani, bir nesnenin ilişkili verilerine erişildiğinde, bu veriler o anda veri tabanından çekilir. İlk erişim anı dışında ilişkili verilere erişilmediği sürece yükleme işlemi gerçekleştirilmez.

Lazy loading’in temel amacı, performansı artırmaktır. İlişkili verilere erişim anında değil, gerçekten ihtiyaç duyulduğunda veritabanı sorgularını çalıştırarak gereksiz veri alımını önlemek için kullanılır. Bu, özellikle büyük veri kümesi veya karmaşık ilişkilerde performansı optimize etmek için önemlidir.

Lazy Loading, Entity Framework 3.0’a kadar varsayılan olarak etkindir. Ancak 3.0 sonrası gereksinimlerinize bağlı olarak etkinleştirilebilirsiniz.

Etkinleştirme:

  1. Navigasyon property’leriniz public, virtual olarak tanımlayın.
  2. NuGet kullanarak Microsoft.EntityFrameworkCore.Proxies paketini yükleyin.
  3. DbContext Sınıfı içersinde OnConfiguring metodu kullanılarak optionsBuilder.UseLazyLoadingProxies(); komutu ile Lazy Loading kullanımını aktif edin.
public class AppDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
         optionsBuilder.UseLazyLoadingProxies();
    }
}

Örnek Kullanım:

var products = context.Products.ToList();
foreach (var item in products)
{
    Console.WriteLine(item.ProductName + " - " + item.Category.CategoryName);
}

Lazy Loading aşağıdaki SQL sorgu biçimini veritabanında yürütecektir:

SELECT [p].[Id], [p].[CategoryRefId], [p].[CreateDate], [p].[DeleteDate], [p].[ProductName], [p].[ProductPrice], [p].[ProductStock], [p].[Status], [p].[UpdateDate]
FROM [Products] AS [p]

Explicit Loading Nedir?

Eager Loading ve Lazy Loading gibi iki diğer yükleme yaklaşımının aksine, Explicit Loading verilerin yüklenme zamanını ve sürecini uygulamanın kontrolüne bırakır.

Explicit Loading nasıl çalışır:

  1. İlk olarak, ana veri nesnelerinizi alırsınız. Bu ana nesneler, ilişkili verileri yüklemek istediğiniz nesnelerdir.
  2. İlişkili verilere erişim gerektiğinde, bu verileri yüklemek için belirli bir metot veya işlemi kullanırsınız.

Entity Framework Core kullanıyorsanız, ilişkili verileri yüklemek için Entry() metodu ve Collection() veya Reference() metodlarını kullanabilirsiniz.

using (var context = new AppDbContext())
{
    var products = context.Products.FirstOrDefault(p => p.Id== 1);

    //Ürünün kategorisini Explicit loading ile yükleme
    context.Entry(products).Reference(p => p.Category).Load();
}

Yukarıdaki örnekte, Load() metodu kullanılarak ürünün kategorisi Explicit Loading ile yüklenir. Bu, ilişkili verileri gerektiğinde yüklemek istediğinizde kullanabileceğiniz bir metotdur.

Explicit Loading, performansı optimize etmek ve gereksiz veri yüklemesini önlemek için kullanışlıdır. İhtiyaca bağlı olarak ilişkili verileri yüklemek için kullanılır ve veri alım sürecini uygulamanın kontrolüne bırakır. Bu nedenle, belirli senaryolarda kullanılabilir.

Collection() ve Reference() metotları arasında önemli bir fark vardır ve hangi metodun kullanılacağı, ilişkili verinin nasıl yüklendiğine bağlıdır:

1) Collection() Metodu:

  • Bu yöntem, ilişkili bir nesnenin koleksiyonunu (örneğin, bir kategorinin birçok ürünü olabilir) yüklemek için kullanılır.
  • Collection() metodu, ilişkilendirilmiş koleksiyonun öğelerini yükler.
//Kategorinin ürünlerini yükleme (Collection ile)
context.Entry(category).Collection(s => s.Products).Load(); 

2) Reference() Metodu:

  • Bu yöntem, bir ilişkili nesnenin (örneğin, bir ürünün kategorisi) yüklenmesi için kullanılır.
  • Reference() metodu, ilişkilendirilmiş nesneyi yükler.
//Bir ürünün kategorisini yükleme (Reference ile)
context.Entry(product).Reference(s => s.Category).Load();

Başka bir örnek ile açıklamak gerekirse:

Bir öğrencinin birden çok kursa kaydolabileceği ve bir kursun birden fazla öğrenciye sahip olabileceği bir senaryoyu düşünün.

  • Eğer bir öğrencinin tüm kurslarını yüklemek istiyorsanız, Collection() metodunu kullanabilirsiniz.
  • Eğer bir kursun öğrencisini yüklemek istiyorsanız, Reference() metodunu kullanabilirsiniz.