Как сначала создать индекс в Entity Framework 6.2 с кодом

113

Есть ли способ создать индекс для свойства / столбца, используя сначала код вместо нового IndexAttribute?

Valo
источник
5
Индекс - это концепция базы данных, а не концепция модели сущностей. Даже если бы вы могли указать индекс с атрибутом или через свободный API, он ничего бы не сделал в вашем приложении. Это была бы просто инструкция для EF, которую нужно использовать при создании базы данных. Я считаю, что такие инструкции относятся к миграции «сначала код», которая полностью связана с манипулированием схемой базы данных.
JC Ford

Ответы:

85

Что ж, 26.10.2017 Entity Framework 6.2 был официально выпущен . Он включает в себя возможность легко определять индексы через Fluent API. О его использовании уже было объявлено в бета-версии 6.2.

Теперь вы можете использовать HasIndex()метод, а затем IsUnique()указать, должен ли он быть уникальным индексом.

Просто небольшое сравнение (до / после), пример:

// before 
modelBuilder.Entity<Person>()
        .Property(e => e.Name)
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(new IndexAttribute { IsUnique = true }));

// after
modelBuilder.Entity<Person>()
    .HasIndex(p => p.Name)
    .IsUnique();

// multi column index
modelBuilder.Entity<Person>()
    .HasIndex(p => new { p.Name, p.Firstname })
    .IsUnique();

Также можно отметить индекс как кластерный с помощью .IsClustered().


РЕДАКТИРОВАТЬ # 1

Добавлен пример для многоколоночного индекса и дополнительная информация о том, как пометить индекс как кластерный.


РЕДАКТИРОВАТЬ # 2

В качестве дополнительной информации, в EF Core 2.1 он точно такой же, как в EF 6.2 сейчас.
Вот ссылка на MS Doc.

ХЦ
источник
Это круто! Я полагаю, что если бы у меня был многоколоночный индекс, это было бы что-то вроде: .HasIndex (p => new {p.Name, p.Xyz})
Valo
Ой, извините, конечно. Так и должно быть new. Я починю это.
ChW 03
Не могли бы вы показать, как мы можем написать такой же код в Core 2.x?
user3417479 05
Насколько я знаю, это должен быть тот же код, что и в разделах «после» и «многоколоночный индекс».
ChW 05
87

В настоящее время нет «первоклассной поддержки» для создания индекса через свободный API, но вы можете сделать это через свободный API, вы можете пометить свойства как имеющие атрибуты из Annotation API. Это позволит вам добавить Indexатрибут через свободный интерфейс.

Вот несколько примеров из рабочего элемента с сайта Issues для EF.

Создайте индекс для одного столбца:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new IndexAttribute()));

Несколько индексов в одном столбце:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new[]
            {
                new IndexAttribute("Index1"),
                new IndexAttribute("Index2") { IsUnique = true }
            }));

Многоколоночные индексы:

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty1)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName,
        new IndexAnnotation(new IndexAttribute("MyIndex", 1)));

modelBuilder.Entity<MyEntity>()
    .Property(e => e.MyProperty2)
    .HasColumnAnnotation(
        IndexAnnotation.AnnotationName, 
        new IndexAnnotation(new IndexAttribute("MyIndex", 2)));

Использование вышеуказанных методов приведет к тому, что .CreateIndex()вызовы будут автоматически создаваться для вас в вашей Up()функции при формировании следующей миграции (или будут автоматически созданы в базе данных, если вы не используете миграции).

Скотт Чемберлен
источник
4
который может добавить индекс в столбец, но не удалит кластерный индекс, созданный по первичному ключу. HasKey создает кластерный индекс по первичным ключам, которые по умолчанию не удаляются. Это должно быть явно удалено из файла миграции, созданного указанием clusered: false в .Primarykey(x=>x.id,clustered:false)методе
Joy
8
Я пробовал HasAnnotationметод, но такого метода НЕТ. но я нашел метод, имя HasColumnAnnotationкоторого принимает указанные вами параметры. Вам нужно обновить свой ответ или я ошибаюсь?
Hakan Fıstık
@HakamFostok Я взял пример прямо с сайта EF. Возможно, название изменилось в одной из версий или в исходной версии допущена опечатка.
Скотт Чемберлен
3
См. Внизу следующую ссылку с собрания разработчиков в начале этого года: «Переименуйте HasAnnotation в HasColumnAnnotation (плюс другие соответствующие места в базе кода)». entityframework.codeplex.com/…
Зак Чарльз
36

Я создал несколько методов расширения и обернул их в пакет nuget, чтобы сделать это намного проще.

Установите EntityFramework.IndexingExtensions пакет nuget.

Затем вы можете сделать следующее:

public class MyDataContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Entity<Customer>()
        .HasIndex("IX_Customers_Name",          // Provide the index name.
            e => e.Property(x => x.LastName),   // Specify at least one column.
            e => e.Property(x => x.FirstName))  // Multiple columns as desired.

        .HasIndex("IX_Customers_EmailAddress",  // Supports fluent chaining for more indexes.
            IndexOptions.Unique,                // Supports flags for unique and clustered.
            e => e.Property(x => x.EmailAddress)); 
  }
}

Проект и исходный код здесь . Наслаждайтесь!

Мэтт Джонсон-Пинт
источник
Мне очень нравится пакет, но кажется, что имя индекса иногда отсутствует после создания шаблонов в скрипте up. Это появилось у меня только при использовании 4 или более свойств в моем индексе. Работаю с EF 6.1.3.
Mixxiphoid
@Mixxiphoid - не могли бы вы записать здесь проблему с дополнительными сведениями? Также убедитесь, что у вас версия 1.0.1, поскольку в 1.0.0 была ошибка .
Мэтт Джонсон-Пинт,
У меня есть версия 1.0.1. Я запишу проблему в журнал, но пока не могу.
Mixxiphoid
Как добавить порядок столбцов, участвующих в индексе, по убыванию? По умолчанию .HasIndex ("IX_Customers_EmailAddress", IndexOptions.Unique, ... создает возрастающий порядок для всех участвующих столбцов в индексе.
GDroid,
@GDroid - К сожалению, IndexAttributeкласс EF не предоставляет этого , поэтому я не могу включить его в свою библиотеку.
Мэтт Джонсон-
24

Без явного имени:

[Index]
public int Rating { get; set; } 

С конкретным именем:

[Index("PostRatingIndex")] 
public int Rating { get; set; }
Уго Хиларио
источник
Индекс кажется заниженным :(
Hamed Zakery Miab 08
1
@HamedZakeryMiab Какую версию Entity Framework вы используете? Индекс не устарел.
Уго Хиларио
извините, забыл включить EntityFramework. он включен в эту сборку. просто запуталась насчет NS.
Hamed Zakery Miab 08
@HamedZakeryMiab да, это было очень запутанно! Я думал, что это часть System.DataAnnotations! Это определенно пакет фреймворка сущности
AlbatrossCafe
3
вопрос содержит следующее утверждение: instead of using the new IndexAttributeвы это заметили?
Hakan Fıstık
22

Начиная с EF 6.1 этот атрибут [Index]поддерживается.
Используйте [Index(IsUnique = true)]для уникального индекса.
Вот ссылка от Microsoft

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

    [Index(IsUnique = true)] 
    [StringLength(200)] 
    public string Username { get; set; } 

    public string DisplayName { get; set; } 
}
Дари Дорлус
источник
2
Хотя теоретически это может дать ответ на вопрос, было бы предпочтительнее включить сюда основные части ответа и предоставить ссылку для справки.
Энамул Хассан
@manetsus Очень хорошо. Я добавил фрагмент кода, чтобы отразить изменение.
Дари Дорлус 03
3
Длина строки необходима, иначе вы увидите исключение «имеет тип, недопустимый для использования в качестве ключевого столбца в индексе». Мой коллега предпочитает решение modelBuilder для Conntext, чтобы вы не загромождали свой класс User, что, я думаю, действительно.
андрей паштет
А как насчет индексов с несколькими столбцами для уникальности? Довольно часто бывает, что индекс уникального ключа с несколькими столбцами ...
enorl76
1
@ enorl76 Это тоже поддерживается. Для каждого столбца вам нужно будет использовать атрибут, подобный следующему. [Index("IX_BlogIdAndRating", 2)] public int Rating { get; set; } [Index("IX_BlogIdAndRating", 1)] public int BlogId { get; set; } Здесь ссылка от Microsoft
Дари Дорлус,
8

Entity Framework 6

Property(c => c.MyColumn)
        .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_MyIndex")));

И добавьте, используя:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;
Гильерме Феррейра
источник
7

Вы можете использовать аннотацию данных INDEX Code First Data Annotations

Эмре
источник
3
Максимальная длина ключа составляет 900 байтов для nvarchar и 450 байтов для varchar. Если вы сначала используете код, свойства строки будут nvarchar, и вы должны включить атрибут «StringLength», как в [[StringLength (450)]
dunwan
Что касается EF 6.1, это правильный ответ. docs.microsoft.com/en-us/ef/ef6/modeling/code-first/…
Крис Шаллер,
2

Если вы не хотите использовать атрибуты в своих POCO, вы всегда можете сделать это следующим образом:

context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ..."); 

Вы можете выполнить этот оператор в своем DbInitializerпроизводном классе. Однако я не знаю, как это сделать с помощью Fluent API.

Мерт Акчакая
источник
1
Конечно, Мерт. На данный момент я использую миграции, и в методе Up () вы также можете указать: CreateIndex ("dbo.Table1", "Column1", true, "Column1_IX") и в Down () DropIndex (("dbo.Table1 "," Column1_IX "). Я просто надеялся, что они также добавили свободный API ...
Вало
1

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

public static PrimitivePropertyConfiguration HasIndexAnnotation(
    this PrimitivePropertyConfiguration primitivePropertyConfiguration, 
    IndexAttribute indexAttribute = null
    )
{
    indexAttribute = indexAttribute ?? new IndexAttribute();

    return primitivePropertyConfiguration
        .HasColumnAnnotation(
            IndexAnnotation.AnnotationName, 
            new IndexAnnotation(indexAttribute)
        );
}

затем используйте это так:

Property(t => t.CardNo)
    .HasIndexAnnotation();

или вот так, если индексу нужны какие-то конфиги:

Property(t => t.CardNo)
    .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });
Омид-РХ
источник
1

Вы можете использовать один из этих

// Индексы

 this.HasIndex(e => e.IsActive)
            .HasName("IX_IsActive");

или

  this.Property(e => e.IsActive).HasColumnAnnotation(
            "Index",
            new IndexAnnotation(new IndexAttribute("IX_IsActive")));
Наяс Субраманиан
источник