Code Entity Framework première colonne unique

114

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 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 anotations de données au lieu du fichier de configuration si possible.

cpoDesign
la source

Réponses:

257

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 qui n'est pas valide pour être utilisée comme colonne clé dans un index.

La raison est à cause de ceci:

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

(à partir 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;}
}

Mettre à 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 cette rubrique: 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; }
juFo
la source
23
Merci d'avoir répondu à l'ancien message de ce gars avec des informations actuelles pertinentes!
Jim Yarbro
3
pourquoi un index, pourquoi pas juste une contrainte?
John Henckel
2
Pour répondre à la question de l'index vs contraint ... MSDN: "There are no significant differences between creating a UNIQUE constraint and creating a unique index that is independent of a constraint. Data validation occurs in the same manner, and the query optimizer does not differentiate between a unique index created by a constraint or manually created. However, creating a UNIQUE constraint on the column makes the objective of the index clear." msdn.microsoft.com/en-us/library/ms187019.aspx
user919426
3
Remarque; dans Entity Framework Core 1.0.0-preview2-final, une méthode d'annotations de données n'est pas disponible - docs.efproject.net/en/latest/modeling/…
Edward Comeau
26

EF ne prend pas en charge les colonnes uniques à l'exception des clés. Si vous utilisez des migrations EF, vous pouvez forcer EF à créer un index unique sur la UserNamecolonne (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 d'enregistrer une valeur en double, vous devrez intercepter l'exception (violation de contrainte) déclenchée par la base de données.

Ladislav Mrnka
la source
1
C'est exactement ce que je cherchais! Je me demandais s'il était possible d'ajouter de telles contraintes à l'aide de migrations.
Alex Jorgenson
@Ladislav Mrnka: Est-ce également possible via la méthode Seed?
Raheel Khan
2
Voulez-vous donner un exemple? Merci!
Zero3
10

À partir de votre code, il devient évident que vous utilisez POCO. Il n'est pas nécessaire 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 doit 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.

Alexandre Christov
la source
Qu'en est-il de la création d'un index avec plusieurs colonnes à l'aide de la configuration?
FindOutIslamNow
L'un est sur UserName, quel est l'autre?
Alexander Christov
5

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

Robba
la source
2

Dans EF 6.2 utilisant FluentAPI , vous pouvez utiliserHasIndex()

modelBuilder.Entity<User>().HasIndex(u => u.UserName).IsUnique();
Anas Alweish
la source
-13

Solution pour EF4.3

Nom d'utilisateur unique

Ajoutez une annotation de données sur la colonne comme:

 [Index(IsUnique = true)]
 [MaxLength(255)] // for code-first implementations
 public string UserName{get;set;}

ID unique , j'ai ajouté une décoration [Clé] sur ma colonne et c'est fait. Même solution que celle décrite ici: https://msdn.microsoft.com/en-gb/data/jj591583.aspx

C'EST À DIRE:

[Key]
public int UserId{get;set;}

Réponses alternatives

utilisation de l'annotation de données

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column("UserId")]

en utilisant la cartographie

  mb.Entity<User>()
            .HasKey(i => i.UserId);
        mb.User<User>()
          .Property(i => i.UserId)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
          .HasColumnName("UserId");
cpoDesign
la source
25
Soyez prudent avec cette solution. L'ajout de l' Keyattribut à la UserNamepropriété fera que la UserNamepropriété deviendra la clé primaire dans la base de données. Seule la UserIdpropriété doit être marquée avec l' Keyattribut. Cette solution vous donnera le comportement «correct» du côté de la programmation tout en vous donnant une conception de base de données incorrecte.
Alex Jorgenson