NHIbernate学习之旅【七】——立即/延迟加载

  什么是延迟加载:所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出sql语句进行查询,数据是分N次读取。

  什么是立即加载:所谓立即加载既是所有的相关数据一次被读取出来,而不是分N次。

  简单的说就是对于用户表和订单表是一对多的关系,但是NHibernate会自动关联有联系的表,如果你只是查询用户的话,NHibernate却自动帮你关联了订单表是没必要的,所以延迟加载就是如果只查用户信息就生成用户查询的SQL,如果用到该用户对应的订单的话,NHibernate就会自动帮你关联订单表。

  我们在业务层添加下面两种查询:

  

代码
        #region 延迟加载
        
public Customer LazyLoad(int customerId)
        {
            
return _session.Get<Customer>(customerId);
        }

        
public Customer LazyLoadUsingSession(int customerId)
        {
            
using (ISession _session = new SessionManager().GetSession())
            {
                
return _session.Get<Customer>(customerId);
            }
        }
        
#endregion
    

 

  然后在前台调用,可以看到两个查询都只只生成了一条SQL语句:

  

代码
SELECT customer0_.CustomerId as CustomerId16_0_,
       customer0_.Version    
as Version16_0_,
       customer0_.FirstName  
as FirstName16_0_,
       customer0_.LastName   
as LastName16_0_
FROM   Customer customer0_
WHERE  customer0_.CustomerId = 3 /* @p0 */

 

  也就是说没有对订单表进行关联。

  不过延迟加载是需要Session的支持的。看下面两张图

  可以看到前一张图没释放Session存在一条Orders数据,但是后一张释放了Session就会出现failed to lazily initialize a collection, no session or session was closed异常。

使用延迟加载,但没释放Session

 

使用延迟加载,但释放Session

 

(才发现图好花,将就着看把。)

 

以上就是延迟加载,很方便的一个机制,对于不需要的不加载,以减少性能的消耗。但是它也存在着问题,如果一张表有多个关联的表,但你只要查询其中的一个,而NHibernate却帮你全部查出来了不是很耗性能吗,于是就要用到立即加载。

 

  立即加载有3种实现方法。

  lazy属性、NHibernate提供的实用类、使用带fetchHQL查询

  

  1.配置lazy=”false”进行立即加载

  打开Customer.hbm.xml文件,在Set元素中添加lazy="false"

  2.使用NHibernateUtil实用类(我比较喜欢,最方便)

  NHibernateUtil类提供Initialize方法可以强制初始化未初始化的相关联的对象

  

代码
        #region 立即加载
        
public Customer EagerLoadUsingSessionAndNHibernateUtil(int customerId)
        {
            
using (ISession _session = new SessionManager().GetSession())
            {
                Customer customer 
= _session.Get<Customer>(customerId);
                NHibernateUtil.Initialize(customer.Orders);
                
return customer;
            }
        }

        
#endregion

 

   3.使用带fetchHQL查询

  

  a) 使用HQL查询方法也可以立即加载。HQL语句支持的连接类型为:inner join(内连接)、left outer join(左外连接)、right outer join(右外连接)、full join(全连接,不常用)。

  b) “抓取fetch”连接允许仅仅使用一个选择语句就将相关联的对象随着他们的父对象的初始化而被初始化,可以有效的代替了映射文件中的外联接与延迟属性声明。

 

  几点注意:
  c) fetch不与setMaxResults() 或setFirstResult()共用,因为这些操作是基于结果集的,而在预先抓取集合时可能包含重复的数据,也就是说无法预先知道精确的行数。

  d) fetch还不能与独立的with条件一起使用。通过在一次查询中fetch多个集合,可以制造出笛卡尔积,因此请多加注意。对多对多映射来说,同时join fetch多个集合角色可能在某些情况下给出并非预期的结果,也请小心。

  e)使用full join fetch 与 right join fetch是没有意义的。 如果你使用属性级别的延迟获取,在第一个查询中可以使用 fetch all properties 来强制NHibernate立即取得那些原本需要延迟加载的属性。

  删除order.hbm.xml中的lazy="false"属性设置,这样order的Products就不是立即加载了,并将LazyLoad()函数修改如下:

  

代码
//使用HQL的fetch进行立即加载
            
using (ISession iSession = new SessionManager().GetSession())
            {
                
return iSession.CreateQuery("from Order o left join fetch o.Products where o.OrderId=2 ")
                    .UniqueResult
<Order>();
            }

 

 

以上三种方法生成的SQL前两种是两条:

代码
SELECT customer0_.CustomerId as CustomerId16_0_,
       customer0_.Version    
as Version16_0_,
       customer0_.FirstName  
as FirstName16_0_,
       customer0_.LastName   
as LastName16_0_
FROM   Customer customer0_
WHERE  customer0_.CustomerId = 3 /* @p0 */

SELECT orders0_.Customer  as Customer1_,
       orders0_.OrderId   
as OrderId1_,
       orders0_.OrderId   
as OrderId14_0_,
       orders0_.OrderDate 
as OrderDate14_0_,
       orders0_.Customer  
as Customer14_0_
FROM   [Order] orders0_
WHERE  orders0_.Customer = 3 /* @p0 */

  后一种是一条:

代码
select customer0_.CustomerId as CustomerId23_0_,
       orders1_.OrderId      
as OrderId21_1_,
       customer0_.Version    
as Version23_0_,
       customer0_.FirstName  
as FirstName23_0_,
       customer0_.LastName   
as LastName23_0_,
       orders1_.OrderDate    
as OrderDate21_1_,
       orders1_.Customer     
as Customer21_1_,
       orders1_.Customer     
as Customer0__,
       orders1_.OrderId      
as OrderId0__
from   Customer customer0_
       
left outer join [Order] orders1_
         
on customer0_.CustomerId = orders1_.Customer
where  customer0_.CustomerId = 3 /* @p0 */

 

 

posted on 2010-05-15 15:21  neekey  阅读(1394)  评论(2)    收藏  举报

导航