我们有一个数据库,其中一个表包含可以是其他几个表的子记录 . 它有一个“软”外键,由所有者的Id和表名组成 . 这种(反)模式被称为“多态关联” . 我们知道它不是有史以来最好的数据库设计,我们会在适当的时候改变它,但不会在不久的将来改变它 . 让我举一个简化的例子:
Event
, Person
和 Product
都在Comment中有记录 . 如您所见,没有严格的FK约束 .
在实体框架中,可以通过将 Comment
子类化为 EventComment
等来支持此模型,并让 Event
具有 EventComments
集合等:
从数据库生成基本模型后,手动添加子类和关联 . OwnerCode
是此 TPH 模型中的鉴别器 . 请注意 Event
,_1344057_和 Product
是完全不同的实体 . 为它们 Build 一个公共基类是没有意义的 .
这是数据库优先的 . 我们的现实模型就是这样,没问题 .
好 . 现在我们想要转向代码优先 . 所以我开始将数据库逆向工程化为代码优先模型(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模型("code second") . (这将是暂时的解决方法) .
-
当我将工作代码优先模型(带有一个关联)导出到edmx(
EdmxWriter
)时,关联似乎在存储模型中,而在原始edmx中,它们是概念模型的一部分 .
那么,我该如何创建这个模型代码呢?我认为关键是如何指导代码优先映射概念模型中的关联,而不是存储模型 .
1 回答
在任何具有这种复杂程度的架构上使用EF时,我个人首先坚持使用数据库 . 我首先遇到了关于代码的复杂模式的问题 . 也许新版本更好一些,但担心如何尝试编写复杂的关系似乎不太直接,然后允许引擎为您生成它 . 此外,当关系变得复杂时,我倾向于避免尝试使用EF生成它,并尝试使用存储过程来更轻松地排除可能出现的性能瓶颈 .