2011-02-17 70 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對象 - 事實上不是實體而是價值對象(就像我看到的那樣))。