I am writing a WPF application that needs to access information from a database (I am currently using Entity Framework code first, so data access is via DbContext
).
My ViewModels directly instantiate my DbContext
derived class and query this to obtain the information they require. I understand that this is bad for the following reasons:
- My ViewModel now has a dependency on
DbContext
. - my viewModel is more difficult to test.
- It will be difficult to switch to a different data provider if required e.g.
ObjectContext
instead ofDbContext
.
The common solution I have seen to this problem is to define a repository to keep my ViewModels unaware of which data access technology I am using.
I have defined the following generic repository class:
public interface IRepository<T>
{
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> where);
// other data access methods could also be included.
void Add(T entity);
void Attach(T entity);
void Delete(T entity);
}
My concrete repository looks like this:
public class Repository<T> : IRepository<T> where T : class
{
private DbSet<T> _entitySet;
public Repository(DbContext context)
{
if (context == null)
throw new ArgumentNullException("context");
_entitySet = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _entitySet;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> where)
{
return _entitySet.Where(where);
}
public void Add(T entity)
{
_entitySet.Add(entity);
}
public void Attach(T entity)
{
_entitySet.Attach(entity);
}
public void Delete(T entity)
{
_entitySet.Remove(entity);
}
}
Any viewModel that requires access to the database now has a constructor parameter so that a repository can be injected. As far as I can tell this solves all of the problems listed above - my viewModels no longer depend on 'DbContext', they can be tested by using a mocked implementation of the IRepository
interface and I could switch to the ObjectContext
API by creating a different implementation of the IRepository
interface.
This is great except in some cases I may require access to other repositories that contain different entities E.G. Customers and Products. I may also sometimes need to add, update and save the changes to multiple entities in one go. I could change my viewModel constructors to accept just the entities they require but this doesn't smell right to me.
One solution is to use the following interface:
public interface IUnitOfWork : IDisposable
{
IRepository<T> RepositoryFor<T>() where T : class;
void SaveChanges();
}
The idea here is that the unit of work allows my viewModels to request entities from the data source and any changes can be saved in one go. The implication of this interface is that any entities requested belong to the same 'context'.
an example of a concrete implementation looks like this:
public class UnitOfWork : IUnitOfWork
{
private DbContext _context;
public UnitOfWork(DbContext context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
public IRepository<T> RepositoryFor<T>() where T : class
{
return new Repository<T>(_context);
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
My ViewModel constructors now have an IUnitOfWork
injected rather than a repository and the IUnitOfWork
instance allows me to request generic repositories for each entity and then save all changes to the same context using the SaveChanges()
method.
This still solves the problems listed earlier and also allows me to make changes to multiple entities within my viewModels. My next concern was over the lifetime of the IUnitOfWork
instance. My implementation is using DbContext
and my understanding is that the this type should be (generally speaking) short lived.
Consider the following scenario:
- An
IUnitOfWork
instance is passed into my ViewModel constructor. - I retrieve some entities, work with them and then save the changes to the database.
- I dispose the
IUnitOfWork
instance. - I now need to carry out another series of operations so need to create a new
IUnitOfWork
instance - My ViewModel is now dependant on my concrete application of the interface.
The alternative is to keep the IUnitOfWork
around for the lifetime of the ViewModel but this means that the underlying DbContext
will be keeping track of all changes I make.
My solution to this was to create another interface:
public interface IUnitOfWorkProvider
{
IUnitOfWork GetUnitOfWork();
}
The idea here is that a concrete instance will be injected into my ViewModels via the constructor. Whenever I need to do any data access I will just do something like this:
using (IUnitOfWork uow = provider.GetUnitOfWork())
{
// Carry out all data access here...
uow.SaveChanges();
}
What I would like to know is, is my implementation of the repository and unit of work patterns acceptable? Will this cause me any major problems?
Update
As was pointed out to me by dreza in the comments, my viewModels are retrieving their own data from the repository. I'm not sure how to pass the data into my viewModels without having a unique interface or class per viewModel to encapsulate this information.
In it's current state the repository can also (potentially) return any entity repository that is requested. e.g. in my customerViewModel I may want to work only with Customer and Product entities but there is nothing to stop me requesting other unrelated entities.