zoukankan      html  css  js  c++  java
  • Multiple DbContexts in NTier Application

    一种模式,对多个DBContext的支持。

    引自:http://stackoverflow.com/questions/6654355/multiple-dbcontexts-in-n-tier-application

    Giving your Factory and UnitOfWork a generic type parameter might be a solution:

    public class UnitOfWork<T> : IUnitOfWork<T>
        where T : DbContext, new()
    {
        private T _context;
    
        private readonly IDatabaseFactory<T> _databaseFactory;
    
        protected T Context
        {
            get { return _context ?? (_context = _databaseFactory.Get()); }
        }
    
        public UnitOfWork(IDatabaseFactory<T> factory)
        {
            _databaseFactory = factory;
            _context = _databaseFactory.Get();
        }
        //More code
    }
    
    public class DatabaseFactory<T> : Disposable, IDatabaseFactory<T>
        where T : DbContext, new()
    {
        private T _dataContext;
    
        public T Get()
        {
            return _dataContext ?? (_dataContext = new T());
        }
    
        protected override void DisposeCore()
        {
            if (_dataContext != null)
                _dataContext.Dispose();
        }
    }
    

    The IDatabaseFactory and IUnitWork interfaces would also have to be generic then.

    You could then create Unit of Works for different contexts:

    var factory1 = new DatabaseFactory<SiteModelContainer>();
    var unitOfWork1 = new UnitOfWork<SiteModelContainer>(factory1);
    
    var factory2 = new DatabaseFactory<AnotherModelContainer>();
    var unitOfWork2 = new UnitOfWork<AnotherModelContainer>(factory2);
    

    Edit:

    To get rid of the dependency on EF in your service classes you could try something like this. The service only knows these three interfaces:

    public interface IUnitOfWorkFactory
    {
        IUnitOfWork Create(string contextType);
    }
    
    public interface IUnitOfWork : IDisposable
    {
        IRepository<TEntity> CreateGenericRepository<TEntity>()
            where TEntity : class;
        void Commit();
    }
    
    public interface IRepository<T>
    {
        IQueryable<T> Find(Expression<Func<T, bool>> predicate);
        void Attach(T entity);
        void Add(T entity);
        // etc.
    }
    

    Here are special EF-specific implementations:

    public class UnitOfWorkFactory : IUnitOfWorkFactory
    {
        public IUnitOfWork Create(string contextType)
        {
            switch (contextType)
            {
                case "SiteModelContainer":
                    return new UnitOfWork<SiteModelContainer>();
                case "AnotherModelContainer":
                    return new UnitOfWork<AnotherModelContainer>();
            }
    
            throw new ArgumentException("Unknown contextType...");
        }
    }
    
    public class UnitOfWork<TContext> : IUnitOfWork
        where TContext : DbContext, new()
    {
        private TContext _dbContext;
    
        public UnitOfWork()
        {
            _dbContext = new TContext();
        }
    
        public IRepository<TEntity> CreateGenericRepository<TEntity>()
            where TEntity : class
        {
            return new Repository<TEntity>(_dbContext);
        }
    
        public void Commit()
        {
            _dbContext.SaveChanges();
        }
    
        public void Dispose()
        {
            _dbContext.Dispose();
        }
    }
    
    public class Repository<T> : IRepository<T>
        where T : class
    {
        private DbContext _dbContext;
        private DbSet<T> _dbSet;
    
        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
            _dbSet = dbContext.Set<T>();
        }
    
        public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
        {
            return _dbSet.Where(predicate);
        }
    
        public void Attach(T entity)
        {
            _dbSet.Attach(entity);
        }
    
        public void Add(T entity)
        {
            _dbSet.Add(entity);
        }
    
        // etc.
    }
    

    Your service would get a IUnitOfWorkFactory injected:

    public class MyService
    {
        private IUnitOfWorkFactory _factory;
    
        public MyService(IUnitOfWorkFactory factory)
        {
            _factory = factory;
        }
    
        public MyMethod()
        {
            using(var unitOfWork1 = _factory.Create("SiteModelContainer"))
            {
                var repo1 = unitOfWork1.
                    CreateGenericRepository<SomeEntityTypeInSiteModel>();
                // Do some work
                unitOfWork1.Commit();
            }
    
            using(var unitOfWork2 = _factory.Create("AnotherModelContainer"))
            {
                var repo2 = unitOfWork2.
                    CreateGenericRepository<SomeEntityTypeInAnotherModel>();
                // Do some work
                unitOfWork2.Commit();
            }
        }
    }
    

    When the service is created the concrete instance of the factory is injected:

    var service = new MyService(new UnitOfWorkFactory());
    

    Keep in mind that the hard work will be in the abstract repository and it's implementation. As soon as you don't have the EF context anymore in your service class you have to mimic a lot of methods in the repo interface supporting all necessary scenarios to manipulate the data.

  • 相关阅读:
    关于使用quartz动态增删改定时任务
    关于chrome被篡改主页修复方法
    关于git被误删除的分支还原问题
    mysql数据库备份bat脚本
    同步数据库bat脚本
    读取spring boot项目中resource目录下的文件
    使用Java进行udp-demo编程时碰到的consumer和producter无法连接并报出“java.net.SocketException: Can't assign requested address”问题
    关于在项目中遇到MySQL数据库死锁的问题
    Gitlab仓库搭建及在Linux/windows中的免密使用
    GIT
  • 原文地址:https://www.cnblogs.com/zbw911/p/2892388.html
Copyright © 2011-2022 走看看