NHibernate之旅(13):初探马上载入机制
本节内容
- 引入
- 马上载入
- 实例分析
- 1.一对多关系实例
- 2.多对多关系实例
- 结语
引入
通过上一篇的介绍,我们知道了NHibernate中默认的载入机制——延迟载入。其本质就是使用GoF23中代理模式实现,这节我们简单分析NHibernate还有一种载入机制——马上载入。
我用一张图片形象的展现马上载入机制。
马上载入
顾名思义,就是立马载入相关联对象集合,与延迟载入相反。
我们能够使用三种方法来马上载入,各自是:可选的lazy属性、NHibernate提供的有用类、HQL抓取策略。以下依次用实例分析当中的机制。
实例分析
1.一对多关系实例
在一对多关系实例中,我们使用Customer对象与Order对象为例,在数据訪问层中依旧使用上一篇的方法,这里使用强制关闭Session的方法,为什么使用Using强制释放资源呢?我就是想利用这个来模拟Web应用程序中的Session机制。用这个分析比没有Using释放资源更有意义。
数据訪问层中方法:载入Customer对象并使用Using强制清理关闭Session
public Customer LazyLoadUsingSession(int customerId)
{
using (ISession _session = new SessionManager().GetSession())
{
return _session.Get<Customer>(customerId);
}
}
1.使用lazy="false"属性
在上一篇我们一直没有改动映射文件即一直默认是lazy="true"。NHibernate就採用了默认的延迟载入。
这里介绍第一种方法就是改动映射文件来马上载入,打开Customer.hbm.xml文件。在Set元素中加入lazy="false"。
编写一个測试验证。调用数据訪问层中的使用Using强制资源清理Session载入Customer对象的方法载入一个Customer对象,NHibernate这时马上载入Customer相关联的Order对象。利用NHibernate提供有用类(NHibernateUtil)測试被关联的Customer对象集合是否已初始化(也就是已载入)。
[Test]
public void EagerLoadUsingLazyFalseTest()
{
Customer customer = _relation.LazyLoadUsingSession(1);
Assert.IsTrue(NHibernateUtil.IsInitialized(customer.Orders));
}
測试成功,证明NHibernate马上载入了Order对象。发现生成两句SQL语句:第一条查询Customer对象,第二条语句查询其相关联的Order对象集合。
SELECT customer0_.CustomerId as CustomerId9_0_,
customer0_.Version as Version9_0_,
customer0_.Firstname as Firstname9_0_,
customer0_.Lastname as Lastname9_0_
FROM Customer customer0_ WHERE customer0_.CustomerId=@p0; @p0 = '1' SELECT orders0_.Customer as Customer1_,
orders0_.OrderId as OrderId1_,
orders0_.OrderId as OrderId6_0_,
orders0_.Version as Version6_0_,
orders0_.OrderDate as OrderDate6_0_,
orders0_.Customer as Customer6_0_
FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = '1'
只是,细心的朋友会发现。这时Orders对象集合的类型是Iesi.Collections.Generic.HashedSet`1[DomainModel.Entities.Order]。上一节仅仅有在没有使用Using强制关闭资源下,Orders对象集合才是这个类型,在使用强制关闭资源的情况下。Orders对象集合的类型为:NHibernate.Collection.Generic.PersistentGenericSet<DomainModel.Entities.Order> ,进一步读取Order项抛出HibernateException异常。我想从这个角度也说明了马上载入机制。
好了,这就讲到这里,还是把映射文件改为原来默认的吧(即去掉lazy="false")。看看还有其他什么方法来马上载入。
2.使用NHibernateUtil有用类
NHibernate提供有用类(NHibernateUtil)不光光仅仅是用来測试被关联的对象集合是否已初始化,另一个很重要的功能就是能够强制初始化未初始化的相关联的对象。有了这个功能。我们就能够改动数据訪问层中的方法。把上面使用Using强制清理关闭Session的方法中加上NHibernateUtil类提供Initialize方法来初始化Customer相关联的Order对象集合。
public Customer EagerLoadUsingSessionAndNHibernateUtil(int customerId)
{
using (ISession _session = new SessionManager().GetSession())
{
Customer customer= _session.Get<Customer>(customerId);
NHibernateUtil.Initialize(customer.Orders);
return customer;
}
}
我们编写一个方法来測试一下:
[Test]
public void EagerLoadUsingSessionAndNHibernateUtilTest()
{
Customer customer = _relation.EagerLoadUsingSessionAndNHibernateUtil(1);
Assert.IsTrue(NHibernateUtil.IsInitialized(customer.Orders));
}
測试成功,这个结果同改动映射文件一样。
2.多对多关系实例
1.使用lazy="false"属性
同理,使用lazy="false"属性来设置马上载入行为,这时在持久化类中就不必为其公共方法、属性和事件声明为virtual属性了,由于没有使用延迟载入。只是在这里我还是推荐大家使用NHibernate默认的延迟载入行为。原因非常easy,NHibernate延迟载入性能上能够提高非常多,在特殊情况下使用以下的方法来马上载入。
这个样例同上面类似。这里就不举反复的样例了。大家自己測试下就能够了。
2.使用NHibernateUtil有用类
假设你须要获得Order实体的相关联对象能够使用NHibernateUtil类初始化关联对象(把他们从数据库取出来)。看看以下数据訪问层中的方法,使用NHibernateUtil类提供Initialize方法初始化相关联的Customer和Product对象。
public DomainModel.Entities.Order
EagerLoadOrderAggregateSessionAndNHibernateUtil(int orderId)
{
using (ISession _session = new SessionManager().GetSession())
{
DomainModel.Entities.Order order =
_session.Get<DomainModel.Entities.Order>(orderId);
NHibernateUtil.Initialize(order.Customer);
NHibernateUtil.Initialize(order.Products);
return order;
}
}
測试上面的方法:
[Test]
public void EagerLoadOrderAggregateSessionAndNHibernateUtilTest()
{
Order order =
_relation.EagerLoadOrderAggregateSessionAndNHibernateUtil(2);
Assert.IsTrue(NHibernateUtil.IsInitialized(order.Customer));
Assert.IsTrue(NHibernateUtil.IsInitialized(order.Products));
Assert.AreEqual(order.Products.Count, 2);
}
看看NHibernate生成的SQL语句。真是多了,一对多关系,多对多关系的一次马上载入就生成了四条SQL语句,分别查询了Order表。Customer表,OrderProduct表相关联的Product。
(Customer与Order一对多关系在这里也马上载入了一次),这时内存中的内容都是这些关联对象的值,你也不是每一个对象都用到,何必要所有载入呢。
SELECT order0_.OrderId as OrderId6_0_,
order0_.Version as Version6_0_,
order0_.OrderDate as OrderDate6_0_,
order0_.Customer as Customer6_0_
FROM [Order] order0_ WHERE order0_.OrderId=@p0; @p0 = '2' SELECT customer0_.CustomerId as CustomerId9_0_,
customer0_.Version as Version9_0_,
customer0_.Firstname as Firstname9_0_,
customer0_.Lastname as Lastname9_0_
FROM Customer customer0_ WHERE customer0_.CustomerId=@p0; @p0 = '1' SELECT orders0_.Customer as Customer1_,
orders0_.OrderId as OrderId1_,
orders0_.OrderId as OrderId6_0_,
orders0_.Version as Version6_0_,
orders0_.OrderDate as OrderDate6_0_,
orders0_.Customer as Customer6_0_
FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = '1' SELECT products0_.[Order] as Order1_1_,
products0_.Product as Product1_,
product1_.ProductId as ProductId8_0_,
product1_.Version as Version8_0_,
product1_.Name as Name8_0_,
product1_.Cost as Cost8_0_
FROM OrderProduct products0_
left outer join Product product1_ on products0_.Product=product1_.ProductId
WHERE products0_.[Order]=@p0; @p0 = '2'
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>();
}
}
编写測试用例測试上面的方法:验证构建一个HQL查询不仅载入Order。也载入了相关联的Customer和Product对象。
[Test]
public void EagerLoadOrderAggregateWithHQLTest()
{
Order order = _relation.EagerLoadOrderAggregateWithHQL(2);
Assert.IsTrue(NHibernateUtil.IsInitialized(order.Customer));
Assert.IsTrue(NHibernateUtil.IsInitialized(order.Products));
Assert.AreEqual(order.Products.Count, 2);
}
通过NHibernate生成SQL语句能够说明NHibernate能够一口气马上载入Order和全部Order相关联的Customer和Product对象。SQL语句生成例如以下:
select order0_.OrderId as OrderId6_0_,
product2_.ProductId as ProductId8_1_,
customer3_.CustomerId as CustomerId9_2_,
order0_.Version as Version6_0_,
order0_.OrderDate as OrderDate6_0_,
order0_.Customer as Customer6_0_,
product2_.Version as Version8_1_,
product2_.Name as Name8_1_,
product2_.Cost as Cost8_1_,
customer3_.Version as Version9_2_,
customer3_.Firstname as Firstname9_2_,
customer3_.Lastname as Lastname9_2_,
products1_.[Order] as Order1_0__,
products1_.Product as Product0__
from [Order] order0_
left outer join OrderProduct products1_ on order0_.OrderId=products1_.[Order]
left outer join Product product2_ on products1_.Product=product2_.ProductId
inner join Customer customer3_ on order0_.Customer=customer3_.CustomerId
where (order0_.OrderId=@p0 ); @p0 = '2' SELECT orders0_.Customer as Customer1_,
orders0_.OrderId as OrderId1_,
orders0_.OrderId as OrderId6_0_,
orders0_.Version as Version6_0_,
orders0_.OrderDate as OrderDate6_0_,
orders0_.Customer as Customer6_0_
FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = '1'
通过使用HQL抓取策略能够非常好的在程序中编写出自己想要的结果。
结语
通过这篇和上一篇我们初步认识了NHibernate中的载入机制。依次从一对多关系、多对多关系角度分析了NHibernate默认延迟载入和马上载入。这些不过我在平时应用、学习中摸索出来的一点收获,并不是官方认可的东西。希望对你有所帮助。
NHibernate之旅(13):初探马上载入机制的更多相关文章
- [转]NHibernate之旅(13):初探立即加载机制
本节内容 引入 立即加载 实例分析 1.一对多关系实例 2.多对多关系实例 结语 引入 通过上一篇的介绍,我们知道了NHibernate中默认的加载机制——延迟加载.其本质就是使用GoF23中代理模式 ...
- NHibernate之旅系列文章导航
NHibernate之旅系列文章导航 宣传语 NHibernate.NHibernate教程.NHibernate入门.NHibernate下载.NHibernate教程中文版.NHibernate实 ...
- NHibernate之旅(18):初探代码生成工具使用
本节内容 引入 代码生成工具 结语 引入 我们花了大量的篇幅介绍了相关NHibernate的知识.一直都是带着大家手动编写代码,首先创建数据库架构.然后编写持久化类和映射文件,最后编写数据操作方法.測 ...
- JVM系列文章(四):类载入机制
作为一个程序猿,只知道怎么用是远远不够的. 起码,你须要知道为什么能够这么用.即我们所谓底层的东西. 那究竟什么是底层呢?我认为这不能一概而论.以我如今的知识水平而言:对于Web开发人员,TCP/IP ...
- Fluent NHibernate之旅
Fluent NHibernate 之旅 导航篇: [原创]Fluent NHibernate之旅开篇: [原创]Fluent NHibernate之旅二--Entity Mapping: [原创]F ...
- Hibernate级联操作和载入机制(二) cascade and fetch
上一篇介绍了Hibernate持久化对象时候的级联操作.本篇介绍读取时候的级联操作. 还是用上一篇的样例.一份问卷有多个问题.可是每一个问题仅仅能属于一份问卷. 我们先看測试用例: @Test pub ...
- Android源代码分析-资源载入机制
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 我们 ...
- 深入研究Java类载入机制
深入研究Java类载入机制 类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...
- 【SQL进阶】03.执行计划之旅1 - 初探
听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. S ...
随机推荐
- 京东首页原生----js制作|css动画|js动画|计时器--轮播图(好久没更新,这两天闲的蛋疼做个京东页面分辨率1366*768,919京东,适应没调!)要文件加关注找我要哦!
- 【收藏】Web前端开发第三方插件大全
收集整理了一些Web前端开发比较成熟的第三方插件,分享给大家. ******************************************************************** ...
- Django----中间件详解
Django中间件 在http请求 到达视图函数之前 和视图函数return之后,django会根据自己的规则在合适的时机执行中间件中相应的方法. 中间件的执行流程 1.执行完所有的request ...
- 在微信端使用video标签,播放结束会出现QQ浏览器推荐视频的解决办法(vue)
会出现播放结束显示QQ浏览器推荐视频的原因:(我是vue的项目,而且我是新手,只是单纯的给大家分享一个方法,代码比较low请自动忽略) 因为在x5(QQ浏览器)内核中,把video标签劫持了,只要是检 ...
- 使用javax.script包实现Java设置JS脚本中的变量
下面例子中,我们通过javax.script包ScriptEngine.put()方法设置JS脚本中的变量,JS把所有在线用户输出. package ajava.code.javase; import ...
- Python进阶---面向对象第三弹(进阶篇)
Python对象中一些方法 一.__str__ class Teacher: def __init__(self,name,age): self.name=name self.age=age self ...
- 史上最强学生管理系统之ArrayList版
其实不管是网上或者培训班,都会有学生管理系统的最基础版本,本人也不过是照猫画虎,在某些细节方面进行了一些渲染,使这个最基本的小程序更加人性化和便于利于操作一点,个人愚见,大牛勿喷,欢迎转载(请注明出处 ...
- Docker 部署
一.创建Docker 1.进入Rancher 我用的是rancher2.0,首先点击添加容器~~~ 然后就是填写名称,在仓库里找合适的docker镜像,端口映射就是和服务器连接,如果要的可以加. 我 ...
- P2051 [AHOI2009]中国象棋
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- webpack 3.X学习之图片处理
CSS中图片处理 在src目录下新建一个images目录,把图片放入images文件夹中:在index.html文件中增加一个div标签: /src/index.html: <div id=&q ...