web-dev-qa-db-fra.com

Première colonne unique du code Entity Framework

J'utilise Entity Framework 4.3 et j'utilise Code Fist.

J'ai un cours

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

Comment puis-je dire à Entity Framework que UserName doit être unique lors de la création d'une table de base de données? Je préférerais utiliser des annotations de données plutôt qu'un fichier de configuration si possible.

102
cpoDesign

Dans Entity Framework 6.1+, vous pouvez utiliser cet attribut sur votre modèle:

[Index(IsUnique=true)]

Vous pouvez le trouver dans cet espace de noms:

using System.ComponentModel.DataAnnotations.Schema;

Si votre champ de modèle est une chaîne, assurez-vous qu'il n'est pas défini sur nvarchar (MAX) dans SQL Server ou vous verrez cette erreur avec Entity Framework Code First:

La colonne 'x' de la table 'dbo.y' est d'un type non valide pour une utilisation en tant que colonne clé dans un index.

La raison est pour cela:

SQL Server conserve la limite de 900 octets pour la taille totale maximale de toutes les colonnes de clé d'index. "

(de: http://msdn.Microsoft.com/en-us/library/ms191241.aspx )

Vous pouvez résoudre ce problème en définissant une longueur de chaîne maximale sur votre modèle:

[StringLength(450)]

Votre modèle ressemblera maintenant à ceci dans EF CF 6.1+:

public class User
{
   public int UserId{get;set;}
   [StringLength(450)]
   [Index(IsUnique=true)]
   public string UserName{get;set;}
}

Mise à jour:

si vous utilisez Fluent:

  public class UserMap : EntityTypeConfiguration<User>
  {
    public UserMap()
    {
      // ....
      Property(x => x.Name).IsRequired().HasMaxLength(450).HasColumnAnnotation("Index", new IndexAnnotation(new[] { new IndexAttribute("Index") { IsUnique = true } }));
    }
  }

et utilisez dans votre modelBuilder:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  // ...
  modelBuilder.Configurations.Add(new UserMap());
  // ...
}

Mise à jour 2

pour EntityFrameworkCore, voir également ce sujet: https://github.com/aspnet/EntityFrameworkCore/issues/1698

Mise à jour 3

pour EF6.2, voir: https://github.com/aspnet/EntityFramework6/issues/274

Mise à jour 4

ASP.NET Core Mvc 2.2 avec EF Core:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Unique { get; set; }
223
juFo

EF ne prend pas en charge les colonnes uniques sauf les clés. Si vous utilisez EF Migrations, vous pouvez forcer EF à créer un index unique sur la colonne UserName (dans le code de migration, pas par une annotation), mais l'unicité ne sera appliquée que dans la base de données. Si vous essayez de sauvegarder une valeur en double, vous devrez intercepter une exception (violation de contrainte) déclenchée par la base de données.

25
Ladislav Mrnka

À partir de votre code, il devient évident que vous utilisez POCO. Il est inutile d'avoir une autre clé: vous pouvez ajouter un index comme suggéré par juFo .
Si vous utilisez l'API Fluent au lieu d'attribuer la propriété UserName, votre annotation de colonne devrait ressembler à ceci:

this.Property(p => p.UserName)
    .HasColumnAnnotation("Index", new IndexAnnotation(new[] { 
        new IndexAttribute("Index") { IsUnique = true } 
    }
));

Cela créera le script SQL suivant:

CREATE UNIQUE NONCLUSTERED INDEX [Index] ON [dbo].[Users]
(
    [UserName] ASC
)
WITH (
    PAD_INDEX = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    IGNORE_DUP_KEY = OFF, 
    DROP_EXISTING = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]

Si vous essayez d'insérer plusieurs utilisateurs ayant le même nom d'utilisateur, vous obtiendrez une exception DbUpdateException avec le message suivant:

Cannot insert duplicate key row in object 'dbo.Users' with unique index 'Index'. 
The duplicate key value is (...).
The statement has been terminated.

Là encore, les annotations de colonne ne sont pas disponibles dans Entity Framework avant la version 6.1.

9
Alexander Christov

Notez que dans Entity Framework 6.1 (actuellement en version bêta) prendra en charge IndexAttribute pour annoter les propriétés de l'index, ce qui donnera automatiquement un index (unique) dans vos migrations Code First.

5
Robba