本节内容

  • 引入
  • 马上载入
  • 实例分析
    • 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):初探马上载入机制的更多相关文章

  1. [转]NHibernate之旅(13):初探立即加载机制

    本节内容 引入 立即加载 实例分析 1.一对多关系实例 2.多对多关系实例 结语 引入 通过上一篇的介绍,我们知道了NHibernate中默认的加载机制——延迟加载.其本质就是使用GoF23中代理模式 ...

  2. NHibernate之旅系列文章导航

    NHibernate之旅系列文章导航 宣传语 NHibernate.NHibernate教程.NHibernate入门.NHibernate下载.NHibernate教程中文版.NHibernate实 ...

  3. NHibernate之旅(18):初探代码生成工具使用

    本节内容 引入 代码生成工具 结语 引入 我们花了大量的篇幅介绍了相关NHibernate的知识.一直都是带着大家手动编写代码,首先创建数据库架构.然后编写持久化类和映射文件,最后编写数据操作方法.測 ...

  4. JVM系列文章(四):类载入机制

    作为一个程序猿,只知道怎么用是远远不够的. 起码,你须要知道为什么能够这么用.即我们所谓底层的东西. 那究竟什么是底层呢?我认为这不能一概而论.以我如今的知识水平而言:对于Web开发人员,TCP/IP ...

  5. Fluent NHibernate之旅

    Fluent NHibernate 之旅 导航篇: [原创]Fluent NHibernate之旅开篇: [原创]Fluent NHibernate之旅二--Entity Mapping: [原创]F ...

  6. Hibernate级联操作和载入机制(二) cascade and fetch

    上一篇介绍了Hibernate持久化对象时候的级联操作.本篇介绍读取时候的级联操作. 还是用上一篇的样例.一份问卷有多个问题.可是每一个问题仅仅能属于一份问卷. 我们先看測试用例: @Test pub ...

  7. Android源代码分析-资源载入机制

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 我们 ...

  8. 深入研究Java类载入机制

    深入研究Java类载入机制   类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...

  9. 【SQL进阶】03.执行计划之旅1 - 初探

    听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. S ...

随机推荐

  1. 原生promise

    你应该会用事件加回调的办法来处理这类情况:   var img1 = document.querySelector('.img-1'); img1.addEventListener('load', f ...

  2. Problem B: 开个餐馆算算账

    Description 小明创业了!他开了一家餐馆,每天客人还挺多的.每天下班后,他都要算算今天总共收入多少钱,但是手工算太麻烦了,所以他来向你求助了. Input 第1行N>0,表示餐馆提供N ...

  3. CentOS6.8系统下,ecipse下进行编辑操作,意外退出

    错误情况:centos下打开eclipse软件,点击*.java或者*.pom软件卡死,命令行终端报错误信息,稍后eclipse自动退出. 错误信息: Java: cairo-misc.c:380: ...

  4. 无状态的web应用(单个py文件的Django占位图片服务器)

    本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 阅读本文建议了解Django框架的基本工作流程,了解WSGI应用,如果对以上不是很清楚,建议结 ...

  5. axios在vue中的简单配置与使用

    一.axios 简介 axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:https://hzzly.github.io/2017/03/12/ ...

  6. C#里调用 MysqlDB

    最近在做项目,发现在使用Mysql提供给C#操作的类不是和好用,就想办法写了一个操作方便的Mysql数据层类. 比如以前在执 行一个查询 代码                              ...

  7. jstree 获取选中节点的所有子子点

    //加载功能树 function initTree() { $.jstree.destroy(); $.ajax({ type: "Get", url: "/Depart ...

  8. Composer笔记

    安装 windows中安装Composer 一般来说,windows下安装composer有两种办法,一种是直接下载并运行Composer-Setup.exe,这种方法在中国似乎很难完成安装.另一种就 ...

  9. jmockit学习

    下图为jmockit 类图.在我们编写代码时几乎都会用到Expectations(期望)和Verifications(校验),二者均继承自Invacations. 常会用到的注解有:@Mocked @ ...

  10. CentOS7.2非HA分布式部署Openstack Pike版 (实验)

    部署环境 一.组网拓扑 二.设备配置 笔记本:联想L440处理器:i3-4000M 2.40GHz内存:12G虚拟机软件:VMware® Workstation 12 Pro(12.5.2 build ...