2009-12-12 82 views
18

我有以下看似简单的场景,但是我对NHibernate仍然很陌生。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; } 
} 

我得到以下错误:

-failed懒洋洋地初始化角色的集合:SomeOtherModel,没有会话或会话关闭

缺少什么我在这里?

回答

19

问题是您创建并关闭了模型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(); 
} 

但是你实现它,会话和交易应生活,只要商业交易(或系统功能)。除非你不能依赖事务隔离,也不能回滚整个事物。

8

您需要急切地加载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

我不会这么做,因为每次调用打开一个交易是不好的做法。事务隔离也不可用,NHibernate缓存不再有用(每次调用都会返回一个新实例),持久性无知是不可能的,懒惰加载不再工作。简而言之:使用NHibernate的最大好处是被破坏了。 – 2009-12-12 14:56:13

1

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

} 

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

相关问题