本节内容

  • 引入
  • 马上载入
  • 实例分析
    • 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. 数据库集群 MySQL主从复制

    MySQL主从复制 本节内容我们联系使用MySQL的主从复制功能配置Master和Slave节点,验证数据MySQL的数据同步功能. 因为要使用多个MySQL数据库,所以不建议在电脑上安装多个MySQ ...

  2. jquery多种方式实现输入框input输入时的onput,onpropertychange,onchange触发事件及区别

    有关inputs输入内容的事件监听,一般我们会想到下面几个关键词:onput,onpropertychange,onchange onput与onchange的一个区分 onput:该事件在 < ...

  3. 利用C#转换图片格式及转换为ico

    注意:转换为ICO后效果不好. 源代码: using System;using System.Collections.Generic;using System.Text;using System.Dr ...

  4. Linux 计划任务总结

    今天项目用到了,Linux计划任务,从网上找了基本blog看了,总结了下. Linux 下的计划任务有atd和crond两种计划任务.atd服务使用的at命令只能执行一次,而crond服务使用的cro ...

  5. Robotium 框架学习之Class By

    Class By定义了页面元素的定位和支持哪些页面元素(至少我是这么理解的),使用及其简单:Used in conjunction with the web methods. Examples are ...

  6. C# 中枚举的一点研究(跳过一些net坑的研究而已)

    之前一直使用Enum.Parse()将字符串转为枚举,没有深究,后面发现一个问题后对下面的Enum有了一个初步研究(.net 4.0).看下面代码. (留意,枚举类型是值类型,其值不能为Null,所以 ...

  7. Android OpenGL ES 开发(二): OpenGL ES 环境搭建

    零:环境搭建目的 为了在Android应用程序中使用OpenGL ES绘制图形,必须要为他们创建一个视图容器.其中最直接或者最常用的方式就是实现一个GLSurfaceView和一个GLSurfaceV ...

  8. ThreadLocal终极源码剖析

    目录一.ThreadLocal1.1 源码注释1.2 源码剖析      散列算法-魔数0x61c88647      set操作    get操作    remove操作1.3 功能测试1.4 应用 ...

  9. C#.Net与MATLAB集成

    在数学分析工具方面,MATLAB无疑是佼佼者,除了作为软件工具外,MATLAB的自定义编程语言以及混合编程的支持,使其可以与Python.R之类数学分析语言媲美.尤其是在一些传统领域的研究,由于其研究 ...

  10. Nginx实现https网站配置

    咱们下面以google代理实现的方式来实现https.注意这里的https与google的https无关. 代码如下.有备注/usr/local/nginx/config/vhost/hk.cn331 ...