【问题标题】:C# Shared Transactions and NHibernate using IRepositoryC# 共享事务和 NHibernate 使用 IRepository
【发布时间】:2011-02-17 09:16:54
【问题描述】:

我正在研究使用 NHibernate 实现 IRepository 模式,但我有一些问题,我无法在网上找到答案。

假设我有 3 个存储库,PersonRepository、PersonAddressRepository 和 PersonAccountRepository。现在假设业务逻辑规定存在调用 PersonRepository.Deactivate()、PersonAddressRepository.Deactivate() 和 PersonAccountRepository.Deactivate() 的“停用人员”流程。

我希望能够做一些事情......

using (ITransaction transaction = session.BeginTransaction()) { 
    session.Update(Person);
    session.Update(PersonAddress);
    session.Update(PersonAccount);
}

因此,如果其中任何更新失败,整个过程都会在数据库中回滚。现在我对 NHibernate 的理解是你只能为每个对象创建一个 Session 所以..

var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Person).Assembly);
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession()) {
    using (ITransaction transaction = session.BeginTransaction()) {
    session.Save(Person);
}

这是正确的还是我弄错了?关于多表更新的事务和关于 NHibernate 的事务的最佳实践是什么。

提前致谢。

【问题讨论】:

    标签: c# nhibernate transactions irepository


    【解决方案1】:

    您不应在存储库或“下面”的其他地方创建事务。事务由应用程序逻辑定义。这是我在事务处理中看到的最常见的错误之一。

    我写了一个事务服务来管理事务:

    using (TransactionService.CreateTransactionScope())
    {
      repositoryA.DoX();
      repositoryB.DoY();
      TransactionService.Commit();
    }
    

    存储库正在从服务获取带有开放事务的会话:

    TransactionService.Session.CreateQuery("...");
    

    根据您的环境,您需要使其更复杂一些。例如,会话可能对业务逻辑不可见,应该放在另一个接口上等。

    【讨论】:

    • 您好,谢谢您的回答,我的后续问题是,这个 TransactionService 是否实际上管理了一个事务池,以便如果一个失败,那么池中的所有事务都会回滚?或者有没有办法在多个存储库之间共享 1 个事务?
    • 每个线程都有一个事务。当然,其他并行事务在其他线程上进行。
    【解决方案2】:

    我认为 NHibernate 理解 System.Transactions.TransactionScope 类。你为什么不使用它?

    【讨论】:

      【解决方案3】:

      您可以做的一件事——这就是我现在的做法——将应该用于存储库实例的 ISession 实例传递给您的存储库实例。

      我以后要做的,是这样的:

      • 我有一个 UnitOfWork 类,它非常通用,是 NHibernate 的 ISession 对象的包装器。此 UnitOfWork 类不包含“应用程序”或特定领域的方法

      • 在一个使用 NHibernate(和我的 UnitOfWork 包装器)的项目中,我将在 UnitOfWork 类上创建一组扩展方法,如下所示:

        public static class UnitOfWorkExtension`
        {
            public static IPersonRepository GetPersonRepository( this UnitOfWork uow)
            {
                 return new PersonRepository(uow);
            }
        
            public static IAccountRepository GetAccountRepository( this UnitofWork uow )
            {
                 return new AccountRepository(uow);
            }
        }
        

      那么,这将允许我这样做,例如:

      using( var uow = unitOfWorkFactory.CreateUnitOfWork() )
      {
           var person = uow.GetPersonRepository().GetPerson (1);
           var accounts = uow.GetAccountRepository().GetAccountsForPerson(person);
      }
      

      但是,看看你的例子,我想知道你是否应该有一个“PersonAddress”和“PersonAccount”的存储库。 在我看来,Person 是一个“聚合根”,在您的示例中由 PersonAddressPersonAccount 组成,并且应该有一个 PersonRepository 来处理 Person 聚合根(包括 PersonAddress 和 PersonAccount对象 - 实际上不是实体,而是值对象(如我所见))。

      【讨论】:

        猜你喜欢
        • 2020-02-14
        • 1970-01-01
        • 2010-09-08
        • 2010-12-09
        • 1970-01-01
        • 1970-01-01
        • 2011-10-11
        • 1970-01-01
        • 2010-11-05
        相关资源
        最近更新 更多