2012-05-16 4 views
80

Sto utilizzando Entity Framework 4.3 e utilizzo di Code Fist.Entity Framework code first unique column

Ho una classe

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

Come faccio a dire a Entity Framework quel nome utente deve essere unico per la creazione di tabella di database? Preferirei utilizzare le anotations di dati anziché il file di configurazione, se possibile.

risposta

-13

Soluzione per EF4.3

nome utente unico

Aggiungi annotazione di dati su colonna come:

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

ID univoco , ho aggiunto decorazione [Key] over la mia colonna e fatto. Stessa soluzione come descritto qui: https://msdn.microsoft.com/en-gb/data/jj591583.aspx

IE:

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

alternativa risponde

utilizzando i dati di annotazione

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

utilizzando mappatura

mb.Entity<User>() 
      .HasKey(i => i.UserId); 
     mb.User<User>() 
      .Property(i => i.UserId) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) 
      .HasColumnName("UserId"); 
+24

Attenzione a questa soluzione. Aggiungendo l'attributo 'Key' alla proprietà' UserName', la proprietà 'UserName' diventerà la chiave primaria nel database. Solo la proprietà 'UserId' dovrebbe essere contrassegnata con l'attributo' Key'. Questa soluzione ti darà il comportamento 'corretto' sul lato della programmazione mentre ti fornirai una progettazione di database errata. –

+4

buffo -10 risposta accettata :) –

20

EF non supporta colonne univoche tranne le chiavi. Se si utilizzano le Migrazioni EF, è possibile forzare EF a creare un indice univoco nella colonna UserName (nel codice di migrazione, non in base ad alcuna annotazione) ma l'unicità verrà applicata solo nel database. Se si tenta di salvare il valore duplicato, si dovrà rilevare l'eccezione (violazione del vincolo) attivata dal database.

+1

Questo è esattamente quello che stavo cercando! Mi stavo chiedendo se fosse possibile aggiungere tali vincoli usando le migrazioni. –

+0

@Ladislav Mrnka: questo è possibile anche tramite il metodo Seed? –

+1

Cura di fornire un esempio? Grazie! – Zero3

5

Si noti che in Entity Framework 6.1 (attualmente in versione beta) supporterà l'attributo IndexAttribute per annotare le proprietà dell'indice che genererà automaticamente un indice (univoco) nelle migrazioni Code First.

170

In Entity Framework 6.1+ è possibile utilizzare questo attributo al modello:

[Index(IsUnique=true)] 

lo si può trovare in questo spazio dei nomi:

using System.ComponentModel.DataAnnotations.Schema; 

Se il campo Modello è una stringa, assicurarsi non è impostato su nvarchar (MAX) in SQL Server o verrà visualizzato questo errore con Entity Framework Code First:

Colonna 'x' nella tabella 'dbo.y' i s di un tipo che non è valido per l'uso come colonna chiave in un indice.

Il motivo è a causa di questo:

SQL Server mantiene il limite di 900 byte per la dimensione totale massima di tutte le colonne chiave dell'indice."

(da: http://msdn.microsoft.com/en-us/library/ms191241.aspx)

È possibile risolvere questo impostando una lunghezza massima di stringa del modello:

[StringLength(450)] 

Il modello sarà simile a questa ora a EF CF 6.1 +:

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

Aggiornamento:

se si utilizza 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 } })); 
    } 
    } 

e utilizzare nel vostro ModelBuilder:

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

Aggiornamento 2

per EntityFrameworkCore vedere anche questo argomento: https://github.com/aspnet/EntityFrameworkCore/issues/1698

+14

Grazie per aver risposto al vecchio post di questo tizio con alcune informazioni aggiornate pertinenti! –

+2

Impostazione di StringLength eseguito. Bella risposta. – vidriduch

+1

perché un indice, perché non solo un vincolo? –

8

Dal tuo codice diventa evidente che usi POCO. Non è necessario avere un'altra chiave: è possibile aggiungere un indice come suggerito da juFo.
Se si utilizza API perfetto invece di attribuire proprietà UserName vostra annotazione colonna dovrebbe essere simile a questo:

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

questo modo si crea il seguente script SQL:

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] 

Se si tenta di inserire più utenti con lo stesso nome utente si otterrà un DbUpdateException con il seguente messaggio:

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

Anche in questo caso, la colonna annotati non sono disponibili in Entity Framework prima della versione 6.1.