代码改变世界

NHiberate学习笔记(3)—懒加载

2009-10-06 17:20  小郝(Kaibo Hao)  阅读(558)  评论(0编辑  收藏  举报

继续学习NHibernte ,这一篇学习懒加载:

学习了如何在NUnit测试中使用 目标异常 来进行测试,代码如下所述:

延迟加载中LazyInitializationException异常

如果我想在Session清理关闭之后访问Order对象中的某些项会得到一个异常,由于session关闭,NHibernate不能为我们延迟加载Order项,我们编写一个测试方法验证一下:
[Test]
[ExpectedException(typeof(LazyInitializationException))]
public void LazyLoadOrderAggregateUsingSessionOnFailTest()
{
Order order = _relation.LazyLoadOrderAggregateUsingSession(2);
string name = order.Customer.Name.Fullname;
}

上面的测试抛出“Could not initialize proxy - no Session”预计的LazyInitializationException异常,表明测试成功,证明不能加载Order对象的Customer对象。

对于N+1选择问题,我跟踪到SQL如下:

NHibernate: SELECT order0_.OrderId as OrderId1_0_, order0_.OrderDate as OrderDate1_0_, order0_.Customer as Customer1_0_ FROM [Order] order0_ WHERE order0_.OrderId=@p0;@p0 = 1
NHibernate: SELECT products0_.[Order] as column1_1_, products0_.Product as Product1_, product1_.ProductId as ProductId3_0_, product1_.Name as Name3_0_, product1_.Cost as Cost3_0_ FROM OrderProduct products0_ left outer join Product product1_ on products0_.Product=product1_.ProductId WHERE products0_.[Order]=@p0;@p0 = 1

对于如下代码中的Product遍历,如李永京所说,这里NHibernate进行了优化。也同时体会到了他如下这段话的含义:“NHibernate自动生成最优化的查询语句,一口气加载了两个Product对象。但是试想一下有一个集合对象有100项,而你仅仅需要访问其中的一两项。这样加载所有项显然是资源的浪费。”

Code

下面继续看看【立即加载】是如何做到的

方式1:使用实体映射文件中对属性的 lazy属性进行设置,将其设置为"false",则将不进行默认的懒加载,而是在遇到像Customer的Orders属性就立即将其加载。

方式2:使用NHibernateUtil实用类的Initialize静态方法将指定属性初始化,当然初始化要在一次会话内完成,也就是要在同一个session的生命周期内,如下:

using (ISession _session = new SessionManager().GetSession())

{

Customer customer= _session.Get<Customer>(customerId);
NHibernateUtil.Initialize(customer.Orders);
return customer;
}

方式3:使用HQL抓取策略


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

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

几点注意:
fetch不与setMaxResults() 或setFirstResult()共用,因为这些操作是基于结果集的,而在预先抓取集合时可能包含重复的数据,也就是说无法预先知道精确的行数。
fetch还不能与独立的with条件一起使用。通过在一次查询中fetch多个集合,可以制造出笛卡尔积,因此请多加注意。对多对多映射来说,同时join fetch多个集合角色可能在某些情况下给出并非预期的结果,也请小心。
使用full join fetch 与 right join fetch是没有意义的。 如果你使用属性级别的延迟获取,在第一个查询中可以使用 fetch all properties 来强制NHibernate立即取得那些原本需要延迟加载的属性。

下面写个简单例子说明:

public DomainModel.Entities.Order EagerLoadOrderAggregateWithHQL(int orderId)
{
    
using (ISession _session = new SessionManager().GetSession())
    {
        
return _session.CreateQuery("from Order o"+
            
" left outer join fetch o.Products" +
            
" inner join fetch o.Customer where o.OrderId=:orderId")
            .SetInt32(
"orderId", orderId)
            .UniqueResult
<DomainModel.Entities.Order>();
    }
}
本篇对懒加载进行了一个总结,希望对你我都有帮助,To be continued...

 

本文参考自:李永京
NHibernate之旅(12):初探延迟加载机制
NHibernate之旅(13):初探立即加载机制