代码之家  ›  专栏  ›  技术社区  ›  jamesaharvey

NHibernate-未能延迟初始化角色集合

  •  19
  • jamesaharvey  · 技术社区  · 15 年前

    我有以下看似简单的场景,但我对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; }
    }
    

    我得到以下错误:

    我错过了什么?

    3 回复  |  直到 15 年前
        1
  •  21
  •   Frédéric    7 年前

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

    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
  •  12
  •   Community leo1    7 年前

    您需要急切地加载 SomeOtherModel 如果要在关闭会话之前使用,请执行以下操作:

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

    uses lazy loading 用于集合映射。另一个选项是在映射中修改此默认行为:

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

    每次加载父实体时(使用外部联接)都会急切地加载,而父实体可能不是您想要的。通常,我更喜欢将默认的延迟加载保留在映射级别,并根据情况调整查询。

        3
  •  1
  •   Owen Pauling tmatuschek    9 年前

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

    [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