Создание уникального индекса с помощью Entity Framework 6.1 fluent API

У меня есть столбец "Name", который должен быть unqiue. Никакого внешнего ключа или чего-то подобного.

EF 6.1, наконец, поддерживает создание таких индексов с помощью аннотаций. Это уже обсуждалось на SO. Но, похоже, это можно сделать только с помощью аннотаций в классах. Как это сделать, используя только Fluent API?

что-то вроде этого:

public class PersonConfiguration : EntityTypeConfiguration<Person>
{
    public PersonConfiguration()
    {
        HasKey(p => p.Id);
        Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        //not possible?
        Index(p => p.Name).IsUnique();  //???
    }
}

6 ответов


Примечание: относится к EF 6

можно использовать IndexAttribute как уже упоминалось, но С Fluent API вместо DataAnnotations что будет делать трюк:

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name) 
    .HasColumnAnnotation( 
        "Index",  
        new IndexAnnotation(new IndexAttribute("IX_Name") { IsUnique = true }));

к сожалению, нет другого способа создать уникальные индексы с помощью Fluent API. Существует открытая проблема, касающаяся этой функции:Уникальные Ограничения (Уникальные Индексы)


обновление: Entity Framework Ядро

В последнем выпуске EF Core вы можете положиться на Fluent API для указания индексов без дополнительных уловок.
HasIndex позволяет определить его:
modelBuilder 
    .Entity<Person>()
    .HasIndex(x => x.Name);

отсюда ретурс IndexBuilder object вы можете использовать его для дальнейших конфигураций индекса (i.e уникальность):

modelBuilder 
    .Entity<Person>()
    .HasIndex(x => x.Name)
    .IsUnique();

основываясь на ответе Анатолия, вот метод расширения для более плавной установки уникальных индексов:

public static class MappingExtensions
{
    public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
    {
        return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
    }
}

использование:

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name)
    .IsUnique();

будет генерировать миграции, такие как:

public partial class Add_unique_index : DbMigration
{
    public override void Up()
    {
        CreateIndex("dbo.Person", "Name", unique: true);
    }

    public override void Down()
    {
        DropIndex("dbo.Person", new[] { "Name" });
    }
}

этот ответ содержит только дополнительную информацию, поскольку уже есть отличные ответы.

если вы хотите несколько уникальных полей в вашем индексе вы можете достичь этого, добавив Order собственность. Необходимо также убедиться, что во всех свойствах используется одно и то же имя индекса (см. uniqueIndex ниже).

string uniqueIndex = "UN_TableName";

this.Property(t => t.PropertyOne)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(
            new IndexAttribute(uniqueIndex)
            {
                IsUnique = true,
                Order = 1
            }
        )
    );

this.Property(t => t.PropertyTwo)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(
            new IndexAttribute(uniqueIndex)
            {
                IsUnique = true,
                Order = 2
            }

        )
    );

теперь, предположим, вы также хотите индекс на PropertyTwo.

на неправильно способ сделать это было бы начать новая строку с this.Property(t => t.PropertyTwo) как это отменит Ваш уникальный индекс.

все ваши индексы (index и unique) должны быть определены одновременно. Это был бы правильный способ сделать это:

this.Property(t => t.PropertyTwo)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(new[] 
            {
                new IndexAttribute(), // This is the index
                new IndexAttribute(uniqueIndex) // This is the Unique made earlier
                {
                    IsUnique = true,
                    Order = 2
                }
            }
        )
    );

наконец, если вы также хотите изменить порядок сортировки вашего индекса / unique, вы можете увидеть:

как добавить индекс на несколько столбцов с сортировкой ASC/DESC с помощью Fluent API ?.


в новой версии EF это 6.2 можно использовать HasIndex способ:

 modelBuilder.Entity<User>().HasIndex(user => user.Email).IsUnique(true);
 modelBuilder.Entity<User>().HasIndex(user => user.UserName).IsUnique(true);

обновление для EF Core:

 modelBuilder.Entity<User>()
        .HasIndex(b => b.Email)
        .IsUnique();

 modelBuilder.Entity<User>()
        .HasIndex(b => b.UserName)
        .IsUnique();

Microsoft Docs - EF основные индексы


в файле миграции можно создать уникальный индекс.

В Менеджере Пакетов:

  1. Включить-Миграций
  2. Добавить - Миграция InitialMigration

это создаст новый файл в папке миграций, который помечен временем. Класс будет иметь метод Up и Down, который можно использовать для создания индекса:

public override void Up()
{
    // ... 
    CreateIndex("tableName", "columnName", unique: true, name: "myIndex");
}

public override void Down()
{
    // ...
    DropIndex("tableName", "myIndex");
}

для запуска типа миграции Update-Database в диспетчере пакетов.

вы также можете добавьте индекс как часть миграции, которая также создает таблицу:

CreateTable(
    "dbo.Products",
    c => new
        {
            ProductId = c.Int(nullable: false, identity: true),
            ProductName = c.String(nullable: false, maxLength: 256),
        })
    .Index(c => c.ProductName, name: "IX_Products_ProductName", unique: true)
    .PrimaryKey(t => t.ProductId);

для меня, используя MVC 5 и EF 6, ключевой точкой было указание длины в свойстве string, где я хотел разместить индекс.

protected override void OnModelCreating(DbModelBuilder modelBuilder){
    //More stuff
    modelBuilder.Entity<Device>().Property(c => c.Name).HasColumnType("nvarchar").HasMaxLength(50);
    modelBuilder.Entity<Device>().HasIndex(c => c.Name).IsUnique(true); 
}