Introduction
I have been involved in many projects during my time as a software developer and have seen different ways of accessing databases using different patterns, sometimes too much code when the same things could be done with much less code.
One thing we developers should be aware of when using EntityFramework is that DB Context is "HOLY" and should be handled with care. Create one just before you need it and Dispose it right after you are done with it.
DO NOT share it with different threads or keeping it alive during the whole time your application instance life-cycle, you may end up getting memory leaks.
Below, you will find implementation for UnitOfWork
pattern using EntityFramework
and DContext
.
Background
If you are using Service/Repository pattern and want to want to build a thin Repository using unit of work pattern, this should get you on the right track.
I have seen different ways exposing data from the repository, sometimes returning IQueryable
directly from repository, I don't recommend this way for 3 reasons:
- It is harder to mock when you need to write tests.
- Every time you read data from database, you need to convert it to CLR type using
ToList()
method. - Composing Query can affect performance (Read this link from MIcrosoft)
Using the Code
This time, we are going to build a simple repository. Many think that everything that handles data has to be done through repository (I have seen a project that accesses a web service using repository), I think that Repository should only handle queries against database.
Below are interfaces and classes for setting up Unit of work pattern using EntityFramework
.
This interface defines the Repository
:
public interface IGenericRepository
{
Task<IEnumerable<T>> FindAsync<T>(Expression<Func<T, bool>> expression) where T : class;
Task<T> SingleOrDefaultAsync<T>(Expression<Func<T, bool>> expression) where T : class;
void Add<T>(T entity) where T : class;
void Update<T>(T entity) where T : class;
void Delete<T>(T entity) where T : class;
}
This class implements IGenericRepository
:
public class GenericRepository : IGenericRepository
{
private readonly IDatabaseContext _dbContext;
public GenericRepository(IDatabaseContext dbContext)
{
_dbContext = dbContext;
}
public async Task<IEnumerable<T>> FindAsync<T>
(Expression<Func<T, bool>> expression) where T : class
{
return await _dbContext.Set<T>().Where(expression).ToListAsync();
}
public async Task<T> SingleOrDefaultAsync<T>
(Expression<Func<T, bool>> expression) where T : class
{
return await _dbContext.Set<T>().SingleOrDefaultAsync(expression);
}
public void Add<T>(T entity) where T : class
{
_dbContext.Set<T>().Add(entity);
}
public void Update<T>(T entity) where T : class
{
_dbContext.Entry(entity).State = EntityState.Modified;
}
public void Delete<T>(T entity) where T : class
{
_dbContext.Set<T>().Remove(entity);
}
}
Unit of Work
Using unit of work pattern will help you make several changes to your database model and commit all at once, doing so will help you make sure that all changes have been saved properly or in other case, you can rollback.
Defining unit of work interface:
public interface IUnitOfWork : IDisposable
{
IGenericRepository Repository();
Task CommitAsync();
}
Class that implements IUnitOfWork
, you can see that I use one DB Context per UnitOfWork
instance.
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabaseContext _databaseContext;
public UnitOfWork(IDatabaseContext databaseContext)
{
_databaseContext = databaseContext;
}
public IGenericRepository Repository()
{
return new GenericRepository(_databaseContext);
}
public void Dispose()
{
_databaseContext.Dispose();
}
public Task CommitAsync()
{
return _databaseContext.SaveChangesAsync();
}
}
For creating a new DB Context every time we need one, I recommend using a Factory pattern.
public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
}
Implementing IUnitOfWorkFactory
:
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
public IUnitOfWork Create()
{
return new UnitOfWork(new DatabaseContext());
}
}
Recommended, define interface for exposing properties from DB Context:
public interface IDatabaseContext : IDisposable
{
DbEntityEntry Entry(object entity);
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(System.Type entityType);
int SaveChanges();
Task<int> SaveChangesAsync();
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
public class DatabaseContext : DbContext, IDatabaseContext
{
public DatabaseContext() : base("OrganizationDb")
{
Database.SetInitializer<DatabaseContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
Now, we are able to access database using our DB models for reading data.
Below, you'll find a service as example.
public interface IPersonService
{
Task<List<PersonDto>> GetPersonsAsync(string term);
}
public class PersonService : IPersonService
{
private readonly IUnitOfWorkFactory _unitOfWorkFactory;
public PersonService(IUnitOfWorkFactory unitOfWorkFactory)
{
_unitOfWorkFactory = unitOfWorkFactory;
}
public async Task<List<PersonDto>> GetPersonsAsync(string term)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
var persons = await unitOfWork.Repository().FindAsync<Person>
(x => x.Name.Contains(term));
return persons.Select(person => new PersonDto(person.Name)).ToList();
}
}
}
This is just a simple example, you can always extend repository implementation, or configure your IoC to call Dispose
after every request. Sky is the limit :)
Happy coding!