asp.net-mvc NHibernate - 无法懒惰地初始化角色集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1893611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:58:59  来源:igfitidea点击:

NHibernate -failed to lazily initialize a collection of role

asp.net-mvcnhibernatefluent-nhibernate

提问by jamesaharvey

I have the following seemingly simple scenario, however I'm still pretty new to NHibernate.

我有以下看似简单的场景,但是我对 NHibernate 还是很陌生。

When trying to load the following model for an Edit action on my Controller:

尝试为我的控制器上的编辑操作加载以下模型时:

Controller's Edit Action:

控制器的编辑动作:

public ActionResult Edit(Guid id)
{
    return View(_repository.GetById(id));
}

Repository:

存储库:

public SomeModel GetById(Guid id)
{
    using (ISession session = NHibernateSessionManager.Instance.GetSession())
        return session.Get<SomeModel >(id);
}

Model:

模型:

public class SomeModel
{
    public virtual string Content { get; set; }
    public virtual IList<SomeOtherModel> SomeOtherModel { get; set; }
}

I get the following error:

我收到以下错误:

-failed to lazily initialize a collection of role: SomeOtherModel, no session or session was closed

-未能延迟初始化角色集合:SomeOtherModel,没有会话或会话被关闭

What am I missing here?

我在这里缺少什么?

回答by Stefan Steinegger

The problem is that you create and also close the session in you models GetByIdmethod. (the using statement closes the session) The session must be available during the whole business transaction.

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

There are several ways to achieve this. You can configure NHibernate to use the session factories GetCurrentSession method. See this on nhibernate.infoor this post on Code Project.

有几种方法可以实现这一点。您可以将 NHibernate 配置为使用会话工厂 GetCurrentSession 方法。在 nhibernate.infoCode 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);
}

I don't use this. I wrote my own transaction service which allows the following:

我不使用这个。我编写了自己的交易服务,它允许以下内容:

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();
}

However you implement it, sessions and transactions should live as long as a business transaction (or system function). Unless you can't rely on transaction isolation nor rollback the whole thing.

无论您如何实现它,会话和事务都应该与业务事务(或系统功能)一样长。除非你不能依赖事务隔离或回滚整个事情。

回答by Darin Dimitrov

You need to eagerly load the SomeOtherModelcollection if you intend to use it before closing the session:

SomeOtherModel如果您打算在关闭会话之前使用它,则需要急切地加载它:

using (ISession session = NHibernateSessionManager.Instance.GetSession())
{
    return session
        .CreateCriteria<SomeModel>()
        .CreateCriteria("SomeOtherModel", JoinType.LeftOuterJoin)
        .Add(Restrictions.Eq(Projections.Id(), id))
        .UniqueResult<SomeModel>();
}

By default FluentNHibernate uses lazy loadingfor collection mappings. Another option is to modify this default behavior in your mapping:

默认情况下,FluentNHibernate使用延迟加载进行集合映射。另一种选择是在映射中修改此默认行为:

HasMany(x => x.SomeOtherModel)
    .KeyColumns.Add("key_id").AsBag().Not.LazyLoad();

Note that if you do this SomeOtherModelwill be eagerly loaded (using an outer join) every time you load the parent entity which might not be want you want. In general I prefer to always leave the default lazy loading at the mapping level and tune my queries depending on the situation.

请注意,如果您这样做,则SomeOtherModel每次加载可能不需要的父实体时都会急切加载(使用外部联接)。一般来说,我更喜欢始终在映射级别保留默认的延迟加载,并根据情况调整我的查询。

回答by Darin Dimitrov

"If we want to access the order line items (after the session has been closed) we get an exception. Since the session is closed NHibernate cannot lazily load the order line items for us. We can show this behavior with the following test method"

“如果我们想访问订单行项目(在会话关闭后),我们会收到一个异常。由于会话已关闭,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;
}

"Eagerly loading with the NHibernateUtil class If you know you need have access to related objects of the order entity you can use the NHibernateUtil class to initialize the related objects (that is: to fetch them from the database)."

“急切地加载 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));

}

Reference: http://nhibernate.info/doc/howto/various/lazy-loading-eager-loading.html

参考:http: //nhibernate.info/doc/howto/various/lazy-loading-eager-loading.html