在N层应用多DbContexts [英] Multiple DbContexts in N-Tier Application

查看:124
本文介绍了在N层应用多DbContexts的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要创建我的第N层MVC应用程序,我已经碰到如何管理多个 DbContexts 与我的数据库第一种方法路障。



我有以下层

 演示
服务(WCF )
企业
数据访问

我不希望实体框架参考在我的服务层,但我不明白如何创建一个接口或东西来管理两个上下文。我把它用在IDatabaseFactory warpped单一的环境中工作,但我似乎无法找到管理两个办法。



下面是我的的UnitOfWork 是在我的服务构造函数,但是每一个方法,我看着它,我还是绑在 SiteModelContainer 的时候,其实我还有一个创建。背景

 公共类的UnitOfWork:IUnitOfWork 
{
私人SiteModelContainer _context;

私人只读IDatabaseFactory _databaseFactory;

保护SiteModelContainer SiteContext
{
{返回_context? (_context = _databaseFactory.Get()); }
}

公众的UnitOfWork(IDatabaseFactory工厂)
{
_databaseFactory =厂;
_context = _databaseFactory.Get();
}
//更多代码
}



公共类DatabaseFactory:一次性使用,IDatabaseFactory
{
私人SiteModelContainer _dataContext;

公共SiteModelContainer获得()
{
返回_dataContext? (_dataContext =新SiteModelContainer());
}

保护覆盖无效DisposeCore()
{
如果(_dataContext!= NULL)
_dataContext.Dispose();
}
}


解决方案

捐赠你的工厂和一个的UnitOfWork泛型类型参数可能是一个解决办法:

 公共类的UnitOfWork< T> :IUnitOfWork< T> 
,其中T:的DbContext,新的()
{
私人牛逼_context;

私人只读IDatabaseFactory< T> _databaseFactory;

保护牛逼语境
{
{返回_context? (_context = _databaseFactory.Get()); }
}

公众的UnitOfWork(IDatabaseFactory< T>工厂)
{
_databaseFactory =厂;
_context = _databaseFactory.Get();
}
//更多代码
}

公共类DatabaseFactory< T> :一次性,IDatabaseFactory< T>
,其中T:的DbContext,新的()
{
私人牛逼_dataContext;

公共吨得到()
{
返回_dataContext? (_dataContext =新T());
}

保护覆盖无效DisposeCore()
{
如果(_dataContext!= NULL)
_dataContext.Dispose();
}
}



IDatabaseFactory IUnitWork 接口也必须是通用的吧。



您可以再创建工程单位针对不同的上下文:

  VAR FACTORY1 =新DatabaseFactory< SiteModelContainer>(); 
变种unitOfWork1 =新的UnitOfWork< SiteModelContainer>(FACTORY1);

变种FACTORY2 =新DatabaseFactory< AnotherModelContainer>();
变种unitOfWork2 =新的UnitOfWork< AnotherModelContainer>(FACTORY2);



编辑:



要摆脱你的服务类EF上的依赖,你可以尝试这样的事情的。该服务只知道这三个接口:

 公共接口IUnitOfWorkFactory 
{
IUnitOfWork创建(字符串contextType) ;
}

公共接口IUnitOfWork:IDisposable的
{
IRepository< TEntity> CreateGenericRepository< TEntity>()
其中TEntity:类;
无效提交();
}

公共接口IRepository< T>
{
&IQueryable的LT; T>查找(表达式来; Func键< T,BOOL>>谓语);
无效连接(T实体);
无效添加(T实体);
//等
}

下面是特殊的具体的EF-实现:

 公共类UnitOfWorkFactory:IUnitOfWorkFactory 
{
公共IUnitOfWork创建(字符串contextType)
{
开关(contextType)
{
案SiteModelContainer:
返回新的UnitOfWork< SiteModelContainer>();
案AnotherModelContainer:
返回新的UnitOfWork< AnotherModelContainer>();
}

抛出新的ArgumentException(未知contextType ......);
}
}

公共类的UnitOfWork< TContext> :IUnitOfWork
式TContext:的DbContext,新的()
{
私人TContext _dbContext;

公众的UnitOfWork()
{
_dbContext =新TContext();
}

公共IRepository< TEntity> CreateGenericRepository< TEntity>()
其中TEntity:类
{
返回新的存储库< TEntity>(_的DbContext);
}

公共无效提交()
{
_dbContext.SaveChanges();
}

公共无效的Dispose()
{
_dbContext.Dispose();
}
}

公共类库< T> :IRepository< T>
,其中T:类
{
私有的DbContext _dbContext;
私人DbSet< T> _dbSet;

公共库(的DbContext的DbContext)
{
_dbContext =的DbContext;
_dbSet = dbContext.Set< T>();
}

公众的IQueryable< T>查找(表达式来; Func键< T,BOOL>>谓语)
{
返回_dbSet.Where(谓语);
}

公共无效连接(T实体)
{
_dbSet.Attach(实体);
}

公共无效添加(T实体)
{
_dbSet.Add(实体);
}

//等
}

您的服务会得到一个 IUnitOfWorkFactory 注:

 公共类为MyService 
{
私人IUnitOfWorkFactory _factory;

公共则将MyService(IUnitOfWorkFactory工厂)
{
_factory =厂;
}

公众的MyMethod()使用(VAR unitOfWork1 = _factory.Create(SiteModelContainer))
{
变量
{
repo1 = unitOfWork1。
CreateGenericRepository< SomeEntityTypeInSiteModel>();
//做一些工作
unitOfWork1.Commit();
}

使用(VAR unitOfWork2 = _factory.Create(AnotherModelContainer))
{
VAR repo2 = unitOfWork2。
CreateGenericRepository< SomeEntityTypeInAnotherModel>();
//做一些工作
unitOfWork2.Commit();
}
}
}

在创建服务工厂的具体实例注入:

  VAR的服务=新的MyService(新UnitOfWorkFactory());记住

请说的辛勤工作将在抽象的存储库,它的实现。只要你没有EF背景下再在你的服务类,你必须模仿很多的回购接口,支持所有必要的情况下操纵数据的方法。


I'm creating my first N-Tier MVC application and I've run into a road block with how to manage multiple DbContexts with my database first approach.

I have the following layers

Presentation
Service (WCF)
Business
Data Access

I don't want an entity framework reference in my service layer but I don't see how to create an Interface or something to manage two contexts. I have it working with a single context warpped in a IDatabaseFactory but I can't seem to find an approach to manage two.

Below is my UnitOfWork that is created in my Service ctor but every way I look at it I'm still tied to the SiteModelContainer, when in fact I have another context.

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

解决方案

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.

这篇关于在N层应用多DbContexts的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆