UnitOfWork Sessions中的NHibernate事务

时间:2012-08-23 21:02:38

标签: c# asp.net-mvc nhibernate transactions unit-of-work

我正在开发的项目有一个为整个会话定义的UnitOfWork(似乎是MVC + NHibernate站点的标准做法)

我需要做的是,能够循环遍历一组项目并在他们自己的“本地”交易中一个接一个地完成它们。

类似的东西:

foreach(var item in CollectionOfItems)
 {
      using (ITransaction transaction = UnitOfWork.CurrentSession.BeginTransaction())
      {
         //do work on item. rollback on failure, 
         //but it should not affect the other items
      }
 }

但这不起作用,因为BeginTransaction行使用相同的“外部”会话。 如何获得一个自包含的“本地”会话来对一小段代码执行事务?我认为会话正在以下代码中注入工作单元。我不确切知道如何:

UnitOfWOrk类具有以下构造函数

    private readonly ISessionFactory _sessionFactory;
    private readonly ITransaction _transaction;

    public UnitOfWork(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
        CurrentSession = _sessionFactory.OpenSession();
        _transaction = CurrentSession.BeginTransaction();
    }

通过以下方式注册:

For<IUnitOfWork>().LifecycleIs(new HybridLifecycle())
            .Use<UnitOfWork>();

因此,只要控制器返回响应,会话就会被刷新。这是我感到困惑的地方。我并不总是希望一切都是全有或全无。

编辑:

以下是NHibernate注册过程的所有代码

    public NHibernateRegistry()
    {
        FluentConfiguration fluentConfig = Fluently.Configure()
            .Database(
                MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString(x => x.FromConnectionStringWithKey("conn")))
            .ProxyFactoryFactory(typeof (ProxyFactoryFactory).AssemblyQualifiedName)
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>());


        Configuration configuration = fluentConfig.BuildConfiguration();

        ConfigureNhibernateValidator(configuration);

        ISessionFactory sessionFactory = fluentConfig.BuildSessionFactory();

        For<Configuration>().LifecycleIs(new HybridLifecycle()).Singleton().Use(configuration);

        For<ISessionFactory>().LifecycleIs(new HybridLifecycle()).Singleton().Use(sessionFactory);

        For<ISession>().LifecycleIs(new HybridLifecycle())
            .Use(x => x.GetInstance<ISessionFactory>().OpenSession());

        For<IUnitOfWork>().LifecycleIs(new HybridLifecycle())
            .Use<UnitOfWork>();

        For<ITssPrincipal>().HybridHttpOrThreadLocalScoped().Use(container => BuildUserInstanceFromThreadCurrentPrincipal());

        Scan(x =>
        {
            x.TheCallingAssembly();
            x.WithDefaultConventions();
        });
    }

编辑:DI问题的例子 在下面的例子中,你看到RepoA与RepoB是DI'd,并且都得到了StructureMap提供的UnitOfWork。

public RepoA(IUnitOfWork unitOfWork, ITssPrincipal principal,
     IRepoB repoB)
{
}

public RepoB(IUnitOfWork unitOfWork, ITssPrincipal principal)
{
}

即使我在RepoA中的函数中创建了一个新会话,repoB仍将使用原始的UnitOfWork Session

1 个答案:

答案 0 :(得分:3)

看起来你的MVC网站正在使用StructureMap作为它的依赖注入容器,这使得你很容易做你想做的事。

您有几个选项,但最简单的方法是从StructureMap请求一个新的ISession实例。这将返回一个新的,不同于UnitOfWork使用的ISession。

以下是一个例子:

var session = StructureMap.ObjectFactory.GetInstance<ISession>();

using ( var tx = session.BeginTransaction() )
{
    try
    {
        // Do your work here

        tx.Commit();
    }
    catch ( Exception )
    {
        tx.Rollback();

        throw;
    }
}

因为您正在使用DI容器,所以您还可以利用StructureMap的依赖注入,并将新的ISession注入到控制器/类/存储库等的构造函数中,这样您就不必调用StructureMap的ObjectFactory.GetInstance&lt ;&gt;()方法。