Come creare un indice in Entity Framework 6.2 con il codice prima


112

C'è un modo per creare un indice su una proprietà / colonna usando il codice prima, invece di usare il nuovo IndexAttribute?


5
Un indice è un concetto di database, non un concetto di modello di entità. Anche se potessi specificare un indice con un attributo o tramite l'API fluente, in realtà non farebbe nulla nella tua applicazione. Sarebbe solo un'istruzione per EF da utilizzare durante la creazione del database. Credo che tali istruzioni appartengano alle migrazioni code-first, che riguardano interamente la manipolazione dello schema del database.
JC Ford

Risposte:


84

Ebbene 26.10.2017 Entity Framework 6.2 è stato ufficialmente rilasciato . Include la possibilità di definire facilmente gli indici tramite Fluent API. Come usarlo era già stato annunciato nella beta della 6.2.

Ora puoi usare il HasIndex()metodo, seguito da IsUnique()se dovrebbe essere un indice univoco.

Solo un piccolo esempio di confronto (prima / dopo):

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

È anche possibile contrassegnare l'indice come raggruppato con .IsClustered().


MODIFICA # 1

Aggiunto un esempio per l'indice a più colonne e ulteriori informazioni su come contrassegnare un indice come cluster.


MODIFICA # 2

Come informazioni aggiuntive, in EF Core 2.1 è esattamente lo stesso come in EF 6.2 ora.
Ecco l'artcile MS Doc come riferimento.


È fantastico! Suppongo che se ho un indice a più colonne sarebbe qualcosa del tipo: .HasIndex (p => new {p.Name, p.Xyz})
Valo

Oh, scusa, certo. Dovrebbe essere new. Io lo aggiusterò.
ChW

Potresti per favore mostrare come possiamo scrivere lo stesso codice in Core 2.x?
user3417479

Per quanto ne so dovrebbe essere lo stesso codice mostrato sotto "dopo" e "indice a più colonne".
ChW

87

Attualmente non esiste un "supporto di prima classe" per la creazione di un indice tramite l'API fluente, ma ciò che puoi fare è tramite l'API fluente puoi contrassegnare le proprietà come aventi attributi dall'API di annotazione. Ciò ti consentirà di aggiungere l' Indexattributo tramite un'interfaccia fluente.

Di seguito sono riportati alcuni esempi dall'elemento di lavoro dal sito Problemi per EF.

Crea un indice su una singola colonna:

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

Più indici su una singola colonna:

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

Indici a più colonne:

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

L'uso delle tecniche di cui sopra farà sì che le .CreateIndex()chiamate vengano create automaticamente per te nella tua Up()funzione quando impalcature la tua prossima migrazione (o verranno create automaticamente nel database se non stai usando le migrazioni).


4
ciò potrebbe aggiungere l'indice sulla colonna ma ciò non rimuoverà l'indice cluster creato sulla chiave primaria. La hasKey crea l'indice cluster sulle chiavi primarie che per impostazione predefinita non vengono rimosse. Deve essere rimosso esplicitamente dal file di migrazione creato affermando clusered: false in .Primarykey(x=>x.id,clustered:false)method
Joy

8
Ho provato il HasAnnotationmetodo e non esiste un metodo come questo. ma ho trovato un metodo il cui nome HasColumnAnnotationaccetta i parametri che fornisci. Devi aggiornare la tua risposta o mi sbaglio?
Hakan Fıstık

@HakamFostok Ho preso l'esempio direttamente dal sito EF. Forse il nome è cambiato in una delle versioni o c'è un errore di battitura nella versione originale.
Scott Chamberlain

3
Vedere a destra in fondo al seguente collegamento da una riunione di progettazione all'inizio di quest'anno: "Rename HasAnnotation to HasColumnAnnotation (plus other related places in the code base).". entityframework.codeplex.com/…
Zac Charles,

36

Ho creato alcuni metodi di estensione e li ho inseriti in un pacchetto nuget per renderlo molto più semplice.

Installa il EntityFramework.IndexingExtensionspacchetto nuget.

Quindi puoi fare quanto segue:

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

Il progetto e il codice sorgente sono qui . Godere!


Mi piace molto il pacchetto ma sembra che il nome dell'indice a volte manchi dopo l'impalcatura nello script up. È apparso solo per me quando utilizzo 4 o più proprietà nel mio indice. Sto lavorando con EF 6.1.3.
Mixxiphoid

@Mixxiphoid - registreresti il ​​problema qui con i dettagli di supporto? Assicurati anche di avere la versione 1.0.1, poiché c'era un bug nella 1.0.0.
Matt Johnson-Pint

Ho la versione 1.0.1. Registrerò il problema ma non posso farlo in questo momento.
Mixxiphoid

Come posso aggiungere l'ordine delle colonne partecipanti all'indice a discendente? Per impostazione predefinita .HasIndex ("IX_Customers_EmailAddress", IndexOptions.Unique, ... crea un ordine crescente per tutte le colonne partecipanti nell'indice.
GDroid

@GDroid - Sfortunatamente, questo non è esposto dalla IndexAttributeclasse EF , quindi non posso includerlo nella mia libreria.
Matt Johnson-Pint

24

Senza un nome esplicito:

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

Con un nome specifico:

[Index("PostRatingIndex")] 
public int Rating { get; set; }

L'indice sembra essere deprecato :(
Hamed Zakery Miab

1
@HamedZakeryMiab Quale versione di Entity Framework stai utilizzando? L'indice non è stato deprecato.
Hugo Hilário

scusami, ho dimenticato di includere EntityFramework. è incluso in quell'assemblaggio. solo confuso sul NS.
Hamed Zakery Miab

@HamedZakeryMiab sì, è stato molto confuso! Pensavo facesse parte di System.DataAnnotations! È sicuramente il pacchetto del framework dell'entità
AlbatrossCafe

3
la domanda contiene la seguente affermazione l' instead of using the new IndexAttributehai notato?
Hakan Fıstık,

22

Da EF 6.1 in poi l'attributo [Index]è supportato.
Utilizzare [Index(IsUnique = true)]per indice univoco.
Ecco il collegamento di 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
Sebbene questo possa teoricamente rispondere alla domanda, sarebbe preferibile includere qui le parti essenziali della risposta e fornire il collegamento per riferimento.
Enamul Hassan

@manetsus Molto bene. Ho aggiunto uno snippet di codice per riflettere la modifica.
Darie Dorlus

3
La lunghezza della stringa è necessaria altrimenti viene visualizzato un 'è di un tipo non valido per essere utilizzato come colonna chiave in un'eccezione di indice'. Il mio collega preferisce la soluzione modelBuilder su Conntext in modo da non ingombrare la tua classe User, che immagino sia valida.
andrew pate

Che dire degli indici con più colonne per l'unicità? Abbastanza comune avere un indice di chiave
univoca

1
@ enorl76 Anche questo è supportato. Per ogni colonna dovresti usare un attributo come il seguente, [Index("IX_BlogIdAndRating", 2)] public int Rating { get; set; } [Index("IX_BlogIdAndRating", 1)] public int BlogId { get; set; } qui il riferimento da Microsoft
Darie Dorlus

8

Entity Framework 6

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

E aggiungi usando:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;


2

Se non vuoi usare attributi sui tuoi POCO, puoi sempre farlo come segue:

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

Puoi eseguire questa dichiarazione nella tua abitudine DbInitializer classe derivata . Tuttavia, non conosco alcun modo API fluente per farlo.


1
Certo, Mert. Al momento sto usando le migrazioni e lì nel metodo Up () puoi anche mettere: CreateIndex ("dbo.Table1", "Column1", true, "Column1_IX") e in Down () DropIndex (("dbo.Table1 "," Column1_IX "). Speravo solo che aggiungessero anche un'API fluente ...
Valo

1

Scrivo un metodo di estensione da utilizzare in EF fluente per evitare codice aggiuntivo:

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

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

quindi usalo in questo modo:

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

o come questo se index necessita di alcune configurazioni:

Property(t => t.CardNo)
    .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });

1

Puoi usare uno di questi

// Indici

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

o

  this.Property(e => e.IsActive).HasColumnAnnotation(
            "Index",
            new IndexAnnotation(new IndexAttribute("IX_IsActive")));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.