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

jam*_*vey 20 nhibernate asp.net-mvc fluent-nhibernate

我有以下看似简单的场景,但是我对NHibernate还是一个新手.

尝试在Controller上为"编辑"操作加载以下模型时:

控制器的编辑操作:

public ActionResult Edit(Guid id)
{
    return View(_repository.GetById(id));
}
Run Code Online (Sandbox Code Playgroud)

库:

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

模型:

public class SomeModel
{
    public virtual string Content { get; set; }
    public virtual IList<SomeOtherModel> SomeOtherModel { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

- 懒得初始化角色集合:SomeOtherModel,没有关闭会话或会话

我在这里错过了什么?

Ste*_*ger 21

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

有几种方法可以实现这一目标.您可以配置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);
}
Run Code Online (Sandbox Code Playgroud)

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

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();
}
Run Code Online (Sandbox Code Playgroud)

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


Dar*_*rov 10

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

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

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

HasMany(x => x.SomeOtherModel)
    .KeyColumns.Add("key_id").AsBag().Not.LazyLoad();
Run Code Online (Sandbox Code Playgroud)

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

  • 我不会这样做,因为为每个电话打开一个交易是不好的做法.事务隔离也不可用,NHibernate缓存不再有用(每次调用返回一个新实例),持久性无知是不可能的,延迟加载不再工作.简而言之:使用NHibernate的大部分优点都被破坏了. (2认同)