NHibernate系列文章二十一:延迟加载
摘要
NHibernate的延迟加载机制是很重要的内容。通过关系映射将数据库表之间的关系映射成对象之间的关系,如果没有延迟加载机制,从主表的一个对象的查询将直接查询出所有与该对象关联的其他对象,如果关联的对象上还有其他的关联对象,还要去查询其他的对象。如果这张“网”非常大,或者关联的数据库记录非常多的话,每次查询主表记录都要把整个数据库都查询一遍,这样效率会非常低下。为了解决这个问题产生了NHibernate延迟加载。对一些属性设置延迟加载,只在对象访问到这些属性的时候才去查询数据库,很大程度上提高了系统性能。
属性是否使用延迟加载在映射文件里设置lazy="true|false"来打开|关闭延迟加载。(NHibnerate默认是开启延迟加载,默认值是true,使用延迟加载)。
对于关联映射的属性,如果查询了主表数据,查询后程序中没有去读其关联属性,这时候如果将Session关闭,NHibernate就不能为我们实现延迟加载。换句话说,对于关联属性,延迟加载只在Session关闭之前有效。
程序演示
1、默认使用延迟加载的情况
假设数据库Customer表里有一条Id为2的记录,与之关联的Order表里有两条Order记录。
var customer = customerService.GetById();
执行此行代码得到的监控结果。
监控结果显示,只查询了Customer表记录。
如果将程序改成下面这样:
var customer = customerService.GetById();
var orders = customer.Orders;
int orderCount = orders.Count;
再次运行程序,得到监控结果:
在执行这句下面赋值语句的时候,才去执行Order表的查询。
int orderCount = orders.Count;
2、关闭延迟加载
修改Customer.hbm.xml文件。
<set name="Orders" table="`Order`" cascade="all-delete-orphan" inverse="true" lazy="false">
<key column="CustomerId"/>
<one-to-many class="Order"/>
</set>
执行同样的查询语句,得到监控结果。
监控记录显示,在查询Customer的同时,还查询了Order记录。
只有在关联的属性记录数量不是很多的情况下才使用lazy="false",关掉延迟加载。
3、延迟加载和关闭Session
上面提到对于关联属性,延迟加载只在Session关闭之前有效。这里用程序演示一下。
修改Main函数。
using Demo.Service;
using Demo.Service.Interface;
using System; namespace Demo.ConsoleApp
{
class Program
{
static readonly ICustomerService customerService = new CustomerService();
static readonly IOrderService orderService = new OrderService();
static readonly IProductService productService = new ProductService(); static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); var customer = customerService.GetById();
Service.Infrastructure.SessionManager.CloseSession();
var orders = customer.Orders;
foreach (var order in orders)
{
Console.WriteLine(order.Id);
} Console.WriteLine("Completed");
Console.ReadLine();
}
}
}
执行程序,得到监控结果。
程序在执行for-each循环取Order对象的时候产生了异常。
如果删除这行代码程序能够正常运行。
Service.Infrastructure.SessionManager.CloseSession();
因此,为了能够利用对象的延迟加载,我们通常的做法是在查询完成后,不关闭Session。
有两种方法可以在关闭Session前,强制立即加载对象关联属性。
1)调用NHibernateUtil.Initialize静态方法,在Session关闭之前强制对指定的对象属性立即加载。
修改Main函数。
static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); var customer = customerService.GetById();
NHibernate.NHibernateUtil.Initialize(customer.Orders);
Service.Infrastructure.SessionManager.CloseSession(); var orders = customer.Orders;
foreach (var order in orders)
{
Console.WriteLine(order.Id);
} Console.WriteLine("Completed");
Console.ReadLine();
}
执行程序,得到监控结果。
2)在关联映射配置节中定义fetch="join",指出对于关联属性立即加载。
修改Customer.hbm.xml文件。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Demo.XML.Entities" namespace="Demo.XML.Entities.Domain">
<class name="Customer" table="Customer">
<id name="Id">
<generator class="native"/>
</id>
<property name="FirstName" not-null="true"/>
<property name="LastName" not-null ="true"/>
<property name="AverageRating"/>
<property name="Points"/>
<property name="HasGoldStatus"/>
<property name="MemberSince"/>
<property name="CreditRating" type="CustomerCreditRating"/>
<component name="Address">
<property name="Street"/>
<property name="City"/>
<property name="Province"/>
<property name="Country"/>
</component>
<set name="Orders" table="`Order`" cascade="all-delete-orphan" inverse="true" fetch="join">
<key column="CustomerId"/>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
修改Main函数。
static void Main(string[] args)
{
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); var customer = customerService.GetById();
Service.Infrastructure.SessionManager.CloseSession(); var orders = customer.Orders;
foreach (var order in orders)
{
Console.WriteLine(order.Id);
} Console.WriteLine("Completed");
Console.ReadLine();
}
执行程序,得到监控结果。
从监控结果看到,这次的查询SQL语句跟以前都不一样。之前执行了两条SQL语句,分别查询Customer表和Order表。这次只执行了一次SQL查询,从主表Customer到从表Order的left join查询。
有兴趣的可以用大数据测试的方法,比较哪种方法执行效率要高。
结语
NHibernate的延迟加载是NHibernate很重要的一个性能优化,NHibernate默认是开启延迟加载的,可以通过设置属性的lazy="false"强制关闭某一个属性的延迟加载。
NHibernate系列文章二十一:延迟加载的更多相关文章
- NHibernate系列文章二十四:NHibernate查询之Linq查询(附程序下载)
摘要 NHibernate从3.0开始支持Linq查询.写Linq to NHibernate查询就跟写.net linq代码一样,非常灵活,可以很容易实现复杂的查询.这篇文章使用Linq to NH ...
- NHibernate系列文章二十八:NHibernate Mapping之Auto Mapping(附程序下载)
摘要 上一篇文章介绍了Fluent NHibernate基础知识.但是,Fluent NHibernate提供了一种更方便的Mapping方法称为Auto Mapping.只需在代码中定义一些Conv ...
- NHibernate系列文章二十七:NHibernate Mapping之Fluent Mapping基础(附程序下载)
摘要 从这一节起,介绍NHibernate Mapping的内容.前面文章都是使用的NHibernate XML Mapping.NHibernate XML Mapping是NHibernate最早 ...
- NHibernate系列文章二十五:NHibernate查询之Query Over查询(附程序下载)
摘要 这一篇文章介绍在NHibernate 3.2里引入的Query Over查询,Query Over查询跟Criteria查询类似.首先创建IQueryOver对象,然后通过调用该对象的API函数 ...
- NHibernate系列文章二十三:NHibernate查询之Criteria查询(附程序下载)
摘要 上一篇文章介绍了NHibernate HQL,他的缺点是不能够在编译时发现问题.如果数据库表结构有改动引起了实体关系映射的类有改动,要同时修改这些HQL字符串.这篇文章介绍NHibernate面 ...
- NHibernate系列文章二十二:NHibernate查询之HQL查询(附程序下载)
摘要 NHibernate提供了多种查询方式,最早的HQL语言查询.Criteria查询和SQL Query,到NHibernate 3.0的Linq NHibernate,NHIbernate 4. ...
- NHibernate系列文章二十:NHibernate关系之一对一(附程序下载)
摘要 NHibernate一对一关系虽然不经常碰到,但是在对于数据库结构优化的时候,经常会碰到一对一关系.比如,产品详细信息比较多的时候,可以把产品详细信息放到另一张表里面,Product主表只记录产 ...
- NHibernate系列文章二:创建NHibernate工程
摘要 这篇文章介绍了如何创建一个简单的使用NHibernate的控制台应用程序,包括使用NuGet.简单的配置.单表映射.对NHibernate配置文件添加智能提示.使用ISessionFactory ...
- NHibernate系列文章二十六:NHibernate查询之SQL Query查询(附程序下载)
摘要 NHibernate在很早的版本就提供了SQL Query(原生SQL查询),对于很复杂的查询,如果使用其他的查询方式实现比较困难的时候,一般使用SQL Query.使用SQL Query是基于 ...
随机推荐
- python中的input,print
此用例在python3.3.5中测试通过: 输入:在python中输入是使用input,下面示例代码表示把输入的值存入变量s中,并输入s 在这里提醒一下:使用input获取的值都是string类型
- [IOS8兼容性]IOS8上收不到通知
应用中用到了通知功能,同时有远程通知和本地通知. 测试报告应用在iphone6 plus上,收不到本地通知. 因为所有的第三方闹钟应用采用的都是本地通知方式,所以第一时间随机下载了5款不同的闹钟应用. ...
- LINQ 联查多表数据并封装到ViewModel的实现
LINQ 联查多表数据并封装到ViewModel的实现 public List<MyTask> GetPagedTaskList(int pageIndex, int pageSize, ...
- CSS盒子模型的一些理解
盒子模型相当于把现实中的盒子形象化. 盒子模型的大小="内容(content)+内填充(padding)+边框(border)+外边距(margin)" 盒子模型方向为:top, ...
- Node.JS 学习路线图
转载自:http://www.admin10000.com/document/4624.html 从零开始nodejs系列文章, 将介绍如何利Javascript做为服务端脚本,通过Nodejs框架w ...
- windows下安装Composer
1.下载https://getcomposer.org/composer.phar 2.复制到php.exe所在目录 3.在php.exe所在目录新建composer.bat文件 4.打开cmd,跳转 ...
- 05:统计单词数【NOIP2011复赛普及组第二题】
05:统计单词数 总时间限制: 1000ms 内存限制: 65536kB 描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次 ...
- git之.gitignore文件用途
gitignore文件用于忽略无需追踪的文件. 配置文件: $HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore 举例说明: $ gi ...
- Oracle用户密码过期后重置SYS用户密码
问题状况: SYS.SYSTEM用户的密码过期,无法登陆. 运行EM控制台后,出现错误——ORA-28001: the password has expired (DBD ERROR: OCISess ...
- Maven手动下载jar
首先,手动下载的jar一定要是官网上的哦.http://mvnrepository.com/ 在下载之前要在pom.xml里按照官网的格式添加节点,这步一定不能省. 然后迅雷下载jar到本地硬盘. 开 ...