A generic repository
public interface IGenericRepository<TEntity> where TEntity : class { IEnumerable<TEntity> GetAll(); void Add(TEntity entity); // Any other CRUD methods ... void Dispose(); }
public class GenericRepository<TContext, TEntity> : IGenericRepository<TEntity> where TContext : IUnitOfWork where TEntity : class { public IEnumerable<TEntity> GetAll() { return _context.Set().AsEnumerable(); } public void Add(TEntity entity) { if (entity == null) throw new ArgumentException("Cannot add a null entity"); _context.Set<TEntity>().Add(entity); } // Other implementations }
A DbContext implements Unit of Work interface:
public interface IUnitOfWork : IDisposable { DbSet<TEntity> Set<TEntity>() where TEntity : class; int SaveChanges(); }
public interface ISampleContext : IUnitOfWork { DbSet- Items { get; set; } // And all the other DbSets }
public class SampleContext : System.Data.Entity.DbContext, ISampleContext { public CustomerContext() { } public CustomerContext(string connectionString) : base(connectionString) { } }
People claim this pattern gives us three major benefits
- Separate the domain models from persistence concern
- Easy for dependency injection and unit testing
- Can be easier if it needs to swap to another ORM framework or database
Secondly for dependency injection and unit testing. Well, if I use ORM directly there is no need to inject anything here. For the UoW on a typical OLTP MVC project I simply use Ayede's awesome implementation on the infrastructure level. EntityFrameWork 6 makes it easy to mock the DbContext so unit testing is not a problem as well. And using integration test with in-memory database such as SqLite and RavenDB is even better.
For the third benefit, can you tell me when was your last time and why you needed to change ORM framework or database in a deployed commercial project?
I used to be a fan (with pains) of repository + UoW pattern, until I saw some good thoughts and different ways. Most of the implementations I saw are just a wrapper of the ORM framework without adding any true value, not to mention those powerful and flexible features provided by those ORMs hidden by this layer of abstraction. The mutual ORM frameworks like EF, NHibernate, RavenDB Client are already a repository + UoW, why do we need to implement our own which is only an wrapper and an unnecessary abstraction on top of it, which are implemented by awesome people and tested with time?
Do not implement the repository + UoW pattern just for the sack of implementing it, especially when there are already great ORMs, unless there is a business scenario that justifies your own implementation. A good ORM framework is already Repository + Unit of Work. Work with it, not against it.