在 Entity Framework 中添加鉴别器列作为唯一索引的一部分

Add discriminator column as a part of a unique index in Entity Framework

是否可以使用 EF Fluent API 将鉴别器列和另一个字符串列配置为唯一索引约束的一部分?

我有一个标识符列表,其中标识符可以是不同类型的。每个标识符都有一个 属性 类型的字符串,其中包含标识字符串。

在我的例子中,一个客户可以有不同的标识符。但是每个鉴别器只能有一个具有唯一字符串的标识符。

摘要class定义标识符类型

 public abstract class CustomerIdentifier : Entity<int>
 {
    public string Identifier { get; set; }
 }

从 CustomerIdentifier

派生的具体 class
 class NationalIdNumberIdentifier : CustomerIdentifier
 {
 }

我已经使用这里的答案为字符串列配置了索引, Unique Key constraints for multiple columns in Entity Framework如下

class CustomerIdentifierMap : EntityTypeConfiguration<CustomerIdentifier>
{
    public CustomerIdentifierMap()
    {
        Property(p => p.Identifier).HasMaxLength(100).IsRequired().HasUniqueIndexAnnotation("UQ_IdentifierPerDiscriminator", 0);
    }
}

我需要以某种方式在此处添加另一行,指定鉴别器应包含在唯一索引约束中。

不幸的是,它在 EF 6 中不受支持,根据 "Support of Discriminator column which is part of Primary key" https://entityframework.codeplex.com/workitem/2420.

可能包含在 EF 7 中

您可能想对其进行投票以将其推到优先级列表中。

实际上在EF 6中可以做到。下面是一个使用主键创建唯一索引的例子。

internal class DiscriminatorServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
    const string DiscriminatorColumnName = "Discriminator";
    protected override void Generate(CreateTableOperation op)
    {
        base.Generate(op);
        if (op.Columns.Any(x => x.Name == DiscriminatorColumnName))
        {
            if (op.PrimaryKey != null && op.PrimaryKey.Columns.Any())
            {
                CreateDiscriminatorIndex(op.Name, true, op.PrimaryKey.Columns.ToArray());
            }
            else
            {
                CreateDiscriminatorIndex(op.Name);
            }
        }
    }
    private void CreateDiscriminatorIndex(string tableName, bool isUnique = false, params string[] columns)
    {
        var cols = "[Discriminator]";
        if (columns.Length > 0)
        {
            cols += ", " + string.Join(", ", columns.Select(x => "[" + x + "]"));
        }
        var unique = isUnique ? "UNIQUE" : "";
        using (var writer = Writer())
        {
            var str = $@"
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Discriminator' AND object_id = OBJECT_ID(N'{tableName}'))
EXECUTE('CREATE {unique} NONCLUSTERED INDEX [IX_Discriminator] ON {tableName} ({cols})')";
            writer.WriteLine(str);
            Statement(writer);
        }
    }

}

EF 7 现在使用流畅的 API:

对此提供支持
modelBuilder.Entity<User>()
    .HasIndex("EmailAddress", "Discriminator")
    .HasName("UQ_EmailAddress")
    .IsUnique();

我没有使用 EF 检查,但使用 EF core 进行了验证。我们需要在 base table 中为 Discriminator 添加一个自定义的 属性 然后我们可以在 HasIndex 方法中使用这个 属性 来制作唯一键。我已经用 Oracle 和 SQLServer 验证了它。

代码: 鉴别器的自定义 属性:

public string TableName { get; set; }

流利API:

modelBuilder.Entity<BaseTable>().HasDiscriminator<string>("TableName").HasValue<ChildTable1>("ChildTable1").HasValue<ChildTable2>("ChildTable2").HasValue<ChildTable3>("ChildTable3");

modelBuilder.Entity<BaseTable>().HasIndex(m => new { m.Name, m.DeletedOnUtc, m.TableName }).IsUnique().HasFilter(null);