C#使用IRepository的共享交易和NHibernate

C#使用IRepository的共享交易和NHibernate,c#,nhibernate,transactions,irepository,C#,Nhibernate,Transactions,Irepository,我正在研究使用NHibernate实现IRepository模式,我有一个问题,我无法回答搜索网络的问题 假设我有3个存储库,PersonRepository、PersonalAddressRepository和PersonalCountRepository。现在假设业务逻辑规定有一个“Deactivate Person”流程,该流程调用PersonRepository.Deactivate()、PersonAddressRepository.Deactivate()和PersonacconRe

我正在研究使用NHibernate实现IRepository模式,我有一个问题,我无法回答搜索网络的问题

假设我有3个存储库,PersonRepository、PersonalAddressRepository和PersonalCountRepository。现在假设业务逻辑规定有一个“Deactivate Person”流程,该流程调用PersonRepository.Deactivate()、PersonAddressRepository.Deactivate()和PersonacconRepository.Deactivate()

我希望能够按照……的思路做些事情

using (ITransaction transaction = session.BeginTransaction()) { 
    session.Update(Person);
    session.Update(PersonAddress);
    session.Update(PersonAccount);
}
因此,如果这些更新中的任何一个失败,整个过程将回滚到数据库中。现在我对NHibernate的理解是,你只能为每个对象创建一个会话,所以

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的事务的最佳实践是什么


提前感谢。

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

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

using (TransactionService.CreateTransactionScope())
{
  repositoryA.DoX();
  repositoryB.DoY();
  TransactionService.Commit();
}
存储库正在从服务获取具有打开事务的会话:

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

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

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

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

using (TransactionService.CreateTransactionScope())
{
  repositoryA.DoX();
  repositoryB.DoY();
  TransactionService.Commit();
}
存储库正在从服务获取具有打开事务的会话:

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

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

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

我以为NHibernate理解System.Transactions.TransactionScope类。您为什么不使用它呢?

您可以做的一件事——我现在就是这样做的——就是将应用于存储库实例的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);
}
但是,看看你的例子,我想知道你是否应该有一个“PersonalAddress”和“PersonalAccount”的存储库。
依我拙见,
Person
是一个“聚合根”,在您的示例中,它由
PersonAddress
PersonAccount
组成,并且应该有一个
PersonRepository
来处理Person聚合根(包括PersonalAddress和PersonalAccount对象——事实上,它们不是实体,而是值对象(在我看来))。

您可以做的一件事——我现在就是这样做的——就是将应用于存储库实例的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);
}
但是,看看你的例子,我想知道你是否应该有一个“PersonalAddress”和“PersonalAccount”的存储库。
依我拙见,
Person
是一个“聚合根”,在您的示例中,它由
PersonAddress
PersonAccount
组成,并且应该有一个
PersonRepository
来处理Person聚合根(包括PersonalAddress和PersonalAccount对象——实际上它们不是实体,而是值对象(在我看来)).

您好,谢谢您的回答,我的后续问题是,此TransactionService是否有效地管理了一个事务池,以便在一个事务池失败时,池中的所有事务都将回滚?或者是否有一种方法可以跨多个存储库共享一个事务?每个线程有一个事务。当然,其他并行事务c在其他线程上。你好,谢谢你的回答,我的后续问题是,这个事务服务实际上是管理一个事务池,这样如果一个失败,那么池中的所有事务都被回滚了?或者有一种方法可以在多个存储库中共享1个事务吗?每个线程都有一个事务。当然,其他的PAR。所有事务在其他线程上进行。