我有以下实现,并希望就它是否在会话和事务中正确使用NHibernate提供一些反馈。
public interface IUnitOfWork : IDisposable
{
ISession CurrentSession { get; }
void Commit();
void Rollback();
}
public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ITransaction _transaction;
public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
CurrentSession = _sessionFactory.OpenSession();
_transaction = CurrentSession.BeginTransaction();
}
public ISession CurrentSession { get; private set; }
public void Dispose()
{
CurrentSession.Close();
CurrentSession = null;
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
if (_transaction.IsActive) _transaction.Rollback();
}
}
注入绑定
Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<ISessionFactory>().ToProvider<NHibernateSessionFactoryProvider>().InSingletonScope();
Bind<IRepository>().To<Repository>().InTransientScope();
这是用法示例:
public class Repository : IRepository
{
private readonly ISessionFactory _sessionFactory;
public Repository(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
public void Add(IObj obj)
{
using (var unitOfWork = new UnitOfWork(_sessionFactory))
{
unitOfWork.CurrentSession.Save(obj);
unitOfWork.Commit();
}
}
}
在我以前的实现中,我将IUnitOfWork注入到我的存储库构造函数中,如下所示
public Repository(IUnitOfWork unitOfWork)
{...
但是Dispose()方法无法执行,导致随后的调用引发此异常:“无法访问已处置的对象。对象名称:'AdoTransaction'。”
最佳答案
初步观察:您的存储库不应提交工作单元。这打败了工作单元的整体观点。通过立即将更改保存到存储库中,您可以“微管理” NHibernate会话。
在您的应用程序/服务层中,应该在更高层次上引用工作单元。这使您可以使应用程序代码执行可能在不同存储库上执行的多个操作,并且最后仍然可以一次提交所有内容。
UnitOfWork类本身看起来还不错,尽管您应该问自己是否真的需要它。在NHibernate中,ISession是您的工作单元。您的UnitOfWork类似乎并没有增加太多价值(特别是因为无论如何您要公开CurrentSession属性)
但是您确实需要考虑它的一生。我认为您在这一点上错了。会话生存期管理取决于您正在开发的应用程序类型:在Web应用程序中,您通常希望每个请求都有一个工作单元(您可能希望通过Google搜索“每个请求的休眠会话”)。在桌面应用程序中,它稍微复杂一些,您通常会希望“每屏会话”或“每笔业务交易的会话”。