【问题标题】:Best Practice of Repository and Unit of Work Pattern with Multiple DbContext具有多个 DbContext 的存储库和工作单元模式的最佳实践
【发布时间】:2014-09-28 07:03:16
【问题描述】:

我计划使用 ASP.NET MVC 和 Entity Framework 6 (Code First / POCO) 开发一个 Web 应用程序。我还想在我的应用程序中使用通用存储库和工作单元模式。这个应用程序连接到两个以上的数据库,所以我必须在应用程序中使用多个 DbContext。

public class ContextOne : DbContext
{
    public DbSet<Model_One1>
    public DbSet<Model_One2>
}

public class ContextTwo : DbContext
{
    public DbSet<Model_Two1>
    public DbSet<Model_Two2>
}

public class ContextThree : DbContext
{
    public DbSet<Model_Three1>
    public DbSet<Model_Three2>
}

public interface IRepository<T> where T : DbContext
{
    void Add<T>(T entity) where T : class;
}

public class Repository<T> where T : DbContext
{
    void Add<T>(T entity) where T : class
    {
        //T is DbContext and Model. So confusing
    }
}

public interface IUnitOfWork<IRepository>
{
}

public class UnitOfWork<IRepository>
{
    //IRepository contains more than one DbContext how can I initiate them here?
}

//in application should look like this
public class BaseController : Controller
{
    protected IRepository repository = new .. //here I have no idea with multiple DbContext
}

public class HomeController : BaseController
{
    public ActionResult Add(Model_Two2 model)
    {
        base.repository.Add<Model_Two2>(model)
    }
}

如果我从 Controller 调用 IRepository 和 IUnitOfWork 我如何知道匹配的上下文?这个问题的最佳实践是什么?

【问题讨论】:

    标签: c# asp.net-mvc design-patterns


    【解决方案1】:

    我建议您使用 Constructor 参数创建 UnitOfWork 模式以接受 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];
        }
    }
    

    IDbContext 在哪里 -

    public interface IDbContext
    {
        IDbSet<T> Set<T>() where T : class;
        int SaveChanges();
        void Dispose();
    }
    

    而存储库实现将是 -

     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();
            }
        }
    

    使用这种方法,您可以为单个 DBContext 创建一个 UnitOfWork,并且您可以在 UnitOfWork 中提交或回滚特定的逻辑。

    【讨论】:

    • 我应该如何在我的 BaseController 中调用 IRepository 和 IUnitOfWork?我应该为每个模型创建数百个 IRepository 实例吗?比如IRepository repositoryStudent = new Repository&lt;StudentViewModel&gt;()等等等等。
    • 我认为BaseController 不是启动 UoW 的正确位置。相反,它应该在您的业务流程级别按需创建。因此,根据需求根据 DbContexts 创建特定的 UoW,然后获取特定的存储库。
    • 由于您的UnitOfWork 没有析构函数和非托管资源,您不必调用GC.SuppressFinalize(this) 也不必实现处置模式。您只需在UnitOfWork.Dispose 中拨打_context.Dispose()
    • @ramiramilu 我会要求提供您获得此代码的 github 路径
    • @ramiramilu 我的存储库有问题。你可以通过 Skype 给我看看吗?
    【解决方案2】:

    我会将UnitOfWork 实现为ActionAttribute,其中OnActionExecuting 我打开事务,OnActionExecuted 我提交事务,如果一切正常,如果ActionContext 出现异常,事务应该回滚。

    棘手的是您有 2 个 DbContext。我认为,您应该懒惰地创建 dbContexts。引入一种标志变量,在UnitOfWork.OnActionExecuting中设置为True。然后,当你第一次接触 dbContext 时,你应该检查你是否正在处理UnitOfWork,如果是,你应该为这个特定的 dbContext 打开事务。所有打开的交易都可以放入一个可以从UnitOfWork.ActionExecuted 访问的列表中。最后检查ActionContext中是否有异常:是-Rollback,否-Commit

    【讨论】:

    • 提交和回滚事务没有问题。我需要解释使用多个 DbContext 创建 Repsitory 和 UoW 模式的最佳实践,因为我的应用程序必须连接到相同和不同服务器上的多个数据库。我想要一个带有单个通用存储库的 UoW 可以处理这些 DbContexts。
    猜你喜欢
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多