Jak utworzyć indeks w Entity Framework 6,2 z najpierw kodem

112

Czy istnieje sposób na utworzenie indeksu we właściwości / kolumnie przy użyciu najpierw kodu, zamiast używania nowego IndexAttribute?

Valo
źródło
5
Indeks to koncepcja bazy danych, a nie koncepcja modelu jednostki. Nawet gdybyś mógł określić indeks za pomocą atrybutu lub za pośrednictwem interfejsu API Fluent, nie zrobiłby to w rzeczywistości niczego w Twojej aplikacji. To byłaby tylko instrukcja dla EF do użycia podczas tworzenia bazy danych. Uważam, że takie instrukcje należą do migracji najpierw kodu, która jest całkowicie związana z manipulowaniem schematem bazy danych.
JC Ford

Odpowiedzi:

84

Otóż ​​26.10.2017 Entity Framework 6.2 został oficjalnie wydany . Obejmuje możliwość łatwego definiowania indeksów poprzez Fluent API. To, że ma być używany, zostało już ogłoszone w wersji beta 6.2.

Teraz możesz użyć HasIndex()metody, a po IsUnique()niej, jeśli powinien to być unikalny indeks.

Tylko małe porównanie (przed / po) przykład:

// 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();

Możliwe jest również oznaczenie indeksu jako skupionego z .IsClustered().


EDYCJA # 1

Dodano przykład dla indeksu wielokolumnowego i dodatkowe informacje, jak oznaczyć indeks jako klastrowy.


EDYCJA # 2

Jako dodatkowe informacje w EF Core 2,1 jest teraz dokładnie taki sam jak w EF 6,2.
Oto artykuł MS Doc jako odniesienie.

ChW
źródło
To jest świetne! Przypuszczam, że jeśli mam indeks wielokolumnowy, będzie to coś takiego: .HasIndex (p => new {p.Name, p.Xyz})
Valo
Och, przepraszam, jasne. Tak powinno być new. Naprawię to.
ChW
Czy mógłbyś pokazać, jak możemy napisać ten sam kod w Core 2.x?
user3417479
O ile wiem, powinien to być ten sam kod, co pod „po” i „indeksie wielokolumnowym”.
ChW
87

Obecnie nie ma „pierwszej klasy obsługi” tworzenia indeksu za pośrednictwem interfejsu API Fluent, ale za pomocą interfejsu Fluent API można oznaczyć właściwości jako mające atrybuty z interfejsu API adnotacji. Umożliwi to dodanie Indexatrybutu za pośrednictwem płynnego interfejsu.

Oto kilka przykładów z elementu roboczego z witryny problemy dla EF.

Utwórz indeks w jednej kolumnie:

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

Wiele indeksów w jednej kolumnie:

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

Indeksy wielokolumnowe:

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

Użycie powyższych technik spowoduje, że .CreateIndex()wywołania będą automatycznie tworzone dla Ciebie w Twojej Up()funkcji podczas tworzenia szkieletu następnej migracji (lub zostaną automatycznie utworzone w bazie danych, jeśli nie używasz migracji).

Scott Chamberlain
źródło
4
co może dodać indeks do kolumny, ale nie spowoduje usunięcia indeksu klastrowego utworzonego na kluczu podstawowym. HasKey tworzy klastrowany indeks na kluczach podstawowych, które nie są domyślnie usuwane. To musi być wyraźnie usunięte z pliku migracji utworzonego przez stwierdzenie clusered: false in .Primarykey(x=>x.id,clustered:false)method
Joy
8
Wypróbowałem HasAnnotationmetodę i NIE ma takiej metody. ale znalazłem metodę, której nazwa HasColumnAnnotationakceptuje podane przez Ciebie parametry. Czy musisz zaktualizować swoją odpowiedź, czy się mylę?
Hakan Fıstık
@HakamFostok Przykład wziąłem bezpośrednio ze strony EF. Być może nazwa została zmieniona w jednej z wersji lub w oryginalnej wersji jest literówka.
Scott Chamberlain
3
Zobacz na dole poniższego linku ze spotkania projektowego na początku tego roku: „Zmień nazwę HasAnnotation na HasColumnAnnotation (plus inne odpowiednie miejsca w bazie kodu).”. entityframework.codeplex.com/…
Zac Charles
36

Utworzyłem kilka metod rozszerzających i opakowałem je w pakiet nuget, aby to znacznie ułatwić.

Zainstaluj EntityFramework.IndexingExtensionspakiet NuGet.

Następnie możesz wykonać następujące czynności:

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

Projekt i kod źródłowy są tutaj . Cieszyć się!

Matt Johnson-Pint
źródło
Naprawdę podoba mi się ten pakiet, ale wydaje się, że czasami brakuje nazwy indeksu po utworzeniu szkieletu w skrypcie up. Pojawił się tylko wtedy, gdy używam 4 lub więcej właściwości w moim indeksie. Pracuję z EF 6.1.3.
Mixxiphoid,
@Mixxiphoid - czy mógłbyś zarejestrować problem tutaj, podając dodatkowe informacje? Upewnij się również, że masz wersję 1.0.1, ponieważ w wersji 1.0.0 wystąpił błąd .
Matt Johnson-Pint,
Mam wersję 1.0.1. Zarejestruję problem, ale nie mogę tego zrobić w tej chwili.
Mixxiphoid,
Jak dodać malejącą kolejność kolumn uczestniczących w indeksie? Domyślnie .HasIndex ("IX_Customers_EmailAddress", IndexOptions.Unique, ... tworzy porządek rosnący dla wszystkich uczestniczących kolumn w indeksie.
GDroid
@GDroid - niestety nie jest to ujawniane przez IndexAttributeklasę EF , więc nie mogę go umieścić w mojej bibliotece.
Matt Johnson-Pint
24

Bez wyraźnej nazwy:

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

O określonej nazwie:

[Index("PostRatingIndex")] 
public int Rating { get; set; }
Hugo Hilário
źródło
Indeks wydaje się być pozbawiony znaczenia :(
Hamed Zakery Miab
1
@HamedZakeryMiab Której wersji Entity Framework używasz? Indeks nie został wycofany.
Hugo Hilário
przepraszam, zapomniałem dołączyć EntityFramework. jest zawarty w tym zestawie. po prostu zdezorientowany NS.
Hamed Zakery Miab
@HamedZakeryMiab tak, to było bardzo zagmatwane! Myślałem, że to część System.DataAnnotations! Zdecydowanie jest to pakiet ramowy podmiotu
AlbatrossCafe
3
pytanie zawiera następujące stwierdzenie instead of using the new IndexAttribute, zauważyłeś to?
Hakan Fıstık
22

Od wersji EF 6.1 atrybut [Index]jest obsługiwany.
Użyj [Index(IsUnique = true)]dla unikalnego indeksu.
Oto link od firmy Microsoft

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

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

    public string DisplayName { get; set; } 
}
Darie Dorlus
źródło
2
Chociaż może to teoretycznie odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj zasadnicze części odpowiedzi i podać link do odniesienia.
Enamul Hassan
@manetsus Bardzo dobrze. Dodałem fragment kodu, aby odzwierciedlić zmianę.
Darie Dorlus
3
Długość łańcucha jest potrzebna, w przeciwnym razie zobaczysz wyjątek „jest typu, który nie może być używany jako kolumna klucza w indeksie”. Mój kolega preferuje rozwiązanie modelBuilder w Conntext, więc nie zaśmiecasz swojej klasy użytkownika, co, jak sądzę, jest poprawne.
pasztet
A co z indeksami z wieloma kolumnami dla unikalności? Całkiem powszechne jest posiadanie wielokolumnowego indeksu Unique Key ...
enorl76
1
@ enorl76 To jest również obsługiwane. Dla każdej kolumny należy użyć atrybutu takiego jak następujący, [Index("IX_BlogIdAndRating", 2)] public int Rating { get; set; } [Index("IX_BlogIdAndRating", 1)] public int BlogId { get; set; } tutaj odniesienie od firmy Microsoft
Darie Dorlus
8

Entity Framework 6

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

I dodaj używając:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;
Guilherme Ferreira
źródło
2

Jeśli nie chcesz używać atrybutów na swoich POCO, zawsze możesz to zrobić w następujący sposób:

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

Tę instrukcję można wykonać w niestandardowej DbInitializerklasie pochodnej. Nie znam jednak żadnego sposobu na zrobienie tego przez Fluent API.

Mert Akcakaya
źródło
1
Jasne, Mert. W tej chwili używam migracji i tam w metodzie Up () możesz również umieścić: CreateIndex ("dbo.Table1", "Column1", true, "Column1_IX") oraz w Down () DropIndex (("dbo.Table1 "," Column1_IX "). Miałem tylko nadzieję, że dodali też płynny interfejs API ...
Valo,
1

Piszę metodę rozszerzenia do użycia w płynnym EF, aby uniknąć dodatkowego kodu:

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

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

następnie użyj tego w ten sposób:

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

lub w ten sposób, jeśli indeks wymaga pewnych konfiguracji:

Property(t => t.CardNo)
    .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });
Omid-RH
źródło
1

Możesz użyć jednego z tych

// Indeksy

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

lub

  this.Property(e => e.IsActive).HasColumnAnnotation(
            "Index",
            new IndexAnnotation(new IndexAttribute("IX_IsActive")));
Nayas Subramanian
źródło