N层应用程序中的多个DbContexts

我正在创建我的第一个N-Tier MVC应用程序,我遇到了如何使用我的数据库第一种方法管理多个DbContexts

我有以下几层

 Presentation Service (WCF) Business Data Access 

我不想在我的服务层中使用entity framework引用,但是我没有看到如何创建接口或管理两个上下文的东西。 我让它在IDatabaseFactory中使用单个上下文,但我似乎无法找到管理两个的方法。

下面是我在我的服务ctor中创建的UnitOfWork ,但是我看到它的每一种方式我仍然依赖于SiteModelContainer ,而实际上我有另一个上下文。

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

为Factory和UnitOfWork提供generics类型参数可能是一个解决方案:

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

IUnitWorkIUnitWork接口也必须是通用的。

然后,您可以为不同的上下文创建工作单元:

 var factory1 = new DatabaseFactory(); var unitOfWork1 = new UnitOfWork(factory1); var factory2 = new DatabaseFactory(); var unitOfWork2 = new UnitOfWork(factory2); 

编辑:

要摆脱服务类中对EF的依赖,您可以尝试这样的方法。 该服务只知道这三个接口:

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

以下是特定于EF的特定实现:

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

您的服务将获得IUnitOfWorkFactory注入:

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

创建服务时,将注入工厂的具体实例:

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

请记住,辛勤工作将在抽象存储库及其实现中。 只要您的服务类中不再具有EF上下文,就必须在repo界面中模仿许多方法,以支持操作数据的所有必要方案。

您可以创建一个包装器,它是跨DbContexts的通用存储库(并利用底层的ObjectContext来支持它)。

这是我过去使用的一个示例(它还将您的代码与对Entity Framework的任何直接依赖关系分离)。

 // Make your DbContext inherit from this. This goes in your Unit of Work. public interface IEntitySetProvider : IDisposable { IEntitySet CreateEntitySet(); } // This is your adapted DBContext public class MyDbContext1 : DbContext, IEntitySetProvider { public IEntitySet CreateEntitySet() { return new EntitySet(((IObjectContextAdapter)this).CreateObjectSet()); } . . . } ///  /// A wrapper for an IQueryable that exposes AddNew and Attach methods. ///  ///  public interface IEntitySet : IQueryable { ///  /// Attaches the specified value and considers it new. ///  /// The value. void AddNew(T value); ///  /// Attaches the specified value and considers it modified. ///  /// The value. void Attach(T value); } ///  /// An IEntitySet for Entity Framework. ///  ///  internal class EntitySet : IEntitySet where T : class { private readonly ObjectSet _objectSet; public EntitySet(ObjectSet objectSet) { _objectSet = objectSet; } #region IEntitySet Members public void AddNew(T value) { _objectSet.AddObject(value); } public void Attach(T value) { _objectSet.Attach(value); _objectSet.Context.ObjectStateManager.ChangeObjectState(value, EntityState.Modified); } public IEnumerator GetEnumerator() { return ((IQueryable) _objectSet).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IQueryable) _objectSet).GetEnumerator(); } public Type ElementType { get { return ((IQueryable) _objectSet).ElementType; } } public Expression Expression { get { return ((IQueryable) _objectSet).Expression; } } public IQueryProvider Provider { get { return ((IQueryable) _objectSet).Provider; } } #endregion }