19

我们有一个数据库,其中一个表包含可以是其他几个表的子记录。它有一个由所有者 ID 和表名组成的“软”外键。这种(反)模式被称为“多态关联”。我们知道这不是最好的数据库设计,我们会在适当的时候改变它,但不会在不久的将来。让我展示一个简化的例子:

在此处输入图像描述

EventPerson和都Product在 Comment 中有记录。如您所见,没有硬性 FK 约束。

Comment在实体框架中,可以通过子类化到等来支持此模型,EventComment并让Event有一个EventComments集合等:

在此处输入图像描述

从数据库生成基本模型后,手动添加子类和关联。OwnerCode是这个TPH模型中的判别器。请注意Event,PersonProduct是完全不同的实体。为它们提供一个通用的基类是没有意义的。

这是数据库优先的。我们现实生活中的模型就是这样工作的,没问题。

好的。现在我们要转向代码优先。所以我开始将数据库逆向工程为代码优先模型(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 中它们是概念模型的一部分。

那么,我怎样才能先创建这个模型呢?我认为关键是如何指示代码优先映射概念模型中的关联,而不是存储模型。

4

1 回答 1

1

在这种复杂程度的任何模式上使用 EF 时,我个人首先坚持使用数据库。关于代码,我遇到了复杂模式的问题。也许较新的版本更好一些,但担心如何尝试和编码复杂的关系似乎不那么直接,而是让引擎为您生成它。此外,当关系变得如此复杂时,我倾向于避免尝试使用 EF 生成它,并尝试使用存储过程来更轻松地对可能出现的性能瓶颈进行故障排除。

于 2013-11-22T13:36:38.567 回答