2
\$\begingroup\$

I have done some research about intentions of UnitOfWork pattern. In short, what I understood is that UoW is needed for transactions. But I saw some code examples where people use UoW as factory for Repository objects as well, one example is DbContext from EF. My first thought about it doesn't it break single responsibility principle? In my current project I am using both UoW and Repository patterns. Here are my interfaces:

UnitOfWork:

public interface IUnitOfWork : IDisposable
{
    void Commit();
    void Rollback();
    IRepository<T> GetRepository<T>() where T : class;
}

Repository interface:

public interface IRepository<T> where T : class
{
    IQueryable<T> FindAll();
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    T FindById(Id id);
    void Add(T newEntity);
    void Remove(T entity);
}

My concern is GetRepository<T> method in IUnitOfWork interface. Should this method be here at all? Or should I move it somewhere else? What would you suggest?

PS I am using NHibernate as my ORM tool, but I think this should not make any difference

\$\endgroup\$
  • \$\begingroup\$ Are you using Linq-to-NHibernate? \$\endgroup\$ – Mathieu Guindon Mar 24 '14 at 15:32
  • \$\begingroup\$ I am still in architecturing state. But, yes, I am thinking about using Linq to Nhibernate \$\endgroup\$ – matsoor Mar 24 '14 at 15:39
5
\$\begingroup\$

Leaky abstractions

A specific implementation should not leak into an abstraction. By making IUnitOfWork extend IDisposable, that's what you're doing:

public interface IUnitOfWork : IDisposable

The goal of the abstraction, is to abstract implementation details away - in this case, the fact that you're using NHibernate. You had a specific implementation in mind when you created this interface, and that implementation leaked into the abstraction. What if you wanted to implement an IUnitOfWork that worked off a List<T>, for testing purposes?

Not all implementations of IUnitOfWork need to implement IDisposable - better leave that up to the implementation:

public class NHibernateUnitOfWork : IUnitOfWork, IDisposable
{
    private readonly ISession _session;

    /* implementation */

    public void Dispose()
    {
        _session.Dispose();
    }
}
public class TestUnitOfWork : IUnitOfWork
{
    /* implementation */
}

IQueryable

Every single implementation of the Repository & Unit of Work patterns I have seen, were different. Every single one.

Without seeing what your implementations and client code looks like (/how you're using these interfaces), it's very hard to tell whether you've done something wrong.

For one thing, exposing IQueryable<T> is leaking the query outside your repository, making it possible for client code to call IRepository<T>.FindAll() and then from there, add a Where clause or Join on another repository, which means the repository completely loses control of query materialization, which [unless I missed something] defeats its purpose.

By exposing a IRepository<T> GetRepository<T>() method on your IUnitOfWork, you're also making it possible for the unit of work's clients to own the materialization of the query.

Whether that's good or bad, entirely depends on your architecture; I cannot tell just from the interfaces... I can only raise a flag.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.