NHibernate - 懒得初始化一个角色集合

时间:2009-12-12 14:36:50

标签: asp.net-mvc nhibernate fluent-nhibernate

我有以下看似简单的场景,但我对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,没有关闭会话或会话

我在这里缺少什么?

3 个答案:

答案 0 :(得分:20)

问题是您在模型GetById方法中创建并关闭会话。 (using语句关闭会话)会话必须在整个业务事务期间可用。

有几种方法可以实现这一目标。您可以配置NHibernate以使用会话工厂GetCurrentSession方法。请参阅this on nhibernate.infothis 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