我正在ASP.NET Core 1.1中构建Web API.
我有许多不同的数据库(针对不同的系统),这些数据库具有配置项,例如配置,用户和组(总共约25个表)的公共基本模式.我试图通过继承基类来避免为模型的共享部分复制相当广泛的EF配置,如图所示.
但是,这不起作用,因为实体框架(EF)要求DbContextOptions
作为参数传递给构造函数,其中DerivedRepository
必须匹配调用构造函数的存储库的类型.然后必须通过DbContext
调用将参数传递给基数:base(param)
.
因此,当(例如)InvestContext初始化时DbContextOptions
,它调用base(DbContextOptions
并且EF抛出错误,因为对ConfigurationContext
构造函数的调用正在接收类型的参数DbContextOptions
而不是所需的类型DbContextOptions
.由于DbContext上的选项字段定义为
private readonly DbContextOptions _options;
我无法看到解决这个问题的方法.
定义共享模型一次并多次使用它的最佳方法是什么?我想我可以创建一个辅助函数并从每个派生的上下文中调用它,但它不像继承那样干净或透明.
好的,我的工作方式仍然使用继承层次结构,如下所示(以InvestContext
上面的例子为例):
如上所述,InvestContext类接收类型的构造函数参数DbContextOptions
,但必须传递DbContextOptions
给它的基础.
我编写了一个方法,用于从DbContextOptions
变量中挖掘连接字符串,并构建所需类型的DbContextOptions实例.InvestContext使用此方法在调用base()之前将其options参数转换为正确的类型.
转换方法如下所示:
protected static DbContextOptionsChangeOptionsType (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 () .UseSqlServer(((SqlServerOptionsExtension)sqlExt).ConnectionString) .Options; }
和InvestContext构造函数调用此更改:
public InvestContext(DbContextOptionsoptions):base(options)
对此:
public InvestContext(DbContextOptionsoptions):base(ChangeOptionsType (options))
到目前为止,InvestContext和ConfigurationContext都适用于简单的查询,但它似乎有点像黑客,可能不是EF7的设计者所想到的.
当我尝试复杂的查询,更新等时,我仍然担心EF会陷入困境.看来这不是问题,见下文)
编辑:我已经记录了此问题,因为与EF7队的问题在这里,和团队成员曾建议更改了EF核心的核心如下:
"我们应该更新检查以允许TContext成为从当前上下文类型派生的类型"
这样可以解决问题.
在与该团队成员(您可以在问题上看到)进行进一步交互并进行一些挖掘EF Core代码之后,我上面概述的方法看起来是安全的,并且是实施建议更改之前的最佳方法.