Sam
Sam

Reputation: 15761

UnitOfWork - Repository - Service Pattern Advice

So usually when implementing this pattern I have the Service take the Repository<Type> and then have the repository take the UnitOfWork.

I was playing around with hanging a method off the UnitOfWork that gets the Repository<Type> like so:

public class UnitOfWork : IUnitOfWork
{
    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : Core.Domain.Model.EntityBase<TEntity>
    {
        return new Repository<TEntity>(this);
    }
}

Then the Service would take the UnitOfWork and could resolve the repositories needed from that.

What do you think? Do you see any flaws with this?

Upvotes: 1

Views: 530

Answers (1)

Benjamin Gale
Benjamin Gale

Reputation: 13177

I use a similar approach in my ASP.NET MVC program and so far it is working very well.

My IUnitOfWork interface looks like this:

public interface IUnitOfWork
{
    IRepository<TEntity> GetRepositoryFor<TEntity>() where TEntity : class;
    void SaveChanges();
}

and the associated IRepository interface looks like this:

public interface IRepository<TEntity> : IQueryable<TEntity> where TEntity : class
{
    TEntity Find(params object[] keyValues);

    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

And then pass it to my service like so:

public abstract class BaseService
{
    public BaseService(IUnitOfWork unitOfWork)
    {
        // etc...
    }
}

You are right that this makes it easy for the service to resolve it's repositories without having to pass them into the constructor individually which is useful in cases where you might work with multiple repositories in a single service (E.G. Purchase orders and products).

One benefit of using ORM agnostic interfaces like this is that it means you can switch ORMs easily. I'll be honest, the chances of me changing from Entity Framework to another ORM is slim, but the fact is that I could if the need arises. As a bonus my services are much easier to test and I also find this makes my service class cleaner as it is now totally unaware of the ORM in use and is working entirely against the two interface above.

In regards to the comments about a generic repository interface, my advice is to be pragmatic and do what works best for you and your application. There is a number of questions on Stackoverflow on this very topic and the answers to them vary wildly about which is the best way to go (E.G. exposing IQueryable vs IEnumerable, Generic vs non-generic).

I toyed with not having a generic repository as you may already have noticed that my IRepository interface looks like IDbSet; The reason I went for this method is it allows my implementation to handle all of the Entity Framework entity state management stuff that you do with the DbContext E.G.

public void Delete(TEntity entity)
{
    if (Context.Entry(entity).State == EntityState.Detached)
    {
        EntitySet.Attach(entity);
    }
    EntitySet.Remove(entity);
}

If I used IDbSet I would need to perform this in my service layer, which would then require a dependency on DbContext which seemed a much more leaky abstraction than my generic repository.

Upvotes: 2

Related Questions