启动时注册多个DbContext实例以在通用存储库中使用

时间:2019-07-08 14:39:07

标签: asp.net-core .net-core entity-framework-core

我正在尝试创建一个通用存储库,该存储库接受2个通用类型,例如

public class EfRepository<T, TS> : IAsyncRepository<T,TS> where T : BaseEntity
                                                           where TS : DbContext
    {
..........
}

在startup.cs中,我具有通常的映射:

services.AddScoped<DbContext, ConfigDbContext>();

我现在如何向DbContext添加另一个映射?我尝试在DbContext和我创建的另一个Context之间添加另一个映射,但是它仅使用第一个映射。

我需要使用多个数据库,理想情况下,每个数据库都希望有一个DbContext,但是我看不到具有多个DI映射的方法。

在我的EfRepository类中,当我向代码中添加一个额外的DbContext并使用它时,以下代码异常:

protected readonly DbContext _dbContext;
        public EfRepository(DbContext dbContext)
        {
            this._dbContext = (TS)dbContext;
        }

例外是无法从Type1转换为Type2,我知道这是因为DbContext在我的startup.cs中绑定到Type1。

我(如果可能)如何以通用方式使用多个DbContext?

1 个答案:

答案 0 :(得分:2)

这不是您注册DbContext的方式,这是问题的根源。正确的方法是:

services.AddDbContext<ConfigDbContext>(o =>
    o.UseSqlServer(Configuration.GetConnectionString("Foo")));

正确完成,添加另一个完全相同:

services.AddDbContext<SomeOtherContext>(o =>
    o.UseSqlServer(Configuration.GetConnectionString("OtherConnectionString")));

然后,要拉入哪一个取决于您要注入的那一种,是的,这确实意味着您需要指定要注入的实际类型,而不是一般地DbContext。但是,只能执行一个派生类。换句话说,您可以保留已有的代码(尽管不应该强制转换上下文),只需执行以下操作即可:

public class FooRepository : EFRepository<Foo, ConfigDbContext>
{
    public FooRepository(ConfigDbContext context)
        : base(context) {}
}

您可以将其保留为DbContext,因为您不需要实际的类型即可执行EF操作。要使用DbSet,可以使用通用Set<T>

var foos = _dbContext.Set<Foo>();

现在,说了一切,把它全部扔掉。将仓库模式与EF这样的ORM一起使用是完全不可接受的。 EF 已经已实现存储库和工作单元单元。 DbContext是您的工作单元,每个DbSet是一个存储库。在此之上添加额外的层无济于事,但会增加代码的维护问题和额外的熵,并且坦率地说,创建与EF配合良好的存储库/工作单元似乎是不可能的,因此常常,您将束缚EF,从而使其效率降低且更难使用。

使用像EF这样的ORM选择使用第三方DAL。就这些。那时无需创建自己的DAL,因为您已经将其外包了。我不确定为什么这么多人对此感到挂念。您上一次创建自己的路由框架或模板化视图预处理器的时间是什么时候。决不。您只是用于该(框架)的第三方库,那么为什么也将第三方库用于您的DAL是一个问题?

然后,您要问清楚抽象EF依赖项的方法。好吧,首先,如果您想在某天转换ORM,则不会。只是永远不会发生。您将更快地从头开始重写整个应用程序。其次,存储库模式甚至无法实现这一目标。您仍然有一个EF依赖关系,一直到前线应用程序冒泡。没办法解决。

对于真正的抽象,您可以使用诸如微服务架构之类的东西。除此之外,只需拥抱依赖项或根本不使用它,然后真的创建自己的DAL。