NHibernate - 无法延迟初始化角色集合

发布于 2024-08-14 17:16:26 字数 674 浏览 4 评论 0原文

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

我是什么这里不见了?

I have the following seemingly simple scenario, however I'm still pretty new to 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

What am I missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

且行且努力 2024-08-21 17:16:26

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

有多种方法可以实现这一目标。您可以将 NHibernate 配置为使用会话工厂 GetCurrentSession 方法。请参阅nhibernate.info 上的内容这篇关于代码项目的文章

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

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

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

There are several ways to achieve this. You can configure NHibernate to use the session factories GetCurrentSession method. See this on nhibernate.info or 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);
}

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.

只想待在家 2024-08-21 17:16:26

如果您打算在关闭会话之前使用它,则需要立即加载 SomeOtherModel 集合:

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

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

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

请注意,如果执行此操作,每次加载可能不想要的父实体时,SomeOtherModel 都会立即加载(使用外部联接) 。一般来说,我更喜欢始终在映射级别保留默认的延迟加载,并根据情况调整我的查询。

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

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 loading for collection mappings. Another option is to modify this default behavior in your mapping:

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

Note that if you do this SomeOtherModel will 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.

夏の忆 2024-08-21 17:16:26

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

"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"

[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)."

[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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文