Comment créer un index dans Entity Framework 6.2 avec du code en premier

112

Existe-t-il un moyen de créer un index sur une propriété / colonne en utilisant d'abord le code, au lieu d'utiliser le nouveau IndexAttribute?

Valo
la source
5
Un index est un concept de base de données, pas un concept de modèle d'entité. Même si vous pouviez spécifier un index avec un attribut ou via l'API fluide, cela ne ferait rien dans votre application. Ce serait juste une instruction à utiliser par EF lors de la création de la base de données. Je crois que de telles instructions appartiennent aux migrations code-first, qui concernent entièrement la manipulation du schéma de base de données.
JC Ford

Réponses:

84

Eh bien 26.10.2017 Entity Framework 6.2 a été officiellement publié . Il inclut la possibilité de définir facilement des index via Fluent API. Ho il est à utiliser était déjà annoncé dans la version bêta de 6.2.

Vous pouvez maintenant utiliser la HasIndex()méthode, suivie de IsUnique()s'il doit s'agir d'un index unique.

Juste un petit exemple de comparaison (avant / après):

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

Il est également possible de marquer l'index comme clusterisé avec .IsClustered().


MODIFIER N ° 1

Ajout d'un exemple d'index multi-colonnes et d'informations supplémentaires sur la façon de marquer un index comme clusterisé.


MODIFIER # 2

Comme information supplémentaire, dans EF Core 2.1, c'est exactement la même chose que dans EF 6.2 maintenant.
Voici l'artcile MS Doc comme référence.

ChW
la source
C'est bien! Je suppose que si j'ai un index multicolonne, ce serait quelque chose comme: .HasIndex (p => new {p.Name, p.Xyz})
Valo
Oh, désolé, bien sûr. Ça devrait être new. Je le réparerai.
ChW
Pourriez-vous s'il vous plaît montrer comment pouvons-nous écrire le même code dans Core 2.x?
user3417479
Autant que je sache, il devrait s'agir du même code que celui indiqué sous "après" et "index multi-colonnes".
ChW
87

Actuellement, il n'y a pas de "support de première classe" pour la création d'un index via l'API fluent, mais ce que vous pouvez faire, c'est via l'API fluent, vous pouvez marquer les propriétés comme ayant des attributs de l'API d'annotation. Cela vous permettra d'ajouter l' Indexattribut via une interface fluide.

Voici quelques exemples de l'élément de travail du site Problèmes pour EF.

Créez un index sur une seule colonne:

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

Plusieurs index sur une seule colonne:

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

Index multi-colonnes:

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'utilisation des techniques ci-dessus entraînera .CreateIndex()la création automatique d'appels pour vous dans votre Up()fonction lors de l'échafaudage de votre prochaine migration (ou la création automatique dans la base de données si vous n'utilisez pas de migrations).

Scott Chamberlain
la source
4
cela peut ajouter l'index sur la colonne, mais cela ne supprimera pas l'index cluster créé sur la clé primaire. HasKey crée l'index cluster sur les clés primaires qui ne sont pas supprimées par défaut. Cela doit être explicitement supprimé du fichier de migration créé en indiquant clusered: false dans la .Primarykey(x=>x.id,clustered:false)méthode
Joy
8
J'ai essayé la HasAnnotationméthode et il n'y a AUCUNE méthode comme celle-ci. mais j'ai trouvé une méthode dont le nom HasColumnAnnotationaccepte les paramètres que vous fournissez. Avez-vous besoin de mettre à jour votre réponse ou ai-je tort?
Hakan Fıstık
@HakamFostok J'ai pris l'exemple directement sur le site EF. Peut-être que le nom a changé dans l'une des versions ou qu'il y a une faute de frappe dans la version originale.
Scott Chamberlain
3
Voir en bas du lien suivant d'une réunion de conception plus tôt cette année: "Renommer HasAnnotation en HasColumnAnnotation (plus d'autres endroits pertinents dans la base de code).". entityframework.codeplex.com/…
Zac Charles
36

J'ai créé quelques méthodes d'extension et les ai enveloppées dans un package nuget pour rendre cela beaucoup plus facile.

Installez le EntityFramework.IndexingExtensionspackage nuget.

Ensuite, vous pouvez faire ce qui suit:

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

Le projet et le code source sont ici . Prendre plaisir!

Matt Johnson-Pint
la source
J'aime beaucoup le package mais il semble que le nom de l'index manque parfois après l'échafaudage dans le script up. Cela ne m'est apparu que lors de l'utilisation de 4 propriétés ou plus dans mon index. Je travaille avec EF 6.1.3.
Mixxiphoid
@Mixxiphoid - pourriez-vous s'il vous plaît enregistrer le problème ici avec les détails à l'appui? Assurez-vous également d'avoir la version 1.0.1, car il y avait un bogue dans la 1.0.0.
Matt Johnson-Pint
J'ai la version 1.0.1. Je vais enregistrer le problème, mais je ne peux pas le faire pour le moment.
Mixxiphoid
Comment ajouter l'ordre des colonnes participant à l'index à l'ordre décroissant? Par défaut .HasIndex ("IX_Customers_EmailAddress", IndexOptions.Unique, ... crée un ordre croissant pour toutes les colonnes participantes dans l'index.
GDroid
@GDroid - Malheureusement, cela n'est pas exposé par la IndexAttributeclasse d'EF , je ne peux donc pas l'inclure dans ma bibliothèque.
Matt Johnson-Pint
24

Sans nom explicite:

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

Avec un nom spécifique:

[Index("PostRatingIndex")] 
public int Rating { get; set; }
Hugo Hilário
la source
L'index semble être déprécié :(
Hamed Zakery Miab
1
@HamedZakeryMiab Quelle version d'Entity Framework utilisez-vous? L'index n'était pas obsolète.
Hugo Hilário
excusez-moi, j'ai oublié d'inclure EntityFramework. il est inclus dans cette assemblée. juste confus au sujet de la NS.
Hamed Zakery Miab
@HamedZakeryMiab ouais c'était super déroutant! Je pensais que cela faisait partie de System.DataAnnotations! C'est définitivement le package de cadre d'entité
AlbatrossCafe
3
la question contient la déclaration suivante l' instead of using the new IndexAttributeavez-vous remarqué?
Hakan Fıstık
22

À partir d'EF 6.1, l'attribut [Index]est pris en charge.
Utiliser [Index(IsUnique = true)]pour un index unique.
Voici le lien de 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
la source
2
Bien que cela puisse théoriquement répondre à la question, il serait préférable d'inclure ici les parties essentielles de la réponse et de fournir le lien pour référence.
Enamul Hassan
@manetsus Très bien. J'ai ajouté un extrait de code pour refléter le changement.
Darie Dorlus
3
La longueur de la chaîne est nécessaire, sinon vous voyez une exception «est d'un type qui n'est pas valide pour être utilisé comme colonne clé dans un index». Mon collègue préfère la solution modelBuilder sur le Conntext pour ne pas encombrer votre classe User, ce qui, je suppose, est valide.
andrew pate le
Qu'en est-il des index avec plusieurs colonnes pour l'unicité? Assez commun d'avoir un index de clé unique à plusieurs colonnes ...
enorl76
1
@ enorl76 Cela est également pris en charge. Pour chaque colonne, vous devez utiliser un attribut comme le suivant, [Index("IX_BlogIdAndRating", 2)] public int Rating { get; set; } [Index("IX_BlogIdAndRating", 1)] public int BlogId { get; set; } ici la référence de Microsoft
Darie Dorlus
8

Entity Framework 6

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

Et ajoutez en utilisant:

using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;
Guilherme Ferreira
la source
7

Vous pouvez utiliser l'annotation de données INDEX Code First Data Annotations

Emre
la source
3
La longueur maximale de la clé est de 900 octets pour nvarchar et de 450 octets pour varchar. Si vous utilisez d'abord le code, les propriétés de la chaîne seront nvarchar et vous devez inclure l'attribut "StringLength" comme dans [[StringLength (450)]
dunwan
Depuis EF 6.1, c'est la bonne réponse. docs.microsoft.com/en-us/ef/ef6/modeling/code-first/…
Chris Schaller
2

Si vous ne souhaitez pas utiliser d'attributs sur vos POCO, vous pouvez toujours le faire comme suit:

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

Vous pouvez exécuter cette instruction dans votre DbInitializerclasse dérivée personnalisée . Cependant, je ne connais aucun moyen de l'API Fluent de le faire.

Mert Akcakaya
la source
1
Bien sûr, Mert. Pour le moment j'utilise des migrations et là, dans la méthode Up (), vous pouvez également mettre: CreateIndex ("dbo.Table1", "Column1", true, "Column1_IX") et Down () DropIndex (("dbo.Table1" "," Column1_IX "). J'espérais juste qu'ils ont ajouté une API fluide aussi ...
Valo
1

J'écris une méthode d'extension à utiliser dans EF fluent pour éviter du code supplémentaire:

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

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

puis utilisez-le comme ceci:

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

ou comme ceci si l'index a besoin de certaines configurations:

Property(t => t.CardNo)
    .HasIndexAnnotation(new IndexAttribute("IX_Account") { IsUnique = true });
Omid-RH
la source
1

Vous pouvez utiliser l'un de ces

// Index

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

ou

  this.Property(e => e.IsActive).HasColumnAnnotation(
            "Index",
            new IndexAnnotation(new IndexAttribute("IX_IsActive")));
Nayas Subramanian
la source