正确使用NHibernate工作单元模式和Ninject

Bri*_*n T 15 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 _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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Ninject绑定

Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<ISessionFactory>().ToProvider<NHibernateSessionFactoryProvider>().InSingletonScope();
Bind<IRepository>().To<Repository>().InTransientScope();
Run Code Online (Sandbox Code Playgroud)

以下是用法示例:

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();
        }         
    }
}
Run Code Online (Sandbox Code Playgroud)

在我之前的实现中,我会将IUnitOfWork注入到我的存储库构造函数中

public Repository(IUnitOfWork unitOfWork)
    {...
Run Code Online (Sandbox Code Playgroud)

但Dispose()方法不会执行导致后续调用抛出此异常:"无法访问已处置的对象.对象名称:'AdoTransaction'."

jer*_*enh 35

首先观察:您的存储库不应该提交工作单元.这打破了工作单元模式的全部要点.通过立即将更改保存在存储库中,您可以"微观管理"NHibernate会话.

在应用程序/服务层中,应在堆栈的较高位置引用工作单元.这允许您拥有执行多个操作的应用程序代码,可能在不同的存储库上,并且最后仍然可以一次提交所有内容.

UnitOfWork类本身看起来很好,但你应该问自己是否真的需要它.在NHibernate中,ISession是您的工作单元.你的UnitOfWork类似乎没有增加很多价值(特别是因为你无论如何暴露了CurrentSession属性)

但你需要考虑它的寿命.我认为你在这一点上做错了.会话生命周期管理取决于您正在开发的应用程序类型:在Web应用程序中,您通常希望每个请求都有一个工作单元(您可能希望在每个请求的'nhibernate会话'上进行google).在桌面应用程序中,它稍微复杂一点,您大多数时候都想要"每个屏幕的会话"或"每个业务交易的对话".

  • IUnitOfWork的好处是减少了与ORM的耦合.或者至少这是我能想到的唯一好处:) (6认同)
  • @Ryan Barett但是有什么用?http://ayende.com/Blog/archive/2010/07/30/the-false-myth-of-encapsulating-data-access-in-the-dal.aspx (5认同)
  • 另一轮在实用主义和理想主义之间的永恒斗争中被解雇了,现在我更倾向于ayende的观点. (3认同)

Sco*_*ock 8

我有一个主要的CRUD类型的应用程序,我实现了工作单元与存储库模式,但无法真正摆脱会话/事务分裂.会话和交易需要不同的生命周期.在桌面世界中,会话通常是"按屏幕",而事务是"按用户操作".

这篇优秀文章中的更多信息.

所以我最终得到的是:

  • IUnitOfWork - >包装会话,实现 IDisposable
  • IAtomicUnitOfWork - >包装事务,实现 IDisposable
  • IRepository - >提供获取,保存,删除和查询访问权限

我这样做是为了你需要一个IUnitOfWork构建一个IAtomicUnitOfWork,你需要一个IAtomicUnitOfWork构建一个IRepository,以便执行适当的事务管理.这实际上是我通过实现自己的接口获得的.

正如jeroenh所说,你几乎可以使用ISession,ITransaction但最后我觉得在我定义的界面上编写所有代码要好一些.