我们有一个数据库,其中一个表包含可以是其他几个表的子记录。它有一个由所有者 ID 和表名组成的“软”外键。这种(反)模式被称为“多态关联”。我们知道这不是最好的数据库设计,我们会在适当的时候改变它,但不会在不久的将来。让我展示一个简化的例子:
Event
、Person
和都Product
在 Comment 中有记录。如您所见,没有硬性 FK 约束。
Comment
在实体框架中,可以通过子类化到等来支持此模型,EventComment
并让Event
有一个EventComments
集合等:
从数据库生成基本模型后,手动添加子类和关联。OwnerCode
是这个TPH模型中的判别器。请注意Event
,Person
和Product
是完全不同的实体。为它们提供一个通用的基类是没有意义的。
这是数据库优先的。我们现实生活中的模型就是这样工作的,没问题。
好的。现在我们要转向代码优先。所以我开始将数据库逆向工程为代码优先模型(EF Power Tools),然后继续创建子类并映射关联和继承。试图连接到 Linqpad 中的模型。这时候麻烦就开始了。
当尝试使用此模型执行查询时,它会抛出一个InvalidOperationExeception
外键组件“OwnerId”不是“EventComment”类型的声明属性。验证它没有被明确地从模型中排除,并且它是一个有效的原始属性。
当我有双向关联并被OwnerId
映射为Comment
. EventMap
我的类 ( )中的映射EntityTypeConfiguration<Event>
如下所示:
this.HasMany(x => x.Comments).WithRequired(c => c.Event)
.HasForeignKey(c => c.OwnerId);
所以我试图OwnerId
在模型中不映射关联:
this.HasMany(x => x.Comments).WithRequired().Map(m => m.MapKey("OwnerId"));
这抛出一个MetaDataException
指定的架构无效。错误:(10,6):错误 0019:类型中的每个属性名称必须是唯一的。已定义属性名称“OwnerId”。(11,6) : 错误 0019: 类型中的每个属性名称必须是唯一的。已定义属性名称“OwnerId”。
如果我删除了三个实体评论关联中的两个,就可以了,但这当然不是治愈方法。
一些进一步的细节:
- 通过添加 DbContext 生成器项,可以从 edmx 创建一个有效的 DbContext 模型(“第二个代码”)。(这暂时是一种解决方法)。
- 当我将工作代码优先模型(具有一个关联)导出到 edmx (
EdmxWriter
) 时,关联似乎在存储模型中,而在原始 edmx 中它们是概念模型的一部分。
那么,我怎样才能先创建这个模型呢?我认为关键是如何指示代码优先映射概念模型中的关联,而不是存储模型。