I plan to develop a web application using ASP.NET MVC with Entity Framework 6 (Code First / POCO). I also want to use generic Repository and Unit of Work Pattern in my appli
I would suggest you to create UnitOfWork pattern with a Constructor parameter to accept DbContext -
public class UnitOfWork : IUnitOfWork
{
private readonly IDbContext _context;
private bool _disposed;
private Hashtable _repositories;
public UnitOfWork(IDbContext context)
{
_context = context;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Save()
{
_context.SaveChanges();
}
public virtual void Dispose(bool disposing)
{
if (!_disposed)
if (disposing)
_context.Dispose();
_disposed = true;
}
public IRepository<TEntity> Repository<TEntity>() where TEntity : class
{
if (_repositories == null)
_repositories = new Hashtable();
var type = typeof(TEntity).Name;
if (_repositories.ContainsKey(type)) return (IRepository<TEntity>) _repositories[type];
var repositoryType = typeof (Repository<>);
var repositoryInstance =
Activator.CreateInstance(repositoryType
.MakeGenericType(typeof (TEntity)), _context);
_repositories.Add(type, repositoryInstance);
return (IRepository<TEntity>) _repositories[type];
}
}
where IDbContext is -
public interface IDbContext
{
IDbSet<T> Set<T>() where T : class;
int SaveChanges();
void Dispose();
}
And the repository implementation would be -
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal IDbContext Context;
internal IDbSet<TEntity> DbSet;
public Repository(IDbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public virtual TEntity FindById(object id)
{
return DbSet.Find(id);
}
public virtual void Update(TEntity entity)
{
DbSet.Attach(entity);
}
public virtual void Delete(object id)
{
var entity = DbSet.Find(id);
var objectState = entity as IObjectState;
if (objectState != null)
objectState.State = ObjectState.Deleted;
Delete(entity);
}
public virtual void Delete(TEntity entity)
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
public virtual void Insert(TEntity entity)
{
DbSet.Attach(entity);
}
public virtual List<TEntity> GetAll()
{
return DbSet.ToList();
}
}
With this approach you can create a UnitOfWork for individual DBContext and you have specific logic to commit or rollback in UnitOfWork.
I would implement UnitOfWork
as an ActionAttribute
where OnActionExecuting
I open transaction, and OnActionExecuted
I commit transaction if everything is ok, if there is exception in ActionContext
, transaction should be rolled back.
The tricky thing is that you have 2 DbContexts. I think, you should have lazy creation of dbContexts. Introduce a kind of flag variable and set it to True
in UnitOfWork.OnActionExecuting
. Then, when you first time touch dbContext, you should check if you are dealing with UnitOfWork
, and if yes, you should open transaction for this particular dbContext. All the open transactions could be put into a List which is accessible from UnitOfWork.ActionExecuted
. Finally, check if there are any exceptions in ActionContext: yes - Rollback
, no - Commit
.