NHibernate会话 - 在Windows应用程序中处理会话的常用方法是什么?

时间:2009-07-08 10:12:04

标签: nhibernate

我刚刚开始使用NHibernate,我有一些问题,我不确定如何正确解决。

我开始创建一个包含CUD和一些搜索方法的通用存储库。在DB操作期间,这些方法中的每一个都会打开一个单独的会话(如果需要,还会进行事务处理)。这样做的问题(据我所知)是我无法利用相关集合/对象的延迟加载。

由于几乎每个实体关系在fluent映射中都有.Not.LazyLoad(),因此当我请求给定类型的所有实体的列表时,它会导致整个数据库被加载。

如果我错了,请纠正我,因为在NHibernate方面,我仍然是一个完整的新手:)

最常见的是要避免这种情况?只要程序运行,或者我应该做什么,就有一个全局静态会话保持活动状态?


一些存储库代码:

public T GetById(int id)
{
    using (var session = NHibernateHelper.OpenSession())
    {
        return session.Get<T>(id);
    }
}

使用存储库获取人员

var person = m_PersonRepository.GetById(1); // works fine

var contactInfo = person.ContactInfo; // Throws exception with message:

// failed to lazily initialize a collection, no session or session was closed

1 个答案:

答案 0 :(得分:3)

您的问题实际上归结为对象缓存和重用。如果你从一个会话加载一个Foo对象,那么你可以保持它,然后在以后延迟加载它的Bar属性吗?

每个ISession实例都旨在表示一个工作单元,并带有一级缓存,允许您在该工作单元内多次检索对象,但只有一个数据库命中。它不是线程安全的,绝对不能在WinForms应用程序中用作静态对象。

如果要在处理加载对象的会话时使用对象,则需要使用Session.SaveOrUpdate(object)或Session.Update(object)将其与新会话关联。

您可以在chapter 10 of the Hibernate documentation中找到所有这些内容。

如果这看起来效率低下,那么请研究二级缓存。这是在ISessionFactory级别提供的 - 您的会话工厂可以是静态的,如果启用二级缓存,这将有效地构建大部分数据的内存缓存。只有在没有基础服务更新数据的情况下才能进行二级缓存 - 如果所有数据库更新都通过NHibernate进行,那么它是安全的。

根据发布的代码进行修改

您的会话使用情况处于错误的级别 - 您将其用于单个数据库获取,而不是工作单元。在这种情况下,您的GetById方法应该接受它使用的会话,并且会话实例应该在更高级别进行管理。或者,如果您愿意,您的PersonRepository类应该管理会话,并且您应该为每个工作单元实例化和处置此类型的对象。

public T GetById(int id)
{
    return m_session.Get<T>(id);
}

using (var repository = new PersonRepository())
{
    var person = repository.GetById(1);
    var contactInfo = person.ContactInfo;
} // make sure the repository Dispose method disposes the session.

您收到的错误消息是因为不再使用会话来延迟加载集合 - 您已经处理了它。