NHIbernate学习之旅【七】——立即/延迟加载
什么是立即加载:所谓立即加载既是所有的相关数据一次被读取出来,而不是分N次。
简单的说就是对于用户表和订单表是一对多的关系,但是NHibernate会自动关联有联系的表,如果你只是查询用户的话,NHibernate却自动帮你关联了订单表是没必要的,所以延迟加载就是如果只查用户信息就生成用户查询的SQL,如果用到该用户对应的订单的话,NHibernate就会自动帮你关联订单表。
我们在业务层添加下面两种查询:
代码
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语句:
代码
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提供的实用类、使用带fetch的HQL查询
1.配置lazy=”false”进行立即加载
打开Customer.hbm.xml文件,在Set元素中添加lazy="false"
2.使用NHibernateUtil实用类(我比较喜欢,最方便)
NHibernateUtil类提供Initialize方法可以强制初始化未初始化的相关联的对象
代码
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.使用带fetch的HQL查询
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()函数修改如下:
代码
using (ISession iSession = new SessionManager().GetSession())
{
return iSession.CreateQuery("from Order o left join fetch o.Products where o.OrderId=2 ")
.UniqueResult<Order>();
}
以上三种方法生成的SQL前两种是两条:
代码
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 */
后一种是一条:
代码
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 */

浙公网安备 33010602011771号