NHibernate - Tải chậm

Trong chương này, chúng tôi sẽ đề cập đến tính năng tải lười biếng. Theo mặc định, đây là một khái niệm hoàn toàn khác và NHibernate không có tính năng tải chậm, ví dụ: nếu bạn tải một khách hàng, nó sẽ không tải tất cả các đơn đặt hàng.

  • Bộ sưu tập đơn hàng sẽ được tải theo yêu cầu.

  • Bất kỳ liên kết nào, cho dù là nhiều-một hay một tập hợp được tải chậm theo mặc định, nó yêu cầu Open ISession.

  • Nếu bạn đã đóng phiên của mình hoặc nếu bạn đã thực hiện giao dịch của mình, bạn có thể nhận được một ngoại lệ tải chậm mà nó không thể kéo các đối tượng bổ sung đó vào.

  • Bạn phải cẩn thận về việc tải chậm và lượng dữ liệu bạn thực sự cần.

  • Bạn có thể tắt tính năng tải chậm cho toàn bộ liên kết hoặc bạn có thể đặt lười biếng bằng false hoặc bạn cũng có thể chỉ định chiến lược tìm nạp.

Đây là Program.cs triển khai tệp.

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; 
      } 
   } 
}

Để hiểu điều này, hãy chạy ứng dụng và xem qua NHibernate Profiler.

Như bạn có thể thấy rằng chúng tôi có Chọn Từ Khách hàng, được cung cấp một ID khách hàng cụ thể và sau đó chúng tôi cũng có một bảng Chọn Từ Đơn đặt hàng khác, khi nó thực sự truy cập vào bộ sưu tập của khách hàng đó.

Vì vậy, chúng tôi có 2 roundtrips đến cơ sở dữ liệu. Đôi khi, chúng tôi muốn tối ưu hóa điều này. Để làm điều này, chúng ta hãy đi đếncustomer.hbm.xml và thêm một chiến lược tìm nạp và yêu cầu nó thực hiện tìm nạp tham gia.

<?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>

Như bạn có thể thấy rằng chúng tôi không thay đổi bất kỳ mã nào trong ứng dụng của mình, chúng tôi vừa thêm một chiến lược tìm nạp trong customer.hbm.xml. Hãy chạy lại ứng dụng này, nó vẫn hoạt động giống hệt như cũ. Hãy nhìn vào NHibernate Profiler.

  • Trước đây, chương trình có hai chuyến đi vòng đến cơ sở dữ liệu, bây giờ, nó chỉ có một và đó là bởi vì nó đang thực hiện một phép nối bên trái ở đây.

  • Chúng ta có thể thấy rằng nó đang thực hiện kết hợp bên ngoài bên trái giữa bảng khách hàng và bảng đơn đặt hàng dựa trên ID khách hàng và do đó, nó có thể tải tất cả thông tin đó cùng một lúc.

  • Chúng tôi đã lưu 1 vòng vào cơ sở dữ liệu.

  • Mặt trái của nó là thông tin khách hàng sẽ được sao chép trên cả hai dòng và đó là cách hoạt động của phép nối bên ngoài bên trái SQL.

  • Vì vậy, với chiến lược tìm nạp, chúng tôi đang lấy lại nhiều dữ liệu hơn một chút và chúng tôi đang tiết kiệm một vòng.

Bạn cũng có thể thực hiện việc này ở cấp độ truy vấn, vì vậy hãy chuyển đến Program.cs và xem ví dụ tải lại đơn giản hơ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(); 
}

Ở đây, chúng tôi đang thực hiện tải của khách hàng. Bây giờ hãy thay đổi nó thành một truy vấn và chúng tôi sẽ sử dụng một truy vấn liên kết như được hiển thị trong đoạn mã sau.

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();
}

Cũng hãy xóa chiến lược tìm nạp khỏi customer.hbm.xml tập tin.

<?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>

Hãy chạy lại ứng dụng này và bạn sẽ thấy kết quả sau.

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...

Bây giờ chúng ta hãy nhìn vào NHibernate Profiler, bạn có thể thấy rằng chúng tôi đã có lần tìm nạp tham gia háo hức này diễn ra một lần nữa, nhưng lần này, nó dựa trên truy vấn.