C# N层应用程序中的多DBContext

C# N层应用程序中的多DBContext,c#,entity-framework-4.1,repository,dbcontext,unit-of-work,C#,Entity Framework 4.1,Repository,Dbcontext,Unit Of Work,我正在创建我的第一个N层MVC应用程序,在如何使用数据库优先的方法管理多个dbContext方面遇到了一个障碍 我有以下几层 Presentation Service (WCF) Business Data Access 我不想在我的服务层中使用实体框架引用,但我不知道如何创建一个接口或其他东西来管理两个上下文。我在IDatabaseFactory中处理一个扭曲的上下文,但似乎找不到一种方法来管理两个 下面是我的UnitOfWork,它是在我的服务中创建的,但从各个角度看,我仍然与SiteMo

我正在创建我的第一个N层MVC应用程序,在如何使用数据库优先的方法管理多个
dbContext
方面遇到了一个障碍

我有以下几层

Presentation
Service (WCF)
Business
Data Access

我不想在我的服务层中使用实体框架引用,但我不知道如何创建一个接口或其他东西来管理两个上下文。我在IDatabaseFactory中处理一个扭曲的上下文,但似乎找不到一种方法来管理两个

下面是我的
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();
    }
}

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

这里是我在过去使用过的一个示例(它还将您的代码从对实体框架的任何直接依赖中分离出来)

//使您的DbContext从此继承。这是在你的工作单位。
公共接口IEntySetProvider:IDisposable
{
IEntitySet CreateEntitySet();
}
//这是你的背景
公共类MyDbContext1:DbContext,IEntySetProvider
{
公共IEntitySet CreateEntitySet()
{
返回新的EntitySet(((IObjectContextAdapter)this).CreateObjectSet());
}
.
.
.
}
/// 
///IQueryable的包装器,公开AddNew和Attach方法。
/// 
/// 
公共接口IEntitySet:IQueryable
{
/// 
///附加指定的值并将其视为新值。
/// 
///价值。
void AddNew(T值);
/// 
///附加指定的值并将其视为已修改。
/// 
///价值。
空隙附着(T值);
}
/// 
///实体框架的IEntitySet。
/// 
/// 
内部类EntitySet:EntitySet,其中T:class
{
私有只读对象集\u对象集;
公共实体集(ObjectSet ObjectSet)
{
_objectSet=objectSet;
}
#区域IEntitySet成员
公共void AddNew(T值)
{
_objectSet.AddObject(值);
}
公共空间附加(T值)
{
_objectSet.Attach(值);
_objectSet.Context.ObjectStateManager.ChangeObjectState(值,EntityState.Modified);
}
公共IEnumerator GetEnumerator()
{
return((IQueryable)u objectSet.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return((IQueryable)u objectSet.GetEnumerator();
}
公共类型ElementType
{
获取{return((IQueryable)u objectSet.ElementType;}
}
公开表达
{
获取{return((IQueryable)u objectSet.Expression;}
}
公共IQueryProvider提供程序
{
获取{return((IQueryable)\u objectSet.Provider;}
}
#端区
}

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

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

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

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.
}
创建服务时,将注入工厂的具体实例:

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();
        }
    }
}
var service = new MyService(new UnitOfWorkFactory());

请记住,艰苦的工作将在抽象存储库及其实现中进行。一旦您的服务类中不再有EF上下文,您就必须在repo接口中模拟许多方法,支持所有必要的场景来操作数据。

我非常喜欢这种方式,但以这种方式在我的服务中实例化一个新的
UnitOfWork
DatabaseFactory
,仍然需要引用实体框架,我正试图避免引用实体框架以分离关注点。我不希望我的服务依赖于EF,但我想我可能最终会打破这个规则。@Jisaak。我尝试了一个从EF中删除您的服务依赖性的建议。我认为这是可能的,但我已经稍微改变了您的设计,特别是将
数据库工厂
替换为
UnitOfWorkFactory
(接口和实现),请参见我的编辑…“我在IDatabaseFactory中处理单个扭曲的上下文”我感觉到了您的痛苦;我的很多代码似乎也存在时间和/或空间扭曲。
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.
}
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();
        }
    }
}
var service = new MyService(new UnitOfWorkFactory());