具有复合外键的实体框架导航属性

时间:2017-04-07 02:46:29

标签: c# entity-framework entity-framework-6

EF 6.1.3。

我有一个域名,其中包含许多"标题/项目"类型模式,其中一个标题可以有多个项目(1到多个),并且还有一个"当前"或者"最新的"项目。

这表示如下:

Header
    Guid Id
    Guid CurrentItemId
    Item CurrentItem 
    ICollection<Item> AllItems

Item
    HeaderId
    Id

Items的PK始终是HeaderID + ItemID。原因是,到目前为止,项目最常见的访问模式是列出与给定标题相关的所有项目,并且将HeaderID作为PK /聚集索引的第一部分意味着我们使用聚簇索引搜索获取该数据。 / p>

我们的问题是,当我们使用CurrentItem导航属性时,它只使用ItemID进行查找,这导致查询计划不那么好。

我认为这是因为EF我们使用CurrentItemId来查找CurrentItem的约定。我的问题是,有没有办法让我告诉EF总是通过映射Header.Id,Header.CurrentItemId - &gt;来为CurrentItem执行它的连接。 Item.HeaderId,Item.Id?

我认为这与此处描述的情况略有不同:composite key as foreign key

在我的情况下,我有一对一的映射而不是前一个很多,并且似乎没有可用于该场景的WithforeignKey方法。

1 个答案:

答案 0 :(得分:0)

我们最终无法让EF以我们想要的方式生成SQL - 因此我们编写了一个db命令拦截器来动态查找此连接的实例并重新编写连接以匹配我们设计的复合键。

我们将其配置为DbContext级别,如下所示:

    this.ModifyJoin<Item, Header>(
        (i) => new Header() { CurrentItemId = i.Id }, //What to find
        (i) => new Header() { CurerntItemId = i.Id, Id = i.HeaderId }); //What to replace with

此信息附加到上下文实例本身,因此当命令拦截器看到覆盖时,它会使用它们来重写SQL。

这最终适用于大多数情况,但有一些 - 例如当作为LINQ语句的一部分对Item表进行额外过滤时,EF使用的别名规则变得过于复杂而无法编写完整的SQL解析器。

对于我们的使用,这导致理想的加入大约90%的时间,这对我们来说已经足够了。

完成所有这些工作的代码并不困难,但它太大了,无法放在这里。如果你想要一份副本,请添加评论,我将把它放在GitHub上。