【问题标题】:NHibernate transactions within UnitOfWork SessionsUnitOfWork 会话中的 NHibernate 事务
【发布时间】:2012-08-19 11:00:15
【问题描述】:

我正在处理的项目为整个会话定义了一个 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,并且都获得了由 StructureMap 提供的 UnitOfWork。

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

public RepoB(IUnitOfWork unitOfWork, ITssPrincipal principal)
{
}

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

【问题讨论】:

  • 您的会话工厂在您执行 foreach 循环的课程中可用吗?除了使用 UnitOfWork.CurrentSession 之外,您还可以使用工厂在循环中创建一个新会话,然后针对该会话调用 BeginTransaction() 吗?
  • 我添加了更多代码来显示主会话的设置方式。有没有办法在我的循环中以某种方式使用 fluentConfig.BuildSessionFactory()?
  • Randy 的回答看起来不错,但要添加到您的最后一条评论中:永远记住会话很便宜,但会话 factories 很昂贵。因此,请始终避免创建新工厂(并且通过使用依赖注入,您永远不必这样做)。
  • 我认为 DI 是我现在最大的问题。由于 StructureMap 是通过 UnitOfWork 会话为我的所有 repo 类注入的,因此我无法让它们使用新创建的会话(因为此时它们已经被实例化了)
  • 我已经用一个例子更新了我的 OP

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


【解决方案1】:

看起来您的 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 () 方法。

【讨论】:

  • 谢谢,我认为这让我接近了我需要的东西,但我仍然有一个问题,被调用的存储库函数仍然引用了原始的 UnitOfWork 会话。有没有办法在上述上下文中使用新实例化的会话进行任何 repo 调用?
  • @getit 如果您有更多依赖项需要这个新创建的 NHibernate 会话,那么听起来您想要的是集合中每个项目的新 UnitOfWork。到那时,您的应用程序的架构就真正开始发挥作用,以决定这是否可能。一些 UnitOfWork 实现可以支持嵌套的 UnitOfWorks。如果您的应用程序不支持嵌套的 UnitOfWorks,那么您需要发挥创造力。一种选择可能是关闭/提交初始 UnitOfWork 并手动启动并提交集合中每个项目的新 UnitOfWork。
猜你喜欢
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多