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 ...
随机推荐
- iOS 极光推送的集成以及一些集成后的狗血
1.首先进入极光文档下载激光推送的SDk---传送门http://docs.jiguang.cn/jpush/client/iOS/ios_sdk/ 将解压后的lib子文件夹(包含JPUSHSer ...
- php缓存模块apc可能导致php-fpm终止
如果你的网站出现502错误.同时你网站中又使用了apc模块来做缓存处理.那么这篇文章兴许能帮到你. 首先,查看了php-fpm 的进程数. 发现php-fpm的进程数已经到达了php-fpm.conf ...
- 配置好postfix邮件服务器之后就可以使用它来发送邮件了
下面是一段摘自W3school关于php mail函数的栗子,经过测试发现两个问题. <?php $to = "somebody@example.com, somebodyelse@e ...
- liunx 系统调用 getopt() 函数
命令行参数解析函数 -- getopt() getopt()函数声明如下: #include <unistd.h>int getopt(int argc, char * const arg ...
- 一个简单的MVC框架的实现
1.Action接口 package com.togogo.webtoservice; import javax.servlet.http.HttpServletRequest; import jav ...
- 有关数据传输GET和POST的方法的区别
有关前后端数据交互,主要是通过走http协议通过post或get的方法,拿angularJS来说:通过JS来发送http请求调用相关接口: $scope.apostDate=function(){ $ ...
- 不想再被鄙视?那就看进来! 一文搞懂Python2字符编码
程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广,作为一个Python程序员,自然最关心的是下面这幅图啦 我们项目组一值使用 ...
- Maven 项目pom.xml报错
Maven项目报 Failure to transfer org.apache.maven.plugins:maven-*-plugin:pom 原因是maven的plugin并未下载到本地 或者本地 ...
- 你是如何自学 Python 的?
作为一名Python爱好者,我也想跟大家分享分享我自学Python的一些小经验.搬来你的小板凳,听听看吧.也许,你会很有收获,也许你也走上了自学Python的不归路.开讲啦~ 首先,你要有自信心,要明 ...
- Do you kown Asp.Net Core -- 配置Kestrel端口
Kestrel介绍 在Asp.Net Core中,我们的web application 其实是运行在Kestrel服务上,它是一个基于libuv开源的跨平台可运行 Asp.Net Core 的web服 ...