tags:

views:

185

answers:

2

What is a good practice on work with (nHibernate) ITransactions between several repositories?

First created a BeginTransaction() on the generic interface, but i then come to think about how will this work between the repositories? i mean if a delete things from on repository and then other things from another repository, but want's to wrap the whole operation in a transaction.

although all the reposistories share the same ISession (handled by the DI framework) so i guess could get a ITransaction from any of the repositories and then commit it, and it will work for all the other repositories as well.

+2  A: 

By not making the repository responsible for the transaction management. Do not inject ISession directly in the repository, but use a unit of work that holds the session and starts and commits the transaction.

INHibernateUnitOfWork
{
   ISession CurrentSession { get; }
   void Start(); // begins the transaction
   void Commit();
   void RollBack();
}
Paco
Agreed (although don't see the point of that interface). Usually this happens when you want the IRepository to be ORM agnostic so you put the session in the constructor, but that doesn't jive with UoW. So either you build some abstract UoW to use in your abstract repositories, or you save yourself some time and just code to ISession which is a great UoW done for you.
eyston
yes, i just found a pretty good blog post on this pattern here: http://elegantcode.com/2009/03/25/fubumvc-from-scratch-part-4-persistence/
Carl Hörberg
@eyston: A benifit of the interface is that it's usable in other dataaccess secenarios than repository too. In more complex apps, just the repository pattern might not be enough to fit in with any type of dataaccess. This type of unit of work wont make your repository ORM independent, it makes it transaction independent only.@Carl: Good blog post, the unit of work implementation I use looks almost like that.
Paco
so lets say i'm working in a mvc controller, should inject both the repository and the unitofwork object to that controller? where the same unitofwork object already is injected into the repository? or should i only inject the unitofwork object into the controller and then instantiate the repository myself and manually inject the unitofwork object?
Carl Hörberg
The following approach works for 99% of the cases in a typical web application. Other approaches like injecting UoW in the controller or using a UoW spanning multiple requests might be needed sometimes.1. Inject the unit of work in the repository2. Use "per request scope" in the IoC Container for the unit of work, or add it to the httpcontext.items on the beginning en the end of the request3. Start the unit of work on the begin of the request and commit it on the end of the request.
Paco
A: 

I could instead of making the whole class generic, just make each function generic, like this:

public interface IRepository
{
    T Get<T>(int id);
    T SingleOrDefault<T>(Func<T, bool> query);
    IQueryable<T> Where<T>(Expression<Func<T, bool>> query);
    IQueryable<T> All<T>();
    void Save<T>(T entity);
    void Delete<T>(T entity);
    ITransaction BeginTransaction();
}

but then the interface is more or less depended on nHibernate anyway, so maybe it's worth implementering the Unit of Work pattern after all.

Carl Hörberg
You can do both, or is that what you mean?
Paco