2011-02-17 133 views
0

我正在研究实现IRepository模式使用NHibernate和我有问题,我一直无法回答搜索网络。C#共享事务和NHibernate使用IRepository

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

我希望能够做的线沿线的东西..

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有关的多表更新和事务的事务最佳实践是什么?

在此先感谢。

回答

5

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

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

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

存储库与来自服务打开的事务获取会话:

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

根据你的环境,你需要使它更复杂一点。例如,会话可能对业务逻辑不可见,应该放到另一个接口等。

+0

嗨,谢谢你的回答,我的后续问题是,这个TransactionService是否有效地管理着一个事务池,这样如果一个事务失败了,那么池中的所有事务都会回滚?或者是否有跨多个存储库共享1个事务的方式? – David 2011-02-17 09:35:34

+0

每个线程都有一个事务。当然,其他并行事务在其他线程上进行。 – 2011-02-17 11:28:35

0

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

0

你可以做的一件事 - 这就是我现在怎么做 - 是传递应该用于存储库实例的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); 
} 

但是,看着你的榜样,我想知道wheth呃你应该有一个'PersonAddress'和'PersonAccount'的仓库。 在我看来,Person是一个'聚合根',在你的例子中由PersonAddressPersonAccount组成,应该有一个PersonRepository,它处理Person聚合根(包括PersonAddress和PersonAccount对象 - 事实上不是实体而是价值对象(就像我看到的那样))。