NHibernate - Tembel Yükleme

Bu bölümde, geç yükleme özelliğini ele alacağız. Varsayılan olarak tamamen farklı bir kavramdır ve NHibernate'in tembel yüklemesi yoktur, örneğin bir müşteriyi yüklerseniz, tüm siparişleri yüklemeyecektir.

  • Sipariş toplama talep üzerine yüklenecektir.

  • İster çoktan bire isterse bir koleksiyon olsun, varsayılan olarak tembel olarak yüklenen herhangi bir ilişki, bir Open ISession.

  • Oturumunuzu kapattıysanız veya işleminizi gerçekleştirdiyseniz, bu ek nesneleri çekemeyeceği bir tembel yükleme istisnası alabilirsiniz.

  • Tembel yükleme ve gerçekte ne kadar veriye ihtiyacınız olduğu konusunda dikkatli olmalısınız.

  • Tüm bir ilişkilendirme için geç yüklemeyi kapatabilir veya tembel eşittir yanlış koyabilir ya da bir getirme stratejisi de belirtebilirsiniz.

İşte Program.cs dosya uygulaması.

using System; 
using System.Data; 
using System.Linq; 
using System.Reflection; 

using HibernatingRhinos.Profiler.Appender.NHibernate; 
using NHibernate.Cfg; 
using NHibernate.Dialect; 
using NHibernate.Driver; 
using NHibernate.Linq;

namespace NHibernateDemo { 

   internal class Program { 
	
      private static void Main() { 
		
         var cfg = ConfigureNHibernate(); 
         var sessionFactory = cfg.BuildSessionFactory();
         
         Guid id; 
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) {
            var newCustomer = CreateCustomer(); 
            Console.WriteLine("New Customer:"); 
            Console.WriteLine(newCustomer); 
            session.Save(newCustomer); 
            id = newCustomer.Id; 
            tx.Commit(); 
         }
         
         using(var session = sessionFactory.OpenSession()) 
			
         using(var tx = session.BeginTransaction()) { 
            var reloaded = session.Load<Customer>(id); 
            Console.WriteLine("Reloaded:"); 
            Console.WriteLine(reloaded); 
            Console.WriteLine("The orders were ordered by: "); 
            
            foreach (var order in reloaded.Orders) { 
               Console.WriteLine(order.Customer); 
            } 
				
            tx.Commit(); 
         }
			
         Console.WriteLine("Press <ENTER> to exit..."); 
         Console.ReadLine(); 
      }
		
      private static Customer CreateCustomer() { 
         
         var customer = new Customer { 
            FirstName = "John", 
            LastName = "Doe", 
            Points =100, 
            HasGoldStatus = true, 
            MemberSince = new DateTime(2012, 1, 1),
            CreditRating = CustomerCreditRating.Good,
            AverageRating = 42.42424242, 
            Address = CreateLocation() 
         }; 
			
         var order1 = new Order { Ordered = DateTime.Now }; 
         customer.AddOrder(order1); 
         
         var order2 = new Order { 
            Ordered = DateTime.Now.AddDays(-1), 
            Shipped = DateTime.Now, 
            ShipTo = CreateLocation() 
         }; 
			
         customer.AddOrder(order2); return customer; 
      }
		
      private static Location CreateLocation() { 
         return new Location { 
            Street = "123 Somewhere Avenue", 
            City = "Nowhere", 
            Province = "Alberta", 
            Country = "Canada" 
         }; 
      }
		
      private static Configuration ConfigureNHibernate() { 
		
         NHibernateProfiler.Initialize(); 
         var cfg = new Configuration(); 
         
         cfg.DataBaseIntegration(x => { 
            x.ConnectionStringName = "default"; 
            x.Driver<SqlClientDriver>(); 
            x.Dialect<MsSql2008Dialect<(); 
            x.IsolationLevel = IsolationLevel.RepeatableRead; 
            x.Timeout = 10;
            x.BatchSize = 10;
         }); 
         
         cfg.SessionFactory().GenerateStatistics();
         cfg.AddAssembly(Assembly.GetExecutingAssembly()); 
         return cfg; 
      } 
   } 
}

Bunu anlamak için uygulamayı çalıştıralım ve NHibernate Profiler'a bir göz atalım.

Gördüğünüz gibi, belirli bir müşteri kimliği verilen Müşteriden Seç'e sahibiz ve ayrıca o müşterinin koleksiyonuna gerçekten eriştiğinde başka bir Siparişlerden Seçme tablosuna sahibiz.

Yani veritabanına 2 gidiş dönüş var. Şimdi, bazen bunu optimize etmek isteriz. Bunu yapmak için gidelimcustomer.hbm.xml dosyasını açın ve bir getirme stratejisi ekleyin ve ondan bir birleştirme getirmesi yapmasını isteyin.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 
   
   <class name = "Customer"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/> 
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
      
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
      
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan" 
         fetch = "join"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Gördüğünüz gibi uygulamamızda herhangi bir kodu değiştirmediğimizi, az önce şuraya bir getirme stratejisi ekledik. customer.hbm.xml. Bu uygulamayı tekrar çalıştıralım, yine aynı şekilde davranıyor. NHibernate Profiler'a bakalım.

  • Daha önce, programın veritabanına iki gidiş-dönüş yolculuğu vardı, şimdi sadece bir tane var ve bunun nedeni burada bir sol dış birleştirme yapıyor.

  • Müşteri kimliğine göre müşteri tablosu ile sipariş tablosu arasında sol dış birleştirme yaptığını ve bu nedenle tüm bu bilgileri aynı anda yükleyebildiğini görebiliriz.

  • Veritabanına 1 gidiş dönüş kaydettik.

  • Olumsuz tarafı, müşteri bilgilerinin her iki satırda da kopyalanacağı ve bu, bir SQL sol dış birleştirmenin çalışma şeklidir.

  • Bu nedenle, getirme stratejisiyle, biraz daha fazla veri çekiyoruz ve bir gidiş dönüş tasarrufu sağlıyoruz.

Bunu sorgu düzeyinde de yapabilirsiniz, öyleyse hadi Program.cs dosyasını açın ve daha basit yeniden yüklenen örneğe bakın.

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) { 
   //var query = from customer in session.Query<Customer>() 
   // select customer; 
   //var reloaded = query.Fetch(x => x.Orders).ToList();
	
   var reloaded = session.Load<Customer>(id); 
   Console.WriteLine("Reloaded:"); 
   Console.WriteLine(reloaded); 
   Console.WriteLine("The orders were ordered by: "); 
   
   foreach (var order in reloaded.Orders) { 
      Console.WriteLine(order.Customer); 
   } 
	
   tx.Commit(); 
}

Burada müşteri tarafından bir yükleme yapıyoruz. Şimdi bunu bir sorgu olarak değiştirelim ve aşağıdaki kodda gösterildiği gibi bir bağlantı sorgusu kullanacağız.

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) {
   var query = from customer in session.Query<Customer>() 
   where customer.Id == id select customer; 
   var reloaded = query.Fetch(x => x.Orders).ToList().First();
	
   Console.WriteLine("Reloaded:"); 
   Console.WriteLine(reloaded); 
	
   tx.Commit();
}

Getirme stratejisini de customer.hbm.xml dosya.

<?xml version = "1.0" encoding = "utf-8" ?> 
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
   namespace = "NHibernateDemo"> 

   <class name = "Customer"> 
	
      <id name = "Id"> 
         <generator class = "guid.comb"/> 
      </id> 
   
      <property name = "FirstName"/> 
      <property name = "LastName"/>
      <property name = "AverageRating"/> 
      <property name = "Points"/> 
      <property name = "HasGoldStatus"/> 
      <property name = "MemberSince" type = "UtcDateTime"/> 
      <property name = "CreditRating" type = "CustomerCreditRatingType"/>
   
      <component name = "Address"> 
         <property name = "Street"/> 
         <property name = "City"/> 
         <property name = "Province"/> 
         <property name = "Country"/> 
      </component>
   
      <set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"> 
         <key column = "CustomerId"/> 
         <one-to-many class = "Order"/> 
      </set> 
   
   </class> 
</hibernate-mapping>

Bu uygulamayı tekrar çalıştıralım ve aşağıdaki çıktıyı göreceksiniz.

New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
   CreditRating: Good
   AverageRating: 42.42424242

   Orders:
      Order Id: 00000000-0000-0000-0000-000000000000
      Order Id: 00000000-0000-0000-0000-000000000000

Reloaded:
John Doe (6ebacd17-f9ba-4ad8-9817-a5bb01112a5a)
   Points: 100
   HasGoldStatus: True
   MemberSince: 1/1/2012 12:00:00 AM (Utc)
   CreditRating: Good
   AverageRating: 42.4242

   Orders:
      Order Id: 16a6596b-d56e-41c7-9681-a5bb01112a60
      Order Id: d41d615b-0f21-4032-81db-a5bb01112a61
		
Press <ENTER> to exit...

Şimdi NHibernate Profiler'a bakalım, bu istekli katılma getirme işleminin bir kez daha gerçekleştiğini görebilirsiniz, ancak bu sefer sorguya dayanıyor.