A Generic Repository and Unit of Work Implementation for Entity Framework
You may be familiar with my previous posts describing the implementation of design patterns for Entity Framework. It started with using generics for lookup tables, and followed with a generic CRUD repository. This strategy follows along with our SSW rule, Do you use the Repository Pattern for data access.
In the lead up to SSW’s recent Enterprise MVC course, I had lots of discussions with Adam Stephensen and Eric Phan about whether we could do a better job with this pattern. We’ve come up with what we think is a great solution that includes the Unit of Work pattern as well.
We felt it was really important to separate the domain models, the repositories, and the context; a separation that’s not made by Entity Framework. Doing so gave us some really important benefits. Testing is made much easier. For one, we can mock our context enabling us to test our repositories without going back to the database. We can also mock the repositories to test the code that calls it.
A quick shout-out to Adrian Clark who suggested this separation in the comments last time.
We also used Inversion of Control to inject a context into the repository. We could have had a reference to each of our repositories in our context, but inverting this relationship meant that we only needed to instantiate those repositories we were actually using. It means less overhead and a looser coupling between the context and each repository.
First, we create our IUnitOfWork and our IGenericRepository.
public interface IUnitOfWork : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
public interface IGenericRepository<TEntity>
where TEntity : class
{
IQueryable<TEntity> Select();
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity> Where(Func<TEntity, bool> predicate);
TEntity GetSingle(Func<TEntity, bool> predicate);
TEntity GetFirst(Func<TEntity, bool> predicate);
void Add(TEntity entity);
void Delete(TEntity entity);
void Attach(TEntity entity);
void Dispose(bool disposing);
void Dispose();
}
Then, we create an interface for our specific context. In this example, we have a context with a set of customers. This context is essentially a unit of work, so we’ll inherit that interface.
public interface ICustomerContext : IUnitOfWork
{
DbSet<Customer> Customers { get; set; }
}
Next, we’ll create a concrete GenericRepository instance. This is very similar to the version in my previous post, but take note of the repository that takes a context. We use this to inject our Unit of Work.
public class GenericRepository<TContext, TEntity> : IGenericRepository<TEntity>
where TContext : IUnitOfWork
where TEntity : class
{
protected TContext _context;
/// <summary>
/// Constructor that takes a context
/// </summary>
/// <param name="context">An established data context</param>
public GenericRepository(TContext context)
{
_context = context;
}
public IQueryable<TEntity> Select()
{
return _context.Set<TEntity>().AsQueryable();
}
public IEnumerable<TEntity> GetAll()
{
return _context.Set<TEntity>().AsEnumerable();
}
public IEnumerable<TEntity> Where(Func<TEntity, bool> predicate)
{
return _context.Set<TEntity>().Where(predicate);
}
public TEntity GetSingle(Func<TEntity, bool> predicate)
{
return _context.Set<TEntity>().Single(predicate);
}
public TEntity GetFirst(Func<TEntity, bool> predicate)
{
return _context.Set<TEntity>().First(predicate);
}
public void Add(TEntity entity)
{
if (entity == null)
throw new ArgumentException("Cannot add a null entity");
_context.Set<TEntity>().Add(entity);
}
public void Delete(TEntity entity)
{
if (entity == null)
throw new ArgumentException("Cannot delete a null entity");
_context.Set<TEntity>().Remove(entity);
}
public void Attach(TEntity entity)
{
if (entity == null)
throw new ArgumentException("Cannot attach a null entity");
_context.Set<TEntity>().Attach(entity);
}
#region IDisposable implementation
private bool disposedValue;
public void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
// dispose managed state here if required
}
// dispose unmanaged objects and set large fields to null
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
Next, we’ll create a concretion for our context using Entity Framework. We’ll inherit DbContext as well as implementing ICustomerContext, and we’ll create both an empty constructor and one that takes a connection string so we can connect to a specific database.
public class CustomerContext : System.Data.Entity.DbContext, ICustomerContext
{
public CustomerContext() { }
public CustomerContext(string connectionString) : base(connectionString) { }
}
And that’s all we really need to do.
When we use it, we have to make sure we refer only to our interfaces so we can replace them later if need be.
private ICustomerContext _context; private IGenericRepository<Customer> _customerRepository;
Ideally, we’d be using Dependency Injection to inject our concretions at runtime, but here’s an example of how you would do it.
_context = new CustomerContext(); _customerRepository = new GenericRepository<ICustomerContext,Customer>(_context);
From there, we can do whatever we need to do with the objects in our repository, and just call SaveChanges() on our context when we’re done. For example:
public ResetCustomerLastLoginDate(int customerId) {
var customer = _customerRepository.GetSingle(c => c.CustomerId == customerId);
customer.LastLoginDate = DateTime.Now;
_context.SaveChanges();
}
[...] Published by Damian Brady on March 7, 2012 05:24 pm under Development, Technology Update: After a bit more work and discussions with other SSW guys, we’ve put together an updated version of this implementation. Have a read here. [...]
Hi Damian,
Do you think the generic repository interface has too much responsibility? On a normal web situation is OK, but when we had ETL, we just need some repository to do write and others do read. I preferred to break the interface to ICanGetAll, ICanGetById and so on. In this way, the read and write can be separated and do not need to write ugly NotImplementedException
Hi Yin,
That’s an interesting point. If your application or domain requires that you separate read and write operations then I can definitely understand separating into read and write interfaces. Throwing NotImplementedExceptions is always bad and shows you have the wrong abstraction.
However I think a separate interface for each method is almost certainly far too granular. For example, if every method has its own interface, it would be entirely possible to implement a repository that doesn’t actually do anything. There should be some expectations on what a repository can do otherwise you end up with a meaningless abstraction. Small interfaces are good, but you can go too far.
That said, we definitely developed this repository with the assumption that this was your data and you could access it how you pleased. The repository doesn’t directly know about your domain rules, all it knows is how to read and write data from its data store.
Hi Domian,
You are right. It was the thing I tried to avoid as well. Thanks for your comment
Hey Damien,
Thanks for the shout out!
My concern with your solution is the mixing of the “ICustomerContext” and the “IUnitOfWork” interfaces. Of course within the Entity Framework the “DbContext” class takes care of being both the unit of work and the data context. However I’m not sure your interfaces should split it up like that.
When coding for the web each HTTP request is usually considered to define the unit of work. As such, I usually have the “IUnitOfWork” interface separate with only methods related to saving changes and a single instance of this is created per request via my IoC container.
Configured like this, if a particular process requires more than one repository which may, perhaps, require the use of more than one type of context you aren’t in the situation of answering the question “which Context.SaveChanges() method should I call?”
This also means that business methods, such as your “ResetCustomerLastLoginDate()” can ignore the “SaveChanges()” method & just update the context. Which could be handy if you wish to combine that method with a perevious call to, say, “SetCustomerPassword()” in a password reset scenario.
Just my nit-picky thoughts anyway.
Hello,
Thank you for your article.
Some modifications i have made to implement “include()” :
The interface :
public interface IGenericRepository
where TContext : IUnitOfWork
where TEntity : class
{
IQueryable Select();
IEnumerable GetAll();
IEnumerable Where(Func predicate);
TEntity GetSingle(Func predicate);
TEntity GetFirst(Func predicate);
void Add(TEntity entity);
void Delete(TEntity entity);
void Attach(TEntity entity);
GenericRepository Include(params Expression<Func>[] includeProperties);
void Dispose(bool disposing);
void Dispose();
}
The class :
public class GenericRepository : IGenericRepository
where TContext : IUnitOfWork
where TEntity : class
{
protected TContext _context;
public Expression<Func>[] includeProperties;
///
/// Constructor that takes a context
///
/// An established data context
public GenericRepository(TContext context)
{
_context = context;
}
public IQueryable Select()
{
IQueryable query = _context.Set();
foreach (var includeProperty in includeProperties)
{
query = (DbSet) query.Include(includeProperty);
}
return query.AsQueryable();
}
public IEnumerable GetAll()
{
IQueryable query = _context.Set();
foreach (var includeProperty in includeProperties)
{
query = (DbSet)query.Include(includeProperty);
}
return query.AsEnumerable();
}
public IEnumerable Where(Func predicate)
{
IQueryable query = _context.Set();
foreach (var includeProperty in includeProperties)
{
query = (DbSet) query.Include(includeProperty);
}
return query.Where(predicate);
}
public TEntity GetSingle(Func predicate)
{
IQueryable query = _context.Set();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query.Single(predicate);
}
public TEntity GetFirst(Func predicate)
{
IQueryable query = _context.Set();
foreach (var includeProperty in includeProperties)
{
query = (DbSet) query.Include(includeProperty);
}
return query.First(predicate);
}
public void Add(TEntity entity)
{
if (entity == null)
throw new ArgumentException(“Cannot add a null entity”);
_context.Set().Add(entity);
}
public void Delete(TEntity entity)
{
if (entity == null)
throw new ArgumentException(“Cannot delete a null entity”);
_context.Set().Remove(entity);
}
public void Attach(TEntity entity)
{
if (entity == null)
throw new ArgumentException(“Cannot attach a null entity”);
_context.Set().Attach(entity);
}
public GenericRepository Include(params Expression<Func>[] includeProperties)
{
this.includeProperties = includeProperties;
return this;
}
#region IDisposable implementation
private bool disposedValue;
public void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
// dispose managed state here if required
}
// dispose unmanaged objects and set large fields to null
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
You can’t use Func. You must use Expression<Func> for your GetSingle/GetFirst
I like the pattern, I’m a bit confused on an implementation of it. Is the suggestion to make a very thin dbcontext class, meaning one for every entity? Or is the thinking to use the standard dbcontext class geneated from the model? Or somewhere in between?
Hi Randy,
Ideally you should be able to use the same DbContext for multiple entities (if you need to update more than one thing)
Damian
I am getting an error :
your ICustomerContext has
DbSet Customers { get; set; }
but the CustomerContext does not implement the interface method Customers.
Any help here?
I use structuremap for DI, and I’m having a little trouble with getting the registrations to work out. I was wondering if you could provide any insight?
I created a github repository with the solution uploaded and a stack overflow question. The solution is in visual studio 2012.
http://stackoverflow.com/questions/15662511/problems-registering-types-with-structuremap-for-generic-repository
Not sure I understand it correctly, but you define the interface ICustomerContext with dbset but there is no implementation of it in CustomerContext, why?
Also, how would you register GenericRepository(_context) in eg Unity or any other DI?
Hi Damian,
Tried to implement/compile this, but CustomerContext do not implement ICustomerContext (DbSet) – am I missing something?
Inserted the missing line, no problem. Very nice(and clean) code – thank you for the effort.
Hi Damian,
After implementating(using Code first),- I alterd my model and wanted to use the EF migration “tool”(Package Manager Console) to update the sql database.
Recieved the message: More than one context type was found in the assembly ‘Infrastructure’.
This is correct, and I found ways to create sql scripts for each specific context (them scripts will drop tables not inside the context, because they are all in the same db). After manual modifications scripts will work.
I could choose to alter the db myself, but prefer to use EF(Update-Database) for this work.
Therefore I go back to 1 context “fit all”,- using a partial class.
To bad, but I am ready to refactor when EF is
Hi Hessner,
You should be able to provide an argument to the EF migrations command to refer to one of your contexts specifically. That way you can still use EF migrations.
Damian
Hi Christian,
The CustomerContext implements ICustomerContext, but only so you can refer to an interface instead of a concrete class (in this example).
Because it inherits from DbContext, we already have all the methods we need to get it working.
If you’re using a DI framework, you wouldn’t register the GenericRepository itself – you’d only register specific instances. For example, if you needed a repository for Customers, you’d define an ICustomerRepository, and register a CustomerRepository as its resolution. The CustomerRepository would inherit from GenericRepository.
Hi Matt,
That’s interesting, I don’t know why that’s the case. Maybe I just forgot a line? If you add it in, does it work?
Damian
Hi Damian,
it is correct that I can provide an argument to the EF migrations command.
The problem is that when I got more contexts and use the same database, then entities not in the particular context are dropped from the database.
I also found arguments for not using a custom respository with EF, and do study these arguments at the moment.
Hi Damian,
Ended up with 1 repository instance, like this:
—–
public interface IUnitOfWork : IDisposable
{
DbSet Set() where TEntity : class;
int SaveChanges();
}
—–
public interface IGenericRepository2
where TContext : IUnitOfWork
{
IQueryable Select() where TEntity : class;
IEnumerable GetAll() where TEntity : class;
IEnumerable Where(Func predicate) where TEntity : class;
TEntity GetSingle(Func predicate) where TEntity : class;
TEntity GetFirst(Func predicate) where TEntity : class;
void Add(TEntity entity) where TEntity : class;
void Delete(TEntity entity) where TEntity : class;
void Attach(TEntity entity) where TEntity : class;
void Dispose(bool disposing);
void Dispose();
}
—–
public class GenericRepository2 : IGenericRepository2
where TContext : IUnitOfWork
{
protected TContext _context;
///
/// Constructor that takes a context
///
/// An established data context
public GenericRepository2(TContext context)
{
_context = context;
}
public IQueryable Select() where TEntity : class
{
return _context.Set().AsQueryable();
}
public IEnumerable GetAll() where TEntity : class
{
return _context.Set().AsEnumerable();
}
……
—–
public class DataContext : System.Data.Entity.DbContext, IDataContext
{
public DataContext() : this(“name=MyProdEntityDatabase”) { }
public DataContext(string connectionString) : base(connectionString)
{
this.Configuration.LazyLoadingEnabled = true;
}
public DbSet Customers { get; set; }
public DbSet Reviews { get; set; }
public DbSet Logs { get; set; }
}
—–
_context = container.Resolve(new NamedParameter(“connectionString”, “name=MyNewTestEntityDatabase”));
_repository = container.Resolve<IGenericRepository2>(new NamedParameter(“context”, _context));
—–
var c = new Customer();
c.Name = “TheCustomer”;
_repository.Add(c);
c.Reviews.Add(new Review { Author = “Me”, Comments = “My comment” });
c.Reviews.Add(new Review { Author = “Me2″, Comments = “My comment2″ });
_context.SaveChanges();
—–
Thats it
Hi Damian,
I have a few questions for you:
-Do I have to make a Context interface and implementation per Entity?
-I instantiate a generic repository per entity type I’m using?
-How do you save Objects that have several nested objects in one go? Or is this not possible with your approach and do i have to loop manually over each item and inspect it’s state and then saving it to the appropriate Repository?
-Could you go a bit more in detail how you’d use this pattern. For example : Saving an object with a collection of objects underneath
Hi,
sorry I wanted to edit my questions but that isn’t possible it seems.
Wouldn’t it be best to have the repository have IDisposable as an interface so it can be used insidie a using statement.
Also for those who are not using DI. What’s the benefit of creating a repository and a context if these two always have the same relationship.
It makes for some lengthy code having to dispose all these objects nicely.
Hi Kristof,
> -Do I have to make a Context interface and implementation per Entity?
You should only need one context – I only have a single entity type in mine, but you’ll usually have all of the entities you care about in there.
> -I instantiate a generic repository per entity type I’m using?
In general, yes.
If those entities have relationships however, you can include those “sub-entities” in the same work you’re doing.
> -How do you save Objects that have several nested objects in one go? Or is this not possible with your approach and do i have to loop manually over each item and inspect it’s state and then saving it to the appropriate Repository?
To follow on from the last answer, let’s say you want to change a customer’s name as well as adding an address.
I haven’t tested this code, but you could do something like:
_context = new CustomerContext();(_context);
_customerRepository = new GenericRepository
var customer = _customerRepository.GetSingle(c => c.CustomerId == customerId);
customer.Name = “John”;
customer.Addresses.Add(newAddress);
_context.SaveChanges();
Making the repository IDisposable isn’t a bad idea, however it’s really the context you want to dispose of when you’re finished I think.
The purpose of separating the repository and context is that they have two separate roles to play. The repository is what you call to get and save data related to a specific entity – but it doesn’t actually have any implementation details (i.e. whether it’s saved to the database or to memory or something else). The context has the implementation details.
This means you can swap out the context if you need to – which is particularly useful for testing. If you’re repository and context were strongly coupled, you couldn’t write tests against your repository without writing to the database.
This strategy uses dependency injection so you can give the repository a context. If you’re writing tests, you give it a context that does nothing. In the main application, you give it a context that retrieves and saves to the database.
Hi Damian,
Thanks for your answers.
I’m now using one context (which contains all my entities) for all repo’s and both have IDisposable and everything is working great.
Thank you for this nice implementation of the Repo/UoW pattern.
Hi,
your implementation of unit of work pattern requires concretion or at least using the interfaces int the client part of the application. Do you have any idea on how to implement this entirely in the core layer, using abstractions where everything happens in core services?
I’m working on this solution currently. Here is what I’ve come up with so far:
I create service (e.g. CustomerService) in the core layer, which depends on IUnitOfWorkFactory, creates new a instance of the UnitOfWork whenever needed. This allows me to do something like this:
private IUnitOfWorkFactory _uow;
public void DoSomethingWithCustomer(int id){
_uow.New(work => {
var customer = work.Customers.Find(id);
work…. // Do something with the customer
work…. // Do something else
work.Commit();
})
}
What this gives you is that you have the usable unit of work implementation in the core part of the application (without touching anything else) and then you just have to use IOC container.
The problem with this solution is that it’s not easily unit testable. So, I’m working on this. Any ideas would be appreciate
The easiest thing to do would be create an ICustomerService that the CustomerService class implements. That way, you can test anything that uses your CustomerService class by mocking it out.
If you’re talking about testing the methods themselves, you should look at constructor injection to inject an IUnitOfWorkFactory as well as any other dependencies you need.
Hi Damian,
Do you have any tips on what would be the best way to implement “include” functionality in the repository.
For the moment this functionality is missing and you have to create/load your object tree “manually”.
kind regards,
Kristof