如何在 EF7/.NET Core 中为多个数据库实现 DbContext 继承 [英] How do I implement DbContext inheritance for multiple databases in EF7 / .NET Core

查看:79
本文介绍了如何在 EF7/.NET Core 中为多个数据库实现 DbContext 继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 ASP.NET Core 1.1 中构建 Web API.

I am building web APIs in ASP.NET Core 1.1.

我有许多不同的数据库(用于不同的系统),它们具有用于配置项(例如配置、用户和组)(总共约 25 个表)的通用基本架构.我试图通过从图中所示的基类继承来避免为模型的共享部分复制相当广泛的 EF 配置.

I have a number different databases (for different systems) which have common base schemas for configuration items such as Configuration, Users and groups (about 25 tables in all). I am trying to avoid duplicating the quite extensive EF configuration for the shared part of the model by inheriting from a base class as shown in the diagram.

但是,这不起作用,因为实体框架 (EF) 要求将 DbContextOptions 作为参数传递给构造函数,其中 DerivedRepository 必须匹配调用构造函数的存储库的类型.然后必须通过调用 :base(param) 将该参数传递给基础 DbContext.

However, this does not work because of the Entity Framework (EF) requirement to pass DbContextOptions<DerivedRepository> as a parameter to the constructor, where DerivedRepository must match the type of the repository the constructor is called on. The parameter must then be passed down to the base DbContext by calling :base(param).

因此,当(例如)使用 DbContextOptions 初始化 InvestContext 时,它调用 base(DbContextOptions) 并且 EF 抛出错误,因为调用ConfigurationContext 构造函数正在接收 DbContextOptions 类型的参数,而不是所需的类型 DbContextOptions.由于 DbContext 上的选项字段定义为

So when (for example) InvestContext is initialised with DbContextOptions<InvestContext>, it calls base(DbContextOptions<InvestContext>) and EF throws an error because the call to the ConfigurationContext constructor is receiving a parameter of type DbContextOptions<InvestContext> instead of the required type DbContextOptions<ConfigurationContext>. Since the options field on DbContext is defined as

    private readonly DbContextOptions _options;

我找不到解决办法.

一次定义共享模型并多次使用它的最佳方法是什么?我想我可以创建一个辅助函数并从每个派生的上下文中调用它,但它不像继承那样干净或透明.

What is the best way to define the shared model once and use it multiple times? I guess I could create a helper function and call it from every derived context, but it's not nearly as clean or transparent as inheritance.

推荐答案

好的,我已经以一种仍然使用继承层次结构的方式工作,就像这样(使用上面的 InvestContext 作为示例):

OK, I have got this working in a way which still uses the inheritance hierarchy, like this (using InvestContext from above as the example):

如前所述,InvestContext 类接收类型为 DbContextOptions 的构造函数参数,但必须将 DbContextOptions 传递给它的基类.

As stated, the InvestContext class receives a constructor parameter of type DbContextOptions<InvestContext>, but must pass DbContextOptions<ConfigurationContext> to it's base.

我编写了一个方法,它从 DbContextOptions 变量中挖掘连接字符串,并构建所需类型的 DbContextOptions 实例.InvestContext 使用此方法在调用 base() 之前将其 options 参数转换为正确的类型.

I have written a method which digs the connectionstring out of a DbContextOptions variable, and builds a DbContextOptions instance of the required type. InvestContext uses this method to convert its options parameter to the right type before calling base().

转换方法如下:

    protected static DbContextOptions<T> ChangeOptionsType<T>(DbContextOptions options) where T:DbContext
    {
        var sqlExt = options.Extensions.FirstOrDefault(e => e is SqlServerOptionsExtension);

        if (sqlExt == null)
            throw (new Exception("Failed to retrieve SQL connection string for base Context"));

        return new DbContextOptionsBuilder<T>()
                    .UseSqlServer(((SqlServerOptionsExtension)sqlExt).ConnectionString)
                    .Options;
    }

并且 InvestContext 构造函数调用从此更改:

and the InvestContext constructor call changes from this:

  public InvestContext(DbContextOptions<InvestContext> options):base(options)

为此:

  public InvestContext(DbContextOptions<InvestContext> options):base(ChangeOptionsType<ConfigurationContext>(options))

到目前为止,InvestContext 和 ConfigurationContext 都适用于简单的查询,但它看起来有点像黑客,可能不是 EF7 的设计者所考虑的.

So far both InvestContext and ConfigurationContext work for simple queries, but it seems like a bit of a hack and possibly not something the designers of EF7 had in mind.

我仍然担心当我尝试复杂的查询、更新等时 EF 会陷入困境.这似乎不是问题,见下文)

I am still concerned that EF is going to get itself in a knot when I try complex queries, updates etc. It appears that this is not a problem, see below)

我已将此问题记录为 EF7 团队的问题 此处,并且一名团队成员建议对 EF Core 核心进行如下更改:

I've logged this problem as an issue with the EF7 team here, and a team member has suggested a change to the EF Core core as follows:

我们应该更新检查以允许 TContext 是从当前上下文类型派生的类型"

"We should update the check to allow TContext to be a type that is derived from the current context type"

这样就可以解决问题了.

This would solve the problem.

在与该团队成员(您可以在问题上看到)进一步互动并深入研究 EF Core 代码后,我在上面概述的方法看起来是安全的,并且是实施建议更改之前的最佳方法.

After further interaction with that team member (which you can see on the issue) and some digging through the EF Core code, the approach I've outlined above looks safe and the best approach until the suggested change is implemented.

这篇关于如何在 EF7/.NET Core 中为多个数据库实现 DbContext 继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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