How to specify Unique Key in EF 7 Code First with Data Annotations

code-first data-annotations entity-framework entity-framework-core

Question

You can specified a Unique Key with Fluent Api:

public class MyContext : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasIndex(u => u.Nickname)
            .IsUnique();
    }
}

public class User
{
    public int UserId { get; set; }
    public string Nickname { get; set; }
}

But can you do it with Data Annotations?

Edit

Methods change in EF7 Beta 8:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
        .Index(u => u.Nickname)
        .Unique();
}

Accepted Answer

I'm afraid create an Index using Data Annotation is not still supported in EF 7. Check this link.

I also tried to find some info related with that subject in the last releases and I couldn't find anything.

EF 7 beta 8 release notes

EF 7 RC1 release notes

I found now a post from one of the EF developers (divega) saying this:

In EF7 we support defining indexes using the fluent API but not an attribute, at least no yet. The IndexAttribute you are possibly referring to is something we added to the EF 6.x package at some point but never really became a standard DataAnnotation.

We don't want to copy the original attribute from EF6 as is because there are a few things in it that we would like to change. Also, having it in DataAnnotations directly would likely make more sense than adding it to the EF7 package. I should mention though that it is highly unlikely that we will add IndexAttribute in the EF7 RTM timeframe.

Update 1

Apparently this is a feature that will not be added to EF Core, at least for now.

From EF Core documentation:

Indexes can not be configured using Data Annotations.

But you can do it using Fluent Api:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasIndex(b => b.Url)
        .HasName("Index_Url");
}

Popular Answer

In the absence of built in support, you can use a custom attribute of your own to annotate model properties and apply in OnModelCreating():

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    foreach (var entity in modelBuilder.Model.GetEntityTypes())
    {
        foreach (var prop in entity.GetProperties())
        {
            var index = prop.PropertyInfo.GetCustomAttribute<IndexAttribute>();
            if (index != null)
            {
                entity.AddIndex(prop);
            }
        }
    }
}

With a simple marker attribute class:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IndexAttribute : Attribute
{
}

Then in your model class, just add the attribute to create a secondary index:

public class User
{
    public int UserId { get; set; }
    [Index]
    public string Nickname { get; set; }
}


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why