- Lazy Loading
“Lazy Loading”, Türkçeye tembel yükleme olarak çevrilse de, kavramsal olarak bu çeviri bazen kafa karıştırabilir. Aslında mantık şudur:
İlişkili veriler, ancak onlara gerçekten ihtiyaç duyulduğunda sorgulanır.
Bu yaklaşım, başlangıçta performans kazandırabilir, ancak kontrolsüz kullanıldığında ciddi N+1 problemi doğurur. Adım adım gidelim.
Lazy Loading kullanabilmemiz için UseLazyLoadingProxies() çağrısı yapılmalıdır.
OnConfiguring metodunda :
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString);
Ya da AddDbContext metodunda
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
Diğer bir gereklilik ise virtual anahtar kelimesi:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public virtual Blog Blog { get; set; }
}
Entity içinde tanımladığımız ilişkili tabloları virtual vermemiz gerekir. Bu sayede EntityFramework bu sınıftan türetme yaparak kullanır. Aksi takdirde Lazy Loading kullanılamaz.
Bu durumda biz şu şekilde bir sorgu kullandığımızda
var blog = context.Blog.First(u => u.Id == 1);
Elimizdeki sonuca baktığımızda Posts kayıtlarını da görebiliriz. Fakat aşağıdaki gibi Blog tablosunun ilişkili Posts tablosuna ulaşmak istediğimizde
var posts = blog.Posts;
Ef arka planda bir sorgu daha çalıştırır.
SELECT * FROM Posts WHERE BlogId = 1
Her virtual property bağımlılığında erişilmek istendiğinde bir sorgu daha çalışır. Bu da N+1 sorununu ortaya çıkarır. Her bir ilişkili tablo için bir foreach içinde döner ve sorgu oluşturur.
Bu arada verinin ihtiyaç halinde gelmesi kafa karıştırmasın. Yani ihtiyaç olan property e erişim sırasında gelir anlamına geliyor. blog.Posts örneğindeki gibi.
- Eager Loading
Eager Loading ilişkili verileri tek bir sorguda getirmektir. Her bir ilişkili tablo için ayrı sorgu çalıştırmak yerine include ve thenInclude kullanarak tek seferde ihtiyaç duyulan ilişkili tablo verilerini getirmektir. Eğer tek seferde tüm bu bilgileri getirmek gerekiyorsa Lazy Loading e göre daha performanslıdır. Burada optimizasyon tamamen senin elindedir. Kaç tane include kullanacağın performansı direk etkileyecektir. Kendi prensiplerine göre sorguda belirli bir include sayısını aşmamak ama aşmak gerekiyorsa da sorguyu parçalamak oldukça verimli bir yöntem olacaktır. Aksi takdirde bu sefer bir sürü Left Join problemi yaşanır.
var blogs = context.Blogs.Include(x => x.Posts).ToList();
Ama yine de başka bir alternatif daha var ve kontrol tamamen sende.
- Explicit Loading
Hem Lazy Loading gibi çalışır hem de Eager Loading gibi yönetilebilir.
dbContext.Entry(blogs).Collection(b => b.Posts).Load();
Bir yanıt yazın