Reputation: 15761
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
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