C# Shared Transactions and NHibernate using IRepository

佐手、 提交于 2019-12-08 13:44:45

问题


I'm looking into implementing the IRepository pattern using NHibernate and I have question that I've not been able to answer searching the net.

Assume I have 3 Repositories, PersonRepository, PersonAddressRepository and PersonAccountRepository. Now assume that business logic dictates that there be an "Deactivate Person" process that calls PersonRepository.Deactivate(), PersonAddressRepository.Deactivate() and PersonAccountRepository.Deactivate().

I want to be able to do something along the lines of..

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

So that if any of those updates fail that the entire process rolls back within the database. Now at the moment my understanding of NHibernate is you can only create a Session per object so..

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);
}

Is this correct or am I mistaken? What are the best practices for Transactions regarding multi table updates and Transactions with regards to NHibernate.

Thanks in advance.


回答1:


You should not create transactions in the repositories or somewhere else "bellow". Transactions are defined by the application logic. This is one of the most common mistakes I see in transaction handling.

I wrote a transaction service which manages the transactions:

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

The repository is getting the session with an open transaction from the service:

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

Depending on your environment, you need to make it a bit more complicated. For instance, the session may not be visible to the business logic and should to be put onto another interface etc.




回答2:


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




回答3:


One thing you can do -this is how I do it right now- is pass the ISession instance that should be used to your repository instances.

What I will do, in the future, is this:

  • I have a UnitOfWork class, which is quite generic and is a wrapper around NHibernate's ISession object. This UnitOfWork class contains no 'application' or domain specific methods

  • In a project which uses NHibernate (and my UnitOfWork wrapper), I'll create a set of extension methods on the UnitOfWork class, that look like this:

    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);
        }
    }
    

Then, this would allow me to do this, for instance:

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

But, looking at your example, I'm wondering whether you should have a repository for 'PersonAddress' and 'PersonAccount'. In my humble opinion, Person is an 'aggregate root' which consists of a PersonAddress and a PersonAccount in your example, and there should be a PersonRepository which handles the Person aggregate root (including the PersonAddress and PersonAccount objects - which are, in fact not entities but value objects (as I see it)).



来源:https://stackoverflow.com/questions/5026994/c-sharp-shared-transactions-and-nhibernate-using-irepository

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!