Создание уникального индекса с API-интерфейсом Entity Framework 6.1

У меня есть столбец "Имя", который должен быть 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();  //???
    }
}

Ответ 1

Вы можете использовать IndexAttribute, как упоминалось, но с Fluent API вместо DataAnnotations, который выполнит трюк:

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

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

Ответ 2

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

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

Ответ 3

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

Если вы хотите иметь несколько уникальных полей в своем индексе, вы можете достичь этого, добавив свойство 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), так как это ОТМЕНА вашего уникального индекса.

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

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

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

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

Ответ 4

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

В диспетчере пакетов:

  • Enable-Миграция
  • Add-Migration InitialMigration

Это создаст новый файл в папке Migrations, отмеченный меткой времени. Класс будет иметь метод 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);