honk
honk

Reputation: 591

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

Is it possible using EF Fluent API to configure a Discriminator column and another string column to be part of a unique index constraint?

I have a list of identifiers, where the identifiers can be of different types. Each identifier has a property of type string which holds the identifying string.

A customer in my case can ha different identifiers. But there can only be one identifier with unique string per discriminator.

Abstract class defining a identifier type

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

Concrete class derived from CustomerIdentifier

 class NationalIdNumberIdentifier : CustomerIdentifier
 {
 }

I've managed to configure index for the string column using the answer here, Unique Key constraints for multiple columns in Entity Framework as follows

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

I need to somehow add another line here specifiying that the discrimnator should be included in the unique index constraint.

Upvotes: 8

Views: 4025

Answers (4)

Saurabh Agrawal
Saurabh Agrawal

Reputation: 41

I did not check with EF but verified with EF core. We need to add a custom property for Discriminator in base table and then we can use this property in HasIndex method for making unique key. I have verified it with Oracle as well as SQLServer.

Code : Custom Property for Discriminator:

public string TableName { get; set; }

Fluent 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);

Upvotes: 1

ajbeaven
ajbeaven

Reputation: 9582

EF 7 now has support for this using the fluent API:

modelBuilder.Entity<User>()
    .HasIndex("EmailAddress", "Discriminator")
    .HasName("UQ_EmailAddress")
    .IsUnique();

Upvotes: 0

realstrategos
realstrategos

Reputation: 793

Actually it can be done in EF 6. Below is an example that uses the primary key to create a unique index.

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);
        }
    }

}

Upvotes: 4

DannyT
DannyT

Reputation: 206

Unfortunately it is not supported in EF 6 and may be included in EF 7 as according to "Support of Discriminator column which is part of Primary key" https://entityframework.codeplex.com/workitem/2420.

You may want to vote on it to push it up the priority list.

Upvotes: 1

Related Questions