01-05-01-2【Nhibernate (版本3.3.1.4000) 出入江湖】立即加载

相关资料:

http://www.cnblogs.com/lyj/archive/2008/10/29/1322373.html

问题的提出:

1.延迟加载,可能会引起session已经关闭的异常,例如:

当实现延迟加载,当需要Orders时,会通过session去查询,session。但此时,由于session已经关闭,

所以会抛出异常:

{"Initializing[Model.Customer#336]-failed to lazily initialize a collection of role: Model.Customer.Orders, no session or session was closed"}

解决方法是,使用强制立即加载:

方法一:为类添加一个方法专门用于加载Orders


public Orders LoadOrders(int customerId)
{
using (ISession _session = new SessionManager().GetSession())
{
return _session.Get<Customer>(customerId).Orders;
}
}

方法二:用NHibernateUtil.Initialize()进行强立即迟加载


        public Customer Get(int customerId)
{
Customer customer = null;
ISession session = _sessionManager.GetSession();
ITransaction transaction = session.BeginTransaction();
try
{
customer = session.Get<Customer>(customerId);
//强制立即加载
NHibernateUtil.Initialize(customer.Orders);
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
finally
{
session.Close();
}

return customer;
}

public Customer Load(int customerId)
{
Customer customer = null;
using (_session)
{
customer = _session.Load<Customer>(customerId);
//强制立即加载
NHibernateUtil.Initialize(customer.Orders);
return customer;

}
}

问题的提出:

2.延迟加载,当关联的表很多,例如:

 Customer--》Orders--》Product--》Company--》。。。

可能会引起连带加载过多其他实体对象,照成资源消耗。

解决方案:fetch的HQL查询:

【1】如果没有用关键fetch的HQL查询是对Orders进行延迟加载的,如下所示:


        public IList<Customer> GetByHQL()
{
using (_session)
{
//注意;如果没有用关键fetch的HQL查询是对Orders进行延迟加载的,
return _session.CreateQuery("select DISTINCT c from Customer c join c.Orders ")
.List<Customer>();

}
}

测试代码:
[TestMethod]
public void TestGetByHQL()
{
CustomerService customerService = new CustomerService();

IList<Customer> customersList = customerService.GetByHQL();

//foreach (var customer in customersList)
//{
// Console.WriteLine("{0}的Order数量:{1}",
// customer.CustomerId, customer.Orders.Count());
//}
}

从下面输出的SQL语句,可以看出,没用加载Orders

NHibernate:
select
distinct customer0_.CustomerId as CustomerId0_,
customer0_.Version as Version0_,
customer0_.Firstname as Firstname0_,
customer0_.Lastname as Lastname0_,
customer0_.Age as Age0_
from
Customer customer0_
inner join
[
Order] orders1_
on customer0_.CustomerId=orders1_.CustomerId

【2】在HQL查询中加入fetch进行强制立即加载


        public IList<Customer> GetByHQLAndFetch()
{
using (_session)
{
//注意;如果没哟关键fetch,HQL是对Orders进行延迟加载的,
//就是通过fetch进行强制立即加载
return _session.CreateQuery("select DISTINCT c from Customer c join fetch c.Orders ")
.List<Customer>();

}
}

测试代码:

[TestMethod]
public void TestGetByHQLAndFetch()
{
CustomerService customerService = new CustomerService();

IList<Customer> customersList = customerService.GetByHQLAndFetch();

//foreach (var customer in customersList)
//{
// Console.WriteLine("{0}的Order数量:{1}",
// customer.CustomerId, customer.Orders.Count());
//}
}

从下面输出的SQL语句,可以看出,添加了fetch的HQL对Orders进行了强制立即加载

NHibernate:
select
distinct customer0_.CustomerId as CustomerId0_0_,
orders1_.OrderId as OrderId1_1_,
customer0_.Version as Version0_0_,
customer0_.Firstname as Firstname0_0_,
customer0_.Lastname as Lastname0_0_,
customer0_.Age as Age0_0_,
orders1_.OrderDate as OrderDate1_1_,
orders1_.CustomerId as CustomerId1_1_,
orders1_.CustomerId as CustomerId0__,
orders1_.OrderId as OrderId0__
from
Customer customer0_
inner join
[
Order] orders1_
on customer0_.CustomerId=orders1_.CustomerId

fetch的缺陷,来自

http://www.cnblogs.com/lyj/archive/2008/10/29/1322373.html

使用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立即取得那些原本需要延迟加载的属性。

时间: 2024-10-20 02:44:32

01-05-01-2【Nhibernate (版本3.3.1.4000) 出入江湖】立即加载的相关文章

01-08-03【Nhibernate (版本3.3.1.4000) 出入江湖】二级缓存:NHibernate自带的HashtableProvider之缓存管理

http://www.cnblogs.com/lyj/archive/2008/11/28/1343418.html 管理NHibernate二级缓存 NHibernate二级缓存由ISessionFactory创建并由ISessionFactory自行维护.我们使用NHibernate操作数据时,ISessionFactory能够自动同步缓存,保证缓存的有效性.但是当我们批量操作数据时,往往NHibernate不能维护缓存持久有效.ISessionFactory提供了可编程方式的缓存管理方法.

01-06-01【Nhibernate (版本3.3.1.4000) 出入江湖】事务

Nhibernate事务的使用: public void Add(Customer customer) { ISession session = _sessionManager.GetSession(); ITransaction transaction = session.BeginTransaction(); try { session.Save(customer); session.Flush();//清除一级缓存 transaction.Commit(); } catch (Except

01-08-01【Nhibernate (版本3.3.1.4000) 出入江湖】NHibernate中的三种状态

以下属于不明来源资料: 引入 在程序运行过程中使用对象的方式对数据库进行操作,这必然会产生一系列的持久化类的实例对象.这些对象可能是刚刚创建并准备存储的,也可能是从数据库中查询的,为了区分这些对象,根据对象和当前会话的关联状态,我们可以把对象分为三种: 瞬时对象:对象刚刚建立.该对象在数据库中没有记录,也不在ISession缓存中.如果该对象是自动生成主键,则该对象的对象标识符为空. 持久化对象:对象已经通过NHibernate进行了持久化,数据库中已经存在对应的记录.如果该对象是自动生成主键,

01-08-01【Nhibernate (版本3.3.1.4000) 出入江湖】NHibernate中的一级缓存

缓存的范围? 1.事务范围 事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束.事务范围的缓存使用内存作为存储介质,一级缓存就属于事务范围. 2.应用范围 应用程序的缓存可以被应用范围内的所有事务共享访问.缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束.应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存就属于应用范围. 3.集群范围 在集群

01-05-01-1【Nhibernate (版本3.3.1.4000) 出入江湖】延迟加载及其class和集合(set、bag等)的Lazy属性配置组合对Get和Load方法的影响

这篇文章 http://ayende.com/blog/3988/nhibernate-the-difference-between-get-load-and-querying-by-id One of the more common mistakes that I see people doing with NHibernate is related to how they are loading entities by the primary key. This is because the

01-08-05【Nhibernate (版本3.3.1.4000) 出入江湖】NHibernate二级缓存:第三方MemCache缓存

一.准备工作 [1]根据操作系统(位数)选择下载相应版本的MemCache, MemCache的下载和安装,参看: http://www.cnblogs.com/easy5weikai/p/3760677.html [2]第三方MemCache缓存适配器,下载地址: http://sourceforge.net/projects/nhcontrib/files/ 特别说明: 1.一定要版本一致 MemCache缓存适配器写本文的时候最高版本是:NHCH-3.2.0.GA-bin(不支持高版本的N

01-07-01【Nhibernate (版本3.3.1.4000) 出入江湖】并发控制

Nhibernate 并发控制 [1]悲观并发控制 正在使用数据的操作,加上锁,使用完后解锁释放资源. 使用场景:数据竞争激烈,锁的成本低于回滚事务的成本 缺点:阻塞,可能死锁 [2]乐观并发控制: 所谓乐观,就是乐观的认为其他人没有在用该资源,资源的使用者不加锁. A 读取数据后,如果该数据被别人B修改,产生错误,A回滚事务并重新开始. 使用场景:数据竞争不激烈,回滚事务的成本低于锁的成本. ---------------------------------------------------

01-04-01【Nhibernate (版本3.3.1.4000) 出入江湖】原生的SQL查询

Nhibernate 支持原生的SQL查询 : 1 /// <summary> 2 /// 使用原生的SQL查询 3 /// </summary> 4 /// <param name="datetime"></param> 5 /// <returns></returns> 6 public IList<Customer> GetCustomersByDateTimeUsingSql(string da

01-03-02-1【Nhibernate (版本3.3.1.4000) 出入江湖】CRUP操作--cascade 级联相关

要点: 1. <!--双向关联时要用:inverse:由子表来维护关系,cascade:级联的关系 如果没有这个设置, 插入Customer成功(即使现在Order插入Order抛异常,这时产生了垃圾数据, 好的做法是用事务两者都能插入,避免垃圾数据的产生--> <!--经测试:只需要在主表配置cascade="all",而子表不用配置cascade="all", 当删除主表实体时,子表的级联实体也会被删除--> <!--cascade

01-03-02-2【Nhibernate (版本3.3.1.4000) 出入江湖】CRUP操作-Save方法的一些问题

NHibernate--Save方法: CustomerService.cs 1 public void Save(Customer customer) 2 { 3 ISession session = _sessionManager.GetSession(); 4 ITransaction transaction = session.BeginTransaction(); 5 6 try 7 { 8 session.Save(customer); 9 transaction.Commit();