[NHibernate]延迟加载

目录

写在前面

文档与系列文章

延迟加载

一个例子

总结

写在前面

上篇文章介绍了多对多关系的关联查询的sql,HQL,Criteria查询的三种方式。本篇文章将介绍nhibernate中的延迟加载方式,延迟加载按个人理解也可以叫做按需要加载(Loading-on-demand)。

文档与系列文章

[Nhibernate]体系结构

[NHibernate]ISessionFactory配置

[NHibernate]持久化类(Persistent Classes)

[NHibernate]O/R Mapping基础

[NHibernate]集合类(Collections)映射 

[NHibernate]关联映射

[NHibernate]Parent/Child

[NHibernate]缓存(NHibernate.Caches)

[NHibernate]NHibernate.Tool.hbm2net

[NHibernate]Nullables

[NHibernate]Nhibernate如何映射sqlserver中image字段

[NHibernate]基本配置与测试 

[NHibernate]HQL查询 

[NHibernate]条件查询Criteria Query

[NHibernate]增删改操作

[NHibernate]事务

[NHibernate]并发控制

[NHibernate]组件之依赖对象

[NHibernate]一对多关系(级联删除,级联添加)

[NHibernate]一对多关系(关联查询)

[NHibernate]多对多关系(关联查询)

延迟加载

延迟加载(Lazy Load)是(也成为懒加载)Hibernate3关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出sql语句进行查询。

延迟加载的有效期是在session打开的情况下,当session关闭后,会报异常。当调用load方法加载对象时,返回代理对象,等到真正用到对象的内容时才发出sql语句。

Hibernate2实现延迟加载有2种方式:1实体对象,2集合。

Hibernate3中又引入了一种新的加载方式:3属性的延迟加载。

一般使用load的方法来实现延迟加载,在实现无限级联动使用延迟加载效率比较好。

——百度百科(java,hibernate)

上面是java中对hibernate的延迟加载的描述,说的比我好多了。

记住三点:1,为了避免无谓的性能开销。2,需要时才真正加载数据。3,使用了代理。 

一个例子

一对多关系

默认延迟加载

采用懒加载的方式根据客户id得到客户信息

 1         /// <summary>
 2         /// 采用懒加载的方式根据客户id得到客户信息
 3         /// </summary>
 4         /// <param name="customerID"></param>
 5         /// <returns></returns>
 6         public Customer GetCustomerbyLazyLoad(Guid customerID)
 7         {
 8             //获得ISession实例
 9             ISession session = NHibernateHelper.GetSession();
10             Customer customer = session.Get<Customer>(customerID);
11             return customer;
12         }

 测试用代码,如图所示,此时数据已经加载出来了

使用SQL Profile监控生成的sql语句,截图如下

 

你会发现,此时只生成了查询customer的sql语句,nhibernate默认是使用延迟加载的,在前面的文章中,并没在映射文件中设置节点的lazy属性。

当展开customer的属性Orders时或者调试向下移动的时候,会执行查询,你会看到如下的sql语句

延迟加载并关闭Session

 1         /// <summary>
 2         /// 采用using释放session,懒加载的方式根据客户id得到客户信息
 3         /// </summary>
 4         /// <param name="customerID"></param>
 5         /// <returns></returns>
 6         public Customer GetCustomerbyLazyLoadUsing(Guid customerID)
 7         {
 8             //获得ISession实例
 9             using(ISession session = NHibernateHelper.GetSession())
10             {
11                 Customer customer = session.Get<Customer>(customerID);
12                 return customer;
13             }
14         }

测试,当视图展开customer的orders属性,或者往下执行获得order集合时出错。

延迟加载,需要的时候再去加载,因为此时session已经关闭,没有去查询的通道了,结果是“此路不通”的提示。

多对多关系

默认延迟加载

这里采用多对多关系那篇文章中举的 Order和Product的例子。

 1         /// <summary>
 2         /// 多对多关系,延迟加载订单产品
 3         /// </summary>
 4         /// <returns></returns>
 5         public Order GetOrderByLazyLoad(Guid orderId)
 6         {
 7             try
 8             {
 9                 var session = NHibernateHelper.GetSession();
10                 return session.Get<Wolfy.Shop.Domain.Entities.Order>(orderId);
11             }
12             catch (Exception)
13             {
14                 throw;
15             }
16         }

进行测试,在查询的时候只有Order表的数据(这个地方,有Order数据的sql,猜测在一对多查询的时候,没有出现查询Customer的sql语句,很有可能是因为缓存的问题造成,因为经常使用Cusomer那条数据进行测试。)

展开Order的属性

当展开Order的属性,回去查询order下的所有的Product,此时生成的sql如下:

延迟加载并关闭Session

 1         /// <summary>
 2         /// 多对多关系,延迟加载订单产品
 3         /// </summary>
 4         /// <returns></returns>
 5         public Order GetOrderByLazyLoadUsing(Guid orderId)
 6         {
 7             //session使用后即释放
 8             using (var session = NHibernateHelper.GetSession())
 9             { return session.Get<Wolfy.Shop.Domain.Entities.Order>(orderId); }
10         }

测试

此时生成的sql语句

如果此时展开Products,同样会出现上面的异常

通过上面的比较一对多和多对多的默认延迟加载和关闭session后的情况类似。

N+1次select查询问题

如果Order下有很多个Product,而我们就想需要的时候才去加载其中某些Product的信息,如果采用立即加载的方式,势必产生多个sql语句,例如第一次查询得到所有的Order对象,然后根据orderid去查询得到所有的产品。

测试,多对多延迟加载订单和订单下单价大于6666的产品

 1        protected void btnMany2Many_Click(object sender, EventArgs e)
 2         {
 3             Business.OrderBusiness orderBusiness = new Business.OrderBusiness();
 4             Order order = orderBusiness.GetOrderByLazyLoad(new Guid("78A53F67-A293-48A1-BBE2-86FED77342FA"));
 5             decimal sum = 0;
 6             foreach (var item in order.Products)
 7             {
 8                 if (item.Price >= 6666)
 9                 {
10                     sum += item.Price;
11                 }
12             }
13             Response.Write(sum.ToString());
14         }

生成的sql语句

延迟加载,可以解决select N+1的问题,比如你查询一个订单还有订单下的Product,势必会产生多条sql语句,先是查询order的sql语句,然后是查询product的sql语句,就会频繁的查询数据库,造成性能方面的压力,而采用延迟加载,通过上面生成的sql语句你会发现,使用left out join 将关联的表拼接起来,只生成了一条sql。

总结

本篇文章介绍了Nhibernate在延迟加载方面的内容,Nhibernate在使用过程中延迟加载方式是默认的。对延迟加载的定义,需要再慢慢的体会。

延迟加载(Lazy Load)是(也成为懒加载)Hibernate3关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出sql语句进行查询。

延迟加载的有效期是在session打开的情况下,当session关闭后,会报异常。当调用load方法加载对象时,返回代理对象,等到真正用到对象的内容时才发出sql语句。

Hibernate2实现延迟加载有2种方式:1实体对象,2集合。

Hibernate3中又引入了一种新的加载方式:3属性的延迟加载。

一般使用load的方法来实现延迟加载,在实现无限级联动使用延迟加载效率比较好。

——百度百科(java,hibernate)

 

博客地址: http://www.cnblogs.com/wolf-sun/
博客版权: 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
再次感谢您耐心的读完本篇文章。

转载:http://www.cnblogs.com/wolf-sun/p/4077226.html

时间: 2024-08-03 20:11:28

[NHibernate]延迟加载的相关文章

NHibernate延迟加载机制

NHibernate实现延迟加载的主要结构: BuildSessionFactory的时候: 1. 根据proxyfactory.factory_class的配置创建IProxyFactoryFactory对象 2. 如果use_proxy_validator配置为true(默认为true),加载实体映射元数据之后,对需要代理的 实体使用 IProxyFactoryFactory的ProxyValidator进行验证(例如要求实体有默认构造器.方法属性必 须为virtual类型等) 3. 为需要

[NHibernate]存储过程的使用(二)

目录 写在前面 文档与系列文章 创建对象 更新对象 总结 写在前面 上篇文章介绍了如何使用MyGeneration代码生成器生成存储过程,以及nhibernate中通过存储过程删除数据的内容,这篇文章将介绍如何创建对象,更新对象. 文档与系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) [NHibernate]O/R Mapping基础 [NHibernate]集合类(

[NHibernate]N+1 Select查询问题分析

目录 写在前面 文档与系列文章 N+1 Select查询问题分析 总结 写在前面 在前面的文章(延迟加载,立即加载)中都提到了N+1 Select的问题,总觉得理解的很不到位,也请大家原谅,这也是为什么单独将该问题拿出来做分析的原因.nhibernate的默认Lazy加载方式是解决N+1 select问题的一种方案,而我自身的理解是立即加载可以解决,完全的背道而驰了.写出那篇文章后,对这个问题,一直念念不忘,总觉得哪地方不对劲.由于我对问题的理解很不透彻,也同样造成你的误解,真的很抱歉. 文档与

[NHibernate]存储过程的使用(三)

目录 写在前面 文档与系列文章 查询 总结 写在前面 前面的文章介绍了在nhibernate中使用存储过程进行增删改的操作,当然查询也是可以的,在nhibernate中也可以执行任意的存储过程.本篇文章将介绍如何使用查询的存储过程的方式. 文档与系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) [NHibernate]O/R Mapping基础 [NHibernate]

[Nhibernate]对象状态

目录 写在前面 文档与系列文章 对象状态 瞬时态(Transient) 持久态(Persistent) 托管态(Detached) 对象状态转换 总结 写在前面 前面两篇文章介绍了SchemaExport工具的使用,使用该工具可以根据映射文件生成数据库架构,这篇文章将介绍nhibernate中的三种对象状态. 在程序运行过程中,使用对象的方式操作数据库的同时,必然会产生一系列的持久化对象.这些对象可能是刚刚创建并准备进行存储的,也有可能是从数据库进行查询得到的,为了区别这些对象,根据对象和当前S

[Nhibernate]二级缓存(二)

目录 写在前面 文档与系列文章 更新数据 二级缓存管理 总结 写在前面 本篇文章也算nhibernate入门系列的结尾了,在总结nhibernate系列的过程中,遇到了很多问题,学习的过程也是解决bug的过程,在学习nhibernate的过程中还学习了单元测试的使用,这个是附属产品,我也没有想到,算是意外收获吧.这个系列学完了,正好公司有个项目,马上就要立项,正好能将学到的东西运用到实际的项目中,想想就让人激动.当然,我相信在实际的项目中,肯定还会遇到问题,但是通过本系列的学习,我已经不怕遇到b

[Nhibernate]二级缓存(一)

目录 写在前面 文档与系列文章 二级缓存 Nhibernate二级缓存提供程序 一个例子 总结 写在前面 上篇文章介绍了nhibernate中一级缓存的相关内容,一级缓存过期时间和ISession对象的生命周期相同,并且不同的Session不能共享缓存,一级缓存也可以成为ISession缓存.那么现在我们就学一下nhibernate中的二级缓存,即ISessionFactory级别缓存,可被所有的ISession所共享.二级缓存是可扩展的,在http://sourceforge.net/proj

[NHibernate]代码生成器的使用

目录 写在前面 文档与系列文章 代码生成器的使用 总结 写在前面 前面的文章介绍了nhibernate的相关知识,都是自己手敲的代码,有时候显得特别的麻烦,比如你必须编写持久化类,映射文件等等,举得例子比较简单,字段比较少,如果一个数据表有几十个字段,你手敲的话烦都烦死了,不过为了学习nhibernate的语法,初学的过程还是建议自己动手,这样敲的多了就对每个过程,及映射文件中的节点的含义有个大致印象.前面举的例子,你也会发现这种方式的步骤就是首先创建数据库,然后编写持久化类,映射文件,最后编写

[Nhibernate]一级缓存

目录 写在前面 文档与系列文章 一级缓存 一个例子 一级缓存管理 总结 写在前面 上篇文章介绍了nhibernate中对象的三种状态,通过对象的三种状态,很容易想到缓存. 什麽是缓存? 有时候,某些数据是会经常需要访问的,像硬盘内部的缓存(暂存器的一种)会将读取比较频繁的一些数据存储在缓存中,再次读取时就可以直接从缓存中直接传输.说白了,缓存是用空间换取时间的一种技术. 文档与系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibern