正确使用NHibernate工作单元模式和Ninject
我有以下实现,并希望得到一些反馈,以了解它是否正确地将NHibernate用于会话和事务正确使用NHibernate工作单元模式和Ninject,nhibernate,session,transactions,ninject,unit-of-work,Nhibernate,Session,Transactions,Ninject,Unit Of Work,我有以下实现,并希望得到一些反馈,以了解它是否正确地将NHibernate用于会话和事务 public interface IUnitOfWork : IDisposable { ISession CurrentSession { get; } void Commit(); void Rollback(); } public class UnitOfWork : IUnitOfWork { private readonly ISessionFactory _se
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();
}
}
Ninject绑定
Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<ISessionFactory>().ToProvider<NHibernateSessionFactoryProvider>().InSingletonScope();
Bind<IRepository>().To<Repository>().InTransientScope();
在我以前的实现中,我会像这样将IUnitOfWork注入到我的存储库构造函数中
public Repository(IUnitOfWork unitOfWork)
{...
但是Dispose()方法将不会执行,导致后续调用引发此异常:“无法访问已处置对象。对象名称:'AdoTransaction”“”第一个观察:存储库不应提交工作单元。这违背了工作单元模式的全部要点。通过立即将更改保存到存储库中,您可以“微观管理”NHibernate会话 工作单元应该在应用程序/服务层的堆栈的更高层引用。这允许您使用应用程序代码执行多个操作,可能在不同的存储库上执行,但最后仍然可以同时提交所有内容 UnitOfWork类本身看起来不错,不过您应该问问自己是否真的需要它。在NHibernate中,会话是您的工作单元。UnitOfWork类似乎没有增加太多的值(特别是因为您仍然公开了CurrentSession属性)
但你需要考虑它的一生。我认为你在这一点上错了。会话生存期管理取决于您正在开发的应用程序的类型:在web应用程序中,您通常希望每个请求有一个工作单元(您可能希望谷歌搜索“每个请求的nhibernate会话”)。在桌面应用程序中,它稍微复杂一些,大多数情况下,您需要“每个屏幕的会话”或“每个业务事务的会话”。我有一个大部分是CRUD类型的应用程序,我使用存储库模式实现了工作单元,但无法真正摆脱会话/事务分离。会话和事务需要不同的生存期。在桌面世界中,会话通常是“每个屏幕”,事务是“每个用户操作” 更多信息请参阅本节 所以我最终得到的是:
->包装会话,实现IUnitOfWork
IDisposable
->包装事务,实现IAtomicUnitOfWork
IDisposable
->提供获取、保存、删除和查询访问IRepository
IUnitOfWork
来构建一个IAtomicUnitOfWork
,并且您需要一个IAtomicUnitOfWork
来构建一个IRepository
,以便实施适当的事务管理。这就是我通过实现自己的接口所获得的一切
正如jeroenh所说,您几乎可以使用
ISession
和ITransaction
,但最终,我觉得根据我定义的接口编写所有代码要好一点。答案的一个重要部分在于您希望事务大小是什么。现在(正如jeroenh所指出的),事务是存储库中每个方法调用的事务。这是非常小的,可能不需要。我创建了一个ASP.MVC应用程序,它使用的事务大小包含了从单个http请求到所有内容。这可能是多个数据库读取/更新。我为国际奥委会使用相同的工作单位和项目。看一看,也许有些东西能帮你解决问题:
希望这有帮助
鲍勃感谢杰罗恩的反馈。我们的应用程序只需要执行简单的crud操作,而不需要执行多个操作并同时提交所有内容。我之所以选择不直接针对ISession工作,是因为我希望UnitOfWork将开始的会话、开始的会话和结束的会话抽象出来。IUnitOfWork的好处是减少了与ORM的耦合。或者至少这是我能想到的唯一好处:)@Ryan Barett但这有什么用呢?在实用主义和理想主义之间的永恒斗争中又打了一轮,我现在更倾向于艾伦德的观点……我不喜欢艾伦德用“绝对主义”来表达他的一些观点,包括这一点。它是否能为抽象出ORM增加价值取决于应用程序的总体复杂性。如果您的应用程序只执行简单的CRUD,那么它实际上只会增加不必要的复杂性。然而,如果您正在进行全面的DDD(并且您的项目的复杂性实际上保证了DDD),那么将ORM抽象到存储库、UoW等后面可能会增加价值。推荐阅读:“领域驱动设计的模式、原则和实践”(Millet&Tune)。感谢您提供的资源。尽管我的应用程序不是MVC应用程序,但想法是一样的。嗨,鲍勃,不幸的是,你的博客的url已从blog.bobcravens.com更改为bobcravens.com。因此很多东西都被破坏了,比如图像链接。希望你能把它修好。把IUoW发送到IRepository是个好主意。就概念上的拆分而言:IUoW根据定义是一个事务。会话的概念有点不同,它上面的抽象应该有一个不同的名称(我称之为IDatabaseGenericSession)@Ryan Barrett:是的,我认为会话包装器的更好名称应该是某种形式的“上下文”。我认为ObjectContext已经被.NET接受了,不是吗?可能是EntityContext?不确定您的最终决定是什么,但不要这样做!:)说真的,NHibernate已经添加了大量抽象和UoW模式。只需直接使用NHibernate,并保持代码简单。你真的想要更多的抽象来调试吗?
public Repository(IUnitOfWork unitOfWork)
{...