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

asked Mar 24, 2014 at 15:23
\$\endgroup\$
2
  • \$\begingroup\$ Are you using Linq-to-NHibernate? \$\endgroup\$ Commented Mar 24, 2014 at 15:32
  • \$\begingroup\$ I am still in architecturing state. But, yes, I am thinking about using Linq to Nhibernate \$\endgroup\$ Commented Mar 24, 2014 at 15:39

1 Answer 1

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.

answered Mar 24, 2014 at 16:16
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.