views:

478

answers:

1

I have a repository pattern setup using NHibernate. The base class looks like this:

public interface IUnitOfWork : IDisposable
{
    void Commit();
    void Rollback();
}

// generic NHibernate implementation of IUnitOfWork here

public class NHibernateRepositoryBase<T> : IRepository<T>
{
    private NHibernateUnitOfWork _unitOfWork;

    public NHibernateRepositoryBase(NHibernateUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    public T Get(object id)
    {
        return _unitOfWork.Session.Get<T>(id);
    }

    // ...
}

As you can see, I'm allowing the unit of work to be populated via the constructor (using StructureMap). I'm populating the repository objects on my ASP.NET web services like so:

[WebService(Namespace = "...")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class ModuleService : System.Web.Services.WebService
{
    public IUserAccountRepository UserAccountRepo { get; set; }

    public ModuleService()
    {
        // tell IoC to inject properties
        ObjectFactory.BuildUp(this);
    }

    // ...
}

As you may be able to deduce, my problem is that by way of design, I've now lost control of the lifecycle of the unit of work. Previously, I made the unit of work a context sensitive object and the repository would obtain a reference to it via something like:

public class NHibernateRepositoryBase<T> : IRepository<T>
{
    public T Get(object id)
    {
        return NHibernateUnitOfWork.GetCurrent().Session.Get<T>(id);
    }

    // ...
}

This previous design allowed me to control the life cycle of the unit of work in my code by creating the unit of work from a UnitOfWorkFactory within a using statement. I was trying to put more of the work in the hands of the IoC container, but I think I actually took a step backwards. What are your thoughts on either implementation?

+1  A: 

It is usually a good thing to let your IoC container handle as much as possible. On the web a unit of work pattern usually get initialized at the start of the request and committed at the end (rolled back if there is any exceptions). This way your repository will take a ISession in the constructor instead of the unitofwork. This way, your repository will not have to deal with committing or anything and that will be handled automatically for you.

Mattias Jakobsson
How do you handle individual transactions in that type of set up though? Let's say I need to run two separate sets of code within the same session, and each has it's own transaction. How would you recommend handling that?
Chris
The transactions is handled through the session. You don't need anything else then the session reference to use a transaction.
Mattias Jakobsson
The NHibernate session is basically a unit of work in it self. The reason to hide it behind your own unit of work interface is basically so that you can expose it in a generic way to the rest of the application (outside of your repository) and not depend on NHibernate. And that will mostly just be to initialize it at the start of the request and commit it at the end.
Mattias Jakobsson