Entity Framework ve ORM araçlarının Lazy Loading mantığı

21 Tem

Entity Framework veya NHibernate veya benzeri ORM araçlarının Lazy Loading özelliği ilişkili tablolardan veri çekerken geliştiricilere büyük kolaylık sağlar. Her kolaylığın bir maliyeti vardır ve ilişkili tablolardan veri çekme işlemi sırasında oluşan maliyetin faturası veri tabanlarına yansıtılmaktadır. Bu yazıda veritabanlarından ilişkili veri çekimi sırasında ORM araçlarının nasıl sorgular oluşturduğunu incelemeye çalışacağız.

İlişkili Tablolar
İlişkili Tablolar

Yukarıdaki şema Blog tablosuna bağlı birçok Article olabileceği gibi, Article tablosuna bağlı birçok Tag olabileceğini göstermektedir. (Veritabanı MsSQL Express’dir.)

Bu yapıya göre bir Blog altındaki Article listesini görmek istediğimizde ve her Article için kaç Tag olduğunu listelemek istediğimizde nasıl bir yol izlemeliyiz? Bunu  Entity Framework kullanarak  incelemeye çalışalım.


public class Blog
{
     public int Id { get; set; }
     public string Name { get; set; }
     public virtual ICollection Articles { get; set; }

     public override string ToString()
     {
         return string.Format("{0} ({1})",Name, Articles.Count);
     }
}

public class Article
{
     public int Id { get; set; }
     public int BlogId { get; set; }
     public string Title { get; set; }
     public string Content { get; set; }

     public virtual Blog Blog { get; set; }
     public virtual ICollection Tags { get; set; }

     public override string ToString()
     {
        return string.Format("{0} ({1} Tags)", Title, Tags.Count);
     }
}

public class Tag
{
     public int Id { get; set; }
     public int ArticleId { get; set; }
     public string Name { get; set; }
     public virtual Article Article { get; set; }
}

public class BloggingContext:DbContext
{
     public DbSet Blogs { get; set; }
     public DbSet Articles { get; set; }
     public DbSet Tags { get; set; }
}

Bu kısımda Entity Framework için veritabanı tablolarını temsil eden tipler oluşturulmuştur. App.config veya Web.config dosyaları içerisinde connectionString ayarlamalarını yaptıktan sonra BloggingContext nesnesi ile veritabanında işlemler gerçekleştirilebilmektedir. Bu işlem aşağıdaki gibi yapılmaktadır.

 static void Main(string[] args)
 {
    using (var context = new BloggingContext())
    {
       foreach (var blog in context.Blogs.ToList())
       {
          Console.WriteLine(blog);
          foreach (var article in blog.Articles)
          {
              Console.Write("\t");
              Console.Write(article);
              Console.Write("\n");
          }
       }
    }
 }
Run
Run

Öncelikle Blog’lar listeleniyor ve parantez içinde her Blog türüne bağlı Article sayısı yazdırılıyor. Article satırına da her Article türüne bağlı Tag sayısı yazdırılıyor.

Bu işlem gerçekleşene kadar acaba veritabanında neler olup bitiyor? Bunu anlamak için Express Profiler aracından faydalanabilirsiniz. Express Profiler aracı veritabanına giden tüm sorguları yakalayabilen bir özelliğe sahiptir.

Kodumuzu çalıştırdığımızda Express Profiler penceresinde bir dizi işlemler raporlanacaktır.

Express Profiler
Express Profiler

Entity Framework öncelikle veritabanının var olup olmadığını sorgular. Daha sonra ilgili tabloların olup olmadığını sorgular. Daha sonra MigrationHistory tablolarını sorgular. Derken bizi ilgilendiren kısım olan Blog listesini çeken sorguyu oluşturulur.

Adsız

Bu sorgu sonrasında Blog listesindeki ilk Blog’a bağlı Article listesi seçilir.

Adsız

Article listesi geldikten sonra ilgili Article için Tag listesi çekilir.

Adsız

 

Bu işlem döngü şeklinde devam eder gider.

Şu anda listelediğim örnek tablolarda toplamda 10 veya 15 veri vardır. Bu işlem yüz binlerce kayıt barındıran tablolarda yapılmaya çalışıldığında epeyce maliyetli olabilir. Maliyeti düşürmek adına JOIN ile oluşturulabilecek ham SQL sorguları kullanmak daha ucuz bir yöntem olacaktır.

SELECT B.Name, COUNT(A.Id)
FROM Blogs as B
LEFT JOIN Articles as A
ON A.BlogId=B.Id
GROUP BY B.Name

ORM araçlarına savaş açmak yerine uygun ve yerinde çözümler üretmek hayat kurtarıcı olabilir.

Güncelleme: 25.07.2015, SQL JOIN sorgusu eklendi.