📜  NHibernate-延迟加载

📅  最后修改于: 2020-11-19 05:39:54             🧑  作者: Mango


在本章中,我们将介绍延迟加载功能。默认情况下,这是一个完全不同的概念,NHibernate不会延迟加载,例如,如果加载客户,则不会加载所有订单。

  • 订单集合将按需加载。

  • 默认情况下,任何关联(无论是多对一还是集合)都是延迟加载的,都需要一个Open ISession

  • 如果关闭了会话或提交了事务,则可能会出现延迟加载异常,该异常无法拉入那些其他对象。

  • 您必须注意延迟加载以及实际需要多少数据。

  • 您可以关闭整个关联的延迟加载,也可以将延迟等于false设置为假,也可以指定获取策略。

这是Program.cs文件的实现。

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(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  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(); 
            x.Dialect

为了理解这一点,让我们运行该应用程序,看看NHibernate Profiler。

客户集合

正如您所看到的,我们有从特定客户ID的“从客户选择”,然后,当它实际访问该客户的集合时,我们还有另一个“从订单选择”表。

因此,我们有2次往返数据库。现在,有时候,我们想对此进行优化。为此,我们转到customer.hbm.xml文件并添加获取策略,并要求其进行联接获取。

 
 
   
    
    
       
          
       
   
       
       
       
       
       
       
      
      
       
          
          
          
          
      
      
       
          
          
       
   
    

如您所见,我们没有更改应用程序中的任何代码,我们只是在customer.hbm.xml中添加了获取策略。让我们再次运行该应用程序,它的行为仍然完全相同。让我们看一下NHibernate Profiler。

客户资料

  • 以前,程序有两次到数据库的往返,现在只有一次,这是因为它在这里进行左外部联接。

  • 我们可以看到它正在根据客户ID在客户表和订单表之间进行左外部联接,因此,它可以立即加载所有这些信息。

  • 我们已经将1次往返保存到数据库中。

  • 不利的一面是,客户信息将在两行上重复,这就是SQL左外部联接工作的方式。

  • 因此,通过获取策略,我们将拉回更多数据,并节省了往返时间。

您也可以在查询级别执行此操作,因此让我们转到Program.cs文件并查看更简单的重新加载示例。

using(var session = sessionFactory.OpenSession()) 

using(var tx = session.BeginTransaction()) { 
   //var query = from customer in session.Query() 
   // select customer; 
   //var reloaded = query.Fetch(x => x.Orders).ToList();
    
   var reloaded = session.Load(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(); 
}

在这里,我们由客户来做负载。现在,将其更改为查询,我们将使用链接查询,如以下代码所示。

using(var session = sessionFactory.OpenSession()) 

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

我们还要从customer.hbm.xml文件中删除获取策略。

 
 

    
    
       
          
       
   
       
      
       
       
       
       
      
   
       
          
          
          
          
      
   
       
          
          
       
   
    

让我们再次运行该应用程序,您将看到以下输出。

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

现在让我们看一下NHibernate Profiler,您可以看到我们再次渴望进行联接获取,但是这次,它是基于查询的。

加入获取