正确使用NHibernate工作单元模式和Ninject [英] Correct use of the NHibernate Unit Of Work pattern and Ninject

查看:75
本文介绍了正确使用NHibernate工作单元模式和Ninject的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下实现方式,并希望获得一些反馈,以了解它是否在会话和事务中正确使用了NHibernate.

I have the following implementation and would like some feedback as to whether it makes correct use of NHibernate for sessions and transactions.

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注入到我的存储库构造函数中,像这样

In my previous implementation I would inject IUnitOfWork into my repository constructor like so

public Repository(IUnitOfWork unitOfWork)
    {...

但是Dispose()方法无法执行,导致随后的调用引发此异常:无法访问已处置的对象.对象名称:'AdoTransaction'."

But the Dispose() method would not execute causing a subsequent call to throw this exception: "Cannot access a disposed object. Object name: 'AdoTransaction'."

推荐答案

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

First observation: your repository should not commit the unit of work. This defeats the whole point of the unit of work pattern. By immediately saving your changes inside the repository, you're "micro managing" the NHibernate Session.

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

The unit of work should be referenced higher up the stack, in your application/service layer. This allows you to have application code that performs several actions, potentially on different repositories, and still at the end commit everything at once.

UnitOfWork类本身看起来不错,尽管您应该问自己是否确实需要它.在NHibernate中,ISession是您的工作单元.您的UnitOfWork类似乎并没有增加太多价值(特别是因为无论如何您要公开CurrentSession属性)

The UnitOfWork class itself looks Ok, though you should ask yourself if you really need it. In NHibernate, the ISession IS your unit of work. Your UnitOfWork class does not seem to add a lot of value (especially since you're exposing the CurrentSession property anyway)

但是您确实需要考虑它的一生.我认为您在这一点上错了.会话生存期管理取决于您正在开发的应用程序的类型:在Web应用程序中,您通常希望每个请求具有一个工作单元(您可能希望通过Google搜索每个请求的休眠会话").在台式机应用程序中,它稍微复杂一些,大多数时候您都希望每屏幕会话数"或每笔业务交易的会话数".

But you do need to think about it's lifetime. I think you have it wrong on this point. Session lifetime management depends on the type of application you're developing: in a web app, you typically want to have a unit of work per request (you might want to google on 'nhibernate session per request'). In a desktop app it's slightly more complicated, you will most of the time want a 'session per screen' or 'conversation per business transaction'.

这篇关于正确使用NHibernate工作单元模式和Ninject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆