Création D'un Index Unique avec Entity Framework 6.1 API fluide

J'ai une colonne "Name" qui doit être unqiue. Pas de clé étrangère ou quelque chose comme ça.

EF 6.1 prend enfin en charge la création de tels Index via des Annotations. Cela a déjà été discuté sur SO. Mais il semble que cela ne peut être fait que via des annotations dans les classes. Comment puis-je faire cela en utilisant uniquement L'API Fluent?

Quelque Chose comme ceci:

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();  //???
    }
}
35
demandé sur Hakam Fostok 2014-05-27 18:49:37

6 réponses

REMARQUE: Les EF 6

, Vous pouvez utiliser IndexAttribute, comme mentionné, mais avec Fluent API au lieu de DataAnnotations, qui fera l'affaire:

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

Malheureusement, il n'y a pas d'autre moyen de créer des index uniques en utilisant Fluent API. Il y a un problème ouvert concernant cette fonctionnalité: contraintes uniques (index uniques)


mise à jour: Entity Framework Core

Dans la dernière version D'EF Core, vous pouvez compter sur Fluent API pour spécifier des index sans autres trucs.
HasIndex permet de définir:
modelBuilder 
    .Entity<Person>()
    .HasIndex(x => x.Name);

Par conséquent, il retourne l'objet IndexBuilder Vous pouvez l'utiliser pour d'autres configurations d'index (c'est-à-dire l'unicité):

modelBuilder 
    .Entity<Person>()
    .HasIndex(x => x.Name)
    .IsUnique();
55
répondu Anatolii Gabuza 2018-05-16 11:47:07

Basé sur la réponse D'Anatolii, voici une méthode d'extension pour définir des index uniques plus couramment:

public static class MappingExtensions
{
    public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
    {
        return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
    }
}

Utilisation:

modelBuilder 
    .Entity<Person>() 
    .Property(t => t.Name)
    .IsUnique();

Générera une migration telle que:

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" });
    }
}
35
répondu Geir Sagberg 2015-11-23 15:31:26

Cette réponse ne contient que des informations supplémentaires car il existe déjà de bonnes réponses.

Si vous voulez avoir plusieurs champs uniques dans votre index, vous pouvez y parvenir en ajoutant la propriété Order. Vous devez également vous assurer que vous utilisez le même nom d'index dans toutes vos propriétés (voir uniqueIndex ci-dessous).

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
            }

        )
    );

Maintenant, disons que vous voulez aussi un index sur PropertyTwo.

Le mal façon de le faire serait de commencer un nouveaux ligne this.Property(t => t.PropertyTwo) comme cela annulerait votre index unique.

TOUS vos Index (index et unique) doivent être définis en même temps. Ce serait la bonne façon de le faire :

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

Enfin, si vous aussi vous souhaitez modifier l'ordre de tri de votre index/unique, vous pouvez voir :

Comment ajouter un index sur plusieurs colonnes avec le tri ASC/DESC en utilisant L'API Fluent ?.

27
répondu Maxime 2017-05-23 11:47:13

Dans la nouvelle version de EF qui est 6.2 vous pouvez utiliser HasIndex méthode:

 modelBuilder.Entity<User>().HasIndex(user => user.Email).IsUnique(true);
 modelBuilder.Entity<User>().HasIndex(user => user.UserName).IsUnique(true);

Mise à Jour Pour EF de Base:

 modelBuilder.Entity<User>()
        .HasIndex(b => b.Email)
        .IsUnique();

 modelBuilder.Entity<User>()
        .HasIndex(b => b.UserName)
        .IsUnique();

Microsoft Docs-EF index de base

8
répondu Soheil Alizadeh 2018-08-04 07:03:09

Vous pouvez créer un index unique dans votre fichier de Migration.

Dans Le Gestionnaire De Paquets:

  1. Activer-Migrations
  2. Ajouter-Migration InitialMigration

Cela va créer un nouveau fichier dans votre dossier Migrations qui est horodaté. La classe aura une méthode Up et une méthode Down que vous pouvez utiliser pour créer l'index:

public override void Up()
{
    // ... 
    CreateIndex("tableName", "columnName", unique: true, name: "myIndex");
}

public override void Down()
{
    // ...
    DropIndex("tableName", "myIndex");
}

Pour exécuter le type de migration Update-Database dans le gestionnaire de paquets.

Vous pouvez également ajouter l'index dans le cadre de la migration crée également la table:

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);
4
répondu Dismissile 2014-05-27 15:30:29

Pour moi, en utilisant MVC 5 et EF 6, le point clé était de spécifier une longueur sur la propriété string où je voulais placer l'index.

protected override void OnModelCreating(DbModelBuilder modelBuilder){
    //More stuff
    modelBuilder.Entity<Device>().Property(c => c.Name).HasColumnType("nvarchar").HasMaxLength(50);
    modelBuilder.Entity<Device>().HasIndex(c => c.Name).IsUnique(true); 
}
0
répondu Oscar 2018-09-14 16:02:49