Best Practice of Repository and Unit of Work Pattern with Multiple DbContext

后端 未结 2 1619
北海茫月
北海茫月 2020-12-23 18:31

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

相关标签:
2条回答
  • 2020-12-23 18:39

    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.

    0 讨论(0)
  • 2020-12-23 18:54

    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.

    0 讨论(0)
提交回复
热议问题