0

我正在研究使用 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 的多表更新和事务的最佳实践是什么。

提前致谢。

4

3 回答 3

5

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

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

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

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

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

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

于 2011-02-17T09:30:08.720 回答
0

I thought NHibernate understands the System.Transactions.TransactionScope class. Why wouldn't you use that?

于 2011-02-17T16:27:08.563 回答
0

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

未来我要做的是:

  • 我有一个UnitOfWork非常通用的类,它是 NHibernateISession对象的包装器。此 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是一个“聚合根”,在您的示例中由 aPersonAddress和 a组成PersonAccount,并且应该有一个PersonRepository处理 Person 聚合根(包括 PersonAddress 和 PersonAccount 对象 - 实际上不是实体而是值对象(照我看来))。

于 2011-02-17T16:33:34.590 回答