我有以下看似简单的场景,但我对NHibernate还是很陌生。
尝试在我的控制器上为“编辑”操作加载以下模型时:
Controller的编辑操作:
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,没有关闭会话或会话
我在这里缺少什么?
答案 0 :(得分:20)
问题是您在模型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();
}
但是,如果实现它,会话和事务应该与业务事务(或系统函数)一样长。除非你不能依赖事务隔离,也不能回滚整个事情。
答案 1 :(得分:10)
如果您打算在关闭会话之前使用它,则需要急切加载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
(使用外部联接)。一般情况下,我更喜欢始终在映射级别保留默认的延迟加载,并根据情况调整查询。
答案 2 :(得分:1)
“如果我们想访问订单行项目(会话关闭后),我们会收到异常。由于会话已关闭,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类初始化相关对象(即:从数据库中获取它们)。” p>
[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