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

查看:17
本文介绍了NHibernate Unit Of Work模式和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();
    }
}

Ninject 绑定

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 应用程序中,您通常希望每个请求都有一个工作单元(您可能希望在每个请求的 nhibernate 会话"上进行谷歌搜索).在桌面应用程序中,它稍微复杂一些,大多数时候您需要每个屏幕的会话"或每个业务交易的对话".

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 Unit Of Work模式和Ninject的正确使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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