27 Nisan 2014 Pazar

Lazy Loading


   Merhaba arkadaşlar,

   Bu hafta birlikte Lazy Loading konusunu öğrenmeye çalışacağız. Lazy Loading kavramının ne olduğunu, Entity Framework konusundaki yerini örneklerle açıklamaya çalışacağım. İlk önce Lazy Loading kavramını açıklayalım. Lazy Loading genel anlamıyla bir nesnenin ihtiyaç duyulmaması halinde çağrılmaması esasına dayanmaktadır. Genel bir örnekle pekiştirirsek bir Web sitesi hayal edelim. Bu web sitesi barındırdığı bütün resimler yüklenmeden açılır. Biz sayfanın ilgili bölümlerini görüntülemeye başladığımızda yine o ilgili bölümde bulunan resimler yüklenmeye başlar. Yani resimleri görüntülemek istediğimiz zaman görüntülenmesi sağlanır. Bu da bize Web sayfasını ilk açmaya çalıştığımızda önemli bir performans katkısı sağlamış olur. Lazy Loading'in temel amacıda budur aslında.

   Lazy Loading'in Entity Framework ile kullanılma amacıda tamamen yukarıda bahsettiğim örnek ile aynıdır. Veritabanımızdaki tabloları nesneler üzerinden kontrol edebildiğimizi daha önceden öğrenmiştik. Oluşturduğumuz nesneleri ihtiyacımız olmadığı zamanlar kullanmazsak bir performans artışı sağlayacağımız şüphesiz. Peki Entity Framework yapısıyla Lazy Loading'i nasıl kullanabiliriz şimdi bunu görelim. Bunun için ilk önce bir veritabanımıza ihtiyacımız var. Örnekleri çeşitlendirmek amacıyla her yazımda farklı bir veritabanı kullanıyorum. Bu yazımda da Northwind veritabanını kullanacağım. Bunun için .bak uzantılı dosyayı buradan indirebilirsiniz. İlgili dosyayı indirdikten sonra .bak uzantılı dosyamızı MS Sql 2008 ile bağlamamız gerekiyor. Bunun için aşağıdaki adımları izlememiz gerekecek.

   Adım 1- İndirdiğimiz dosyayı C:\ klasörüne kopyalayalım.
 
   Adım 2- MS Sql 2008 de Database seçeneğine sağ tıklayıp "Restore Database..." kısmını seçelim.

Figür 1- Restore Database...

   Adım 3- Karşımıza çıkan ekrandan Device kısmını işaretleyip bilgisayarımızda bulunan Northwind veritabanını seçmek için "..." kısmına tıklıyoruz. Bu işlemleri yaptıktan sonra yeni bir pencere açılacaktır. Açılan pencereden Add butonuna basalım.

Figür 2- Veritabanı Ekleme

   Adım 4- Açılan yeni pencereden C:\ klasörüne attığımız Northwind.bak dosyamızı seçip "OK" tuşuna basıyoruz ve veritabanımızı MS Sql 2008'e eklemiş oluyoruz

Figür 3- C:\ Klasöründen Veritabanı Seçme

   Veritabanımızı ekledikten sonra şimdi gelelim örnek kodumuza. Öncelikle C# console application projesi oluşturalım. Oluşturduğumuz projeye her zaman ki gibi DataModel ekliyoruz ve kodlamaya başlıyoruz.

        class Categories
    {
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }
        public string Description { get; set; }
        public string Image { get; set; }   
   }

   Category classımızı oluşturduk ve propertyleri tanımladık. Şimdi Product classımızı oluşturalım.

          class Product
     {
        public int ProductID{ get; set; }
        public string ProductName { get; set; }
       public int CategoryID { get; set; }   
     }

   Kullanacağımız attributeler için propertyleri oluşturduk.

   
         NORTHWINDEntities db = new NORTHWINDEntities();

     List<Categories> categories = db.Categories.OrderBy(c => c.CategoryName).ToList();

       
        foreach (Categories cat in categories)
                {

                    Console.WriteLine(string.Format("{0} [{1}]",
                                               cat.CategoryName,
                                               cat.Products.Count));
                    WriteProducts(cat);

                }
       static void WriteProducts(Categories category)

        {
            foreach (Products prod in category.Products)

            {

                Console.WriteLine(string.Format("\t{0}",prod.ProductName));

            }

        }
  
   Bu kodun ekran çıktısı aşağıdaki gibi olacaktır.
Figür 4- Ekran Çıktısı

   Örneğimizde Category tablosundaki tüm Categoryleri CategoryName attributesine göre sıralayarak bir list oluşturuyoruz. Artık elimizde tüm Categoryler var. Şimdi Products tablosundan da verileri getirip getirmediğini deneyebiliriz. Bunun için "foreach" ile her bir Category altındaki Product elemanlarını almaya çalışalım. Bunun için de "WriteProducts" metodunu oluşturup parametre olarak Categories olarak gönderdik ve bu metodun dönüşünde Category'yi gönderip altındaki Product elemanlarını  Console  yazdırdık.

   Sql Profiler dan arka planda çalıştırılan Sql sorgularını incelediğimizde foreach döngüsüne gelene ve Product elemanları çekilmek istenene kadar sadece tüm kategorileri getiren bir sorgu çalıştığını göreceğiz.

   Ne zamanki ürünler isteniyor o zaman Products koleksiyonu dolduruluyor.

   SELECT
   [Extent1].[CategoryID] AS [CategoryID],
   [Extent1].[CategoryName] AS [CategoryName],
   [Extent1].[Description] AS [Description],
   [Extent1].[Picture] AS [Picture]
   FROM [dbo].[Categories] AS [Extent1]

   ORDER BY [Extent1].[CategoryName] ASC

   Şimdi de kodumuzda Lazy Loading'i kapatalım ve sonuçları gözlemleyelim.

   static void Main(string[] args)
        {

            using (NorthwindEntities db = new NorthwindEntities())

            {
                db.ContextOptions.LazyLoadingEnabled = false; 
                List<Categories> categories = db.Categories.OrderBy(c => c.CategoryName).ToList(); 

                foreach (Categories cat in categories)
                {

                    Console.WriteLine(string.Format("{0} [{1}]",
                                                    cat.CategoryName,
                                                    cat.Products.Count));
                    WriteProducts(cat);

                }

            }
        }

        static void WriteProducts(Categories category)

        {
            foreach (Products prod in category.Products)

            {

                Console.WriteLine(string.Format("\t{0}",prod.ProductName));

            }

        }ORDER BY [Extent1].[CategoryName] ASC

   Entity Modellimizin ContexOptions.LazyLoadingEnabled özelliğini false olarak belirledik. ContexOptions.LazyLoadingEnabled ne için kullanıldığını öğrenmek için Visual Studio'ya sorduğumuzda bize aşağıdaki gibi cevap verecektir.


   Şimdi yapmış olduğumuz örneği açıklayacak olursak; Category elemanlarının altındaki Product propertyleri çağırılacak olursa otomatik olarak yüklenecektir. Ancak Product ile ilgili herhangi bir işlem yapılmadığı zaman veritabanından Product ile ilgili bilgilere erişim yapılmayacaktır.

Figür 5- Ekran Çıktısı-2

   Yukarıda görüldüğü gibi Lazy Loading'i kapattığımız zaman Product bilgilerine erişim olmadı. Lazy Loading'i kapatıp Category başlığı altındaki Tüm Productları listelemek istersek aşağıdaki kodu yazabiliriz.
    
   List<Categories> categories = db.Categories.Include("Products").OrderBy(c => c.CategoryName).ToList();

   Yukarıdaki kod Categoryleri alırken ilgili Productlarıda yüklememizi sağlayacaktır. Sql tarafında da sadece bir sorgu dönecek ve işlemimizi tamamlamış olacağız.

   Fakat Lazy Loading ile bu işlemi yaptığımızda her seferinde bir sorgu dönecek toplam sekiz ayrı Category içinse sekiz farklı sorgu dönecektir. Burada tercih bize kalıyor, eğer tüm kategori ve ürünleri göstermeyeceksek, belirli kategorilerin ürünlerini göstereceksek Lazy Loading kullanmak daha mantıklı.

   Bu haftaki yazımında burada sonuna geliyorum. Haftaya ki yazımda görüşmek üzere...

   Referanslar:

   1- http://www.codeproject.com/Articles/652556/Can-you-explain-Lazy-Loading
   2- http://www.integralwebsolutions.co.za/Blog/EntryId/905/Entity-Framework-5-Lazy-Eager-Explicit-Loading.aspx

3 yorum:

  1. Merhaba Hürkan Bey, yazınızı çok faydalı buldum. Yeniden bilgilerinizi bizimle paylaşmanız dileklerimle.

    YanıtlaSil
  2. Yazı gerçekten açıklayıcı ve doyurucu olmuş. Emeğinize sağlık. Çalışmalarınızın devamını dilerim.

    YanıtlaSil
  3. Yazı oldukça açıklayıcı, kafa karıştırmadan anlatmışsınız...

    YanıtlaSil