首页 > 解决方案 > EF Core:在同一列上创建多个过滤索引

问题描述

EF Core 是否有理由不允许您在同一列上创建多个索引?

    builder
      .ForSqlServerHasIndex(x => x.ColumnX)
      .ForSqlServerInclude(nameof(TableA.ColumnA), nameof(TableA.ColumnB))
      .HasFilter($"{nameof(TableA.ColumnX)} = 1 AND {nameof(TableA.IsDeleted)} = 0")
      .HasName($"IX_{nameof(TableA)}_{nameof(TableA.ColumnX)}_Filter_1}");

    builder
      .ForSqlServerHasIndex(x => x.ColumnX)
      .ForSqlServerInclude(nameof(TableA.ColumnA), nameof(TableA.ColumnB))
      .HasFilter($"{nameof(TableA.ColumnX)} = 0 AND {nameof(TableA.IsDeleted)} = 0")
      .HasName($"IX_{nameof(TableA)}_{nameof(TableA.ColumnX)}_Filter_0}");

以上只是我正在尝试做的一个示例。EF Core 不会生成两个索引。相反,它只是为第一次出现生成一个索引,然后我必须手动编辑迁移脚本以获得第二个索引。

不是好像 SQL 抱怨它吗?

标签: c#sql-serveref-core-2.2

解决方案


我的要求与您的要求非常相似-同一属性上的两个索引,但过滤器不同。我刚刚发现 Entity Framework Core 使用索引属性作为索引标识符的艰难方式。有关创建索引的文档证实了这一点:

EF Core 仅支持每个不同的属性集一个索引。如果您使用 Fluent API 在一组已定义索引的属性上配置索引,无论是按照约定还是以前的配置,那么您将更改该索引的定义。如果您想进一步配置按约定创建的索引,这很有用。

可以通过手动将第一个索引添加回模型快照、迁移和迁移的快照来绕过此行为。这是我们采取的路线,一切都按预期进行。但是,每次生成后续迁移时,它都会删除第一个索引,我们必须继续手动添加它。如果我们可以使用名称作为索引的唯一标识符而不是使用索引属性列表,那就太好了。

顺便说一句,在您发布的示例中,您可以使用IN()运算符并创建以下单个索引来涵盖这两种情况:

builder
    .ForSqlServerHasIndex(x => x.ColumnX)
    .ForSqlServerInclude(nameof(TableA.ColumnA), nameof(TableA.ColumnB))
    .HasFilter($"{nameof(TableA.ColumnX)} IN (1, 2) AND {nameof(TableA.IsDeleted)} = 0");

更新 - 2021 年 11 月 17 日

此问题已在 EntityFramework 5.0 中得到解决。从文档中

现在允许在同一个集合或属性上使用多个索引。这些索引现在通过模型中的名称来区分。按照约定,模型名称用作数据库名称;但是它也可以使用 HasDatabaseName 独立配置。


推荐阅读