NHibernate - 延迟初始化角色集合失败
Posted
技术标签:
【中文标题】NHibernate - 延迟初始化角色集合失败【英文标题】:NHibernate -failed to lazily initialize a collection of role 【发布时间】:2010-12-26 00:03:44 【问题描述】:我有以下看似简单的场景,但是我对 NHibernate 还是很陌生。
尝试为我的控制器上的编辑操作加载以下模型时:
控制器的编辑操作:
public ActionResult Edit(Guid id)
return View(_repository.GetById(id));
存储库:
public SomeModel GetById(Guid id)
using (ISession session = NHibernateSessionManager.Instance.GetSession())
return session.Get<SomeModel >(id);
型号:
public class SomeModel
public virtual string Content get; set;
public virtual IList<SomeOtherModel> SomeOtherModel get; set;
我收到以下错误:
- 延迟初始化角色集合失败:SomeOtherModel,没有会话或会话已关闭
我在这里错过了什么?
【问题讨论】:
【参考方案1】:问题是您在模型GetById
方法中创建并关闭了会话。 (using语句关闭会话)会话必须在整个业务事务期间可用。
有几种方法可以实现这一点。您可以将 NHibernate 配置为使用会话工厂 GetCurrentSession 方法。请参阅this on nhibernate.info 或this post on Code Project。
public SomeModel GetById(Guid id)
// no using keyword here, take the session from the manager which
// manages it as configured
ISession session = NHibernateSessionManager.Instance.GetSession();
return session.Get<SomeModel >(id);
我不使用这个。我编写了自己的事务服务,它允许以下内容:
using (TransactionService.CreateTransactionScope())
// same session is used by any repository
var entity = xyRepository.Get(id);
// session still there and allows lazy loading
entity.Roles.Add(new Role());
// all changes made in memory a flushed to the db
TransactionService.Commit();
无论您如何实现它,会话和事务都应该与业务事务(或系统功能)一样长。除非你不能依赖事务隔离也不能回滚整个事情。
【讨论】:
【参考方案2】:如果您打算在关闭会话之前使用 SomeOtherModel
集合,则需要立即加载它:
using (ISession session = NHibernateSessionManager.Instance.GetSession())
return session
.CreateCriteria<SomeModel>()
.CreateCriteria("SomeOtherModel", JoinType.LeftOuterJoin)
.Add(Restrictions.Eq(Projections.Id(), id))
.UniqueResult<SomeModel>();
默认情况下 FluentNHibernate uses lazy loading 用于集合映射。另一种选择是在映射中修改此默认行为:
HasMany(x => x.SomeOtherModel)
.KeyColumns.Add("key_id").AsBag().Not.LazyLoad();
请注意,如果您这样做,SomeOtherModel
将在您每次加载可能不想要的父实体时被急切地加载(使用外部连接)。一般来说,我更喜欢始终将默认延迟加载保留在映射级别,并根据情况调整我的查询。
【讨论】:
我不会这样做,因为为每个调用打开一个事务是不好的做法。事务隔离也不可用,NHibernate 缓存不再有用(每个调用都返回一个新实例),持久性无知是不可能的,延迟加载不再起作用。简而言之:使用 NHibernate 的大部分优势都被破坏了。【参考方案3】:“如果我们想要访问订单行项目(在会话关闭后),我们会得到一个异常。由于会话关闭,NHibernate 无法为我们延迟加载订单行项目。我们可以通过以下方式显示此行为测试方法”
[Test]
[ExpectedException(typeof(LazyInitializationException))]
public void Accessing_customer_of_order_after_session_is_closed_throws()
Order fromDb;
using (ISession session = SessionFactory.OpenSession())
fromDb = session.Get<Order>(_order.Id);
// trying to access the Customer of the order, will throw exception
// Note: at this point the session is already closed
string name = fromDb.Customer.CompanyName;
“使用 NHibernateUtil 类急切加载如果您知道需要访问订单实体的相关对象,您可以使用 NHibernateUtil 类来初始化相关对象(即:从数据库中获取它们)。”
[Test]
public void Can_initialize_customer_of_order_with_nhibernate_util()
Order fromDb;
using (ISession session = SessionFactory.OpenSession())
fromDb = session.Get<Order>(_order.Id);
NHibernateUtil.Initialize(fromDb.Customer);
Assert.IsTrue(NHibernateUtil.IsInitialized(fromDb.Customer));
Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb.OrderLines));
参考:http://nhibernate.info/doc/howto/various/lazy-loading-eager-loading.html
【讨论】:
以上是关于NHibernate - 延迟初始化角色集合失败的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate LazyInitializationException:未能延迟初始化角色集合
无法写入内容:无法延迟初始化角色集合,无法初始化代理 - 无会话
休眠延迟加载不适用于 Spring Boot => 无法延迟初始化角色集合无法初始化代理 - 无会话
Hibernate:未能延迟初始化角色集合,没有会话或会话被关闭
Hibernate org.hibernate.LazyInitializationException:未能延迟初始化角色集合: