一个例子
1、一对多关系
通过立即加载的方式,加载客户信息及客户的订单信息,
[NHibernate]立即加载
。复制代码
1 ///
2 /// 采用立即加载的方式加载客户信息
3 ///
4 ///
5 ///
6 public Customer GetCustomerByImmediatelyLoad(Guid customerID)
7 {
8 //获得ISession实例
9 //通过using的方式将session释放,为了保证是立即加载的数据,而不是延迟加载的
10 //还记得上篇文章中提到的在延迟加载中,在关闭session情况下,再读取数据的时候就会有一个异常信息
11 //忘记的可以再回到上一篇文章进行查看
12 using (ISession session = NHibernateHelper.GetSession())
13 {
14 return session.Get
15 }
16 }
复制代码
1.1、修改Customer.hbm.xml文件
因为nhibernate默认是使用Lazy的方式加载数据的,也就是默认Lazy=“true”的,需要显示的指定Lazy=“false”。
1
2
3
4
5
6
编写一个测试验证,调用数据访问层中的使用using强制资源清理Session加载Customer对象的方法加载一个Customer对象,NHibernate这时立即加载Customer相关联的Order对象。
利用NHibernate提供实用类(NHibernateUtil)测试被关联的Customer对象集合是否已初始化(也就是已加载)。
上篇文章中也说明了,如果在关闭session的情况下,如果你展开customer的orders属性,就会出现异常
这也说明了Orders是跟customer一样立即加载的。
查看生成的sql语句
1 exec sp_executesql N'SELECT customer0_.CustomerID as CustomerID0_0_, customer0_.Version as Version0_0_, customer0_.CustomerName as Customer3_0_0_, customer0_.CustomerAddress as Customer4_0_0_ FROM TB_Customer customer0_ WHERE customer0_.CustomerID=@p0',N'@p0 uniqueidentifier',@p0='B0720295-9541-40B3-9994-610066224DB8'
2
3 exec sp_executesql N'SELECT orders0_.CustomerID as CustomerID1_, orders0_.OrderID as OrderID1_, orders0_.OrderID as OrderID1_0_, orders0_.OrderDate as OrderDate1_0_, orders0_.CustomerID as CustomerID1_0_ FROM TB_Order orders0_ WHERE orders0_.CustomerID=@p0',N'@p0 uniqueidentifier',@p0='B0720295-9541-40B3-9994-610066224DB8'
第一条sql为查询Customer的,第二条sql是查询与该customer相关联的order的。
1.2、使用NHibernateUtil实用类
NHibernate提供实用类(NHibernateUtil)可以用来检测被关联的对象集合是否已初始化,还可以强制初始化未初始化的相关联的对象。有了这个功能,我们就可以修改数据访问层中的方法,把上面使用Using强制清理关闭Session的方法中加上NHibernateUtil类提供Initialize方法来初始化Customer相关联的Order对象集合。
修改Customer.hbm.xml文件,将set节点的lazy属性设置为默认值true,或者删除该属性。
复制代码
1 ///
2 /// NHibernateUtil方式,立即加载客户信息及关联的数据
3 ///
4 ///
5 ///
6 public Customer GetCustomerByImmediatelyLoadNHibernateUtil(Guid customerID)
7 {
8 //获得ISession实例
9 //通过using的方式将session释放,为了保证是立即加载的数据,而不是延迟加载的
10 //还记得上篇文章中提到的在延迟加载中,在关闭session情况下,再读取数据的时候就会有一个异常信息
11 //忘记的可以再回到上一篇文章进行查看
12 using (ISession session = NHibernateHelper.GetSession())
13 {
14 Customer customer = session.Get
15 //
16 // 摘要:
17 // Force initialization of a proxy or persistent collection.
18 //
19 NHibernate.NHibernateUtil.Initialize(customer.Orders);
20 return customer;
21 }
22 }
复制代码
通过该种方式,跟上面的测试结果相同,就不再贴图了,
电脑资料
《[NHibernate]立即加载》(http://meiwen.anslib.com)。2、多对多关系
2.1、使用Lazy=“false”属性
例子同上面的类似,就不再赘述。
2.2、使用NHibernateUtil实用类
这里采用Order和Product多对多实例进行分析。
如果想在加载Order的情况下,加载该Order下的所有Product,可以使用NHibernateUtil类初始化关联对象(把他们从数据库取出来)。
复制代码
1 ///
2 /// NHibernateUtil方式,立即加载订单与商品
3 ///
4 ///
5 ///
6 public Order GetOrderProductByImmediatelyLoadNHibernateUtil(Guid orderId)
7 {
8 using (var session = NHibernateHelper.GetSession())
9 {
10 var rder = session.Get
11 //强制初始化customer
12 NHibernate.NHibernateUtil.Initialize(order.Customer);
13 //强制初始化Product
14 NHibernate.NHibernateUtil.Initialize(order.Products);
15 return order;
16 }
17 }
1 exec sp_executesql N'SELECT order0_.OrderID as OrderID1_0_, order0_.OrderDate as OrderDate1_0_, order0_.CustomerID as CustomerID1_0_ FROM TB_Order order0_ WHERE order0_.OrderID=@p0',N'@p0 uniqueidentifier',@p0='78A53F67-A293-48A1-BBE2-86FED77342FA'
2
3 exec sp_executesql N'SELECT customer0_.CustomerID as CustomerID0_0_, customer0_.Version as Version0_0_, customer0_.CustomerName as Customer3_0_0_, customer0_.CustomerAddress as Customer4_0_0_ FROM TB_Customer customer0_ WHERE customer0_.CustomerID=@p0',N'@p0 uniqueidentifier',@p0='B0720295-9541-40B3-9994-610066224DB8'
4
5 exec sp_executesql N'SELECT products0_.OrderID as OrderID1_, products0_.ProductID as ProductID1_, product1_.ProductID as ProductID3_0_, product1_.Name as Name3_0_, product1_.Price as Price3_0_ FROM TB_OrderProduct products0_ left outer join TB_Product product1_ on products0_.ProductID=product1_.ProductID WHERE products0_.OrderID=@p0',N'@p0 uniqueidentifier',@p0='78A53F67-A293-48A1-BBE2-86FED77342FA'
复制代码
这里生成了三条sql语句,查询和Order关联的customer和Product。
2.3使用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立即取得那些原本需要延迟加载的属性。
参考:http://www.cnblogs.com/lyj/archive/2008/10/29/1322373.html
测试代码
复制代码
1 ///
2 /// HQL方式,立即加载订单与商品
3 ///
4 ///
5 ///
6 public Order GetOrderProductByImmediatelyLoadHQL(Guid orderId)
7 {
8 using (var session = NHibernateHelper.GetSession())
9 {
10 return session.CreateQuery("from Order o" +
11 " left outer join fetch o.Products" +
12 " inner join fetch o.Customer where o.OrderID=:orderId")
13 .SetGuid("orderId", orderId)
14 .UniqueResult
15 }
16 }
上篇文章中,描述了一个N+1的问题,这里再次说明一下,N+1的问题,我是这样理解的你本来想要一条,可是采用默认延迟加载的情况下,就会把所有的信息都加载,有点浪费,而这时采用立即加载的方式,你可以很好的控制,想加载几条加载几条。
这篇文章介绍了nhibernate立即加载的方式,什么时候使用立即加载,什么时候使用延迟加载,视项目中的情况而定。比如这种情况,如果在多对多的关系中,你想加载几条数据,也就是N+1的问题,还是采用立即加载的方式更好,此时,不会加载多余的数据,可以更好的达到控制的目的。