我刚刚开始使用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发布于 2009-07-08 10:28:51
您的问题实际上归结为对象缓存和重用。如果您从一个会话加载Foo对象,那么可以保持它,然后在稍后的某个时间点延迟加载其Bar属性吗?
每个ISession实例都设计为表示一个工作单元,并附带了一个第一级缓存,它允许您在该工作单元内多次检索对象,但只有一个数据库命中。它不是线程安全的,绝对不应该作为WinForms应用程序中的静态对象使用。
如果您想在加载的会话被释放时使用对象,则需要使用Session.SaveOrUpdate( object )或Session.Update(object)将其与新会话相关联。
您可以在Hibernate文档的第10章中找到所有这些解释。
如果这看起来很低效,那么就研究二级缓存。这是在ISessionFactory级别提供的-您的会话工厂可以是静态的,如果您启用第二级缓存,这将有效地构建一个内存缓存的大部分数据。只有在没有底层服务更新数据的情况下,二级缓存才是合适的--如果所有数据库更新都通过NHibernate进行,那么它是安全的。
根据发布的代码编辑
您的会话使用处于错误的级别--您将其用于单个数据库get,而不是一个工作单元。在这种情况下,您的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.您收到的错误消息是因为不再有会话可以用来延迟加载集合--您已经将其释放了。
https://stackoverflow.com/questions/1097211
复制相似问题