Entity Framework codice prima colonna univoca


114

Sto usando Entity Framework 4.3 e utilizzo Code Fist.

Ho una lezione

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

Come faccio a dire a Entity Framework che UserName deve essere univoco durante la creazione della tabella del database? Preferirei usare annotazioni dei dati invece del file di configurazione, se possibile.

Risposte:


257

In Entity Framework 6.1+ puoi usare questo attributo sul tuo modello:

[Index(IsUnique=true)]

Puoi trovarlo in questo spazio dei nomi:

using System.ComponentModel.DataAnnotations.Schema;

Se il campo del modello è una stringa, assicurati che non sia impostato su nvarchar (MAX) in SQL Server o vedrai questo errore con Entity Framework Code First:

La colonna "x" nella tabella "dbo.y" è di un tipo non valido per essere utilizzato come colonna chiave in un indice.

Il motivo è per questo:

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

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

Puoi risolvere questo problema impostando una lunghezza massima della stringa sul tuo modello:

[StringLength(450)]

Il tuo modello apparirà così ora in EF CF 6.1+:

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

Aggiornare:

se usi 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 usa nel tuo modelBuilder:

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

Aggiorna 2

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

Aggiorna 3

per EF6.2 vedere: https://github.com/aspnet/EntityFramework6/issues/274

Aggiorna 4

ASP.NET Core Mvc 2.2 con EF Core:

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

23
Grazie per aver risposto al vecchio post di questo ragazzo con alcune informazioni attuali pertinenti!
Jim Yarbro

3
perché un indice, perché non solo un vincolo?
John Henckel

2
Per rispondere l'indice vs domanda 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
Nota; in Entity Framework Core 1.0.0-preview2-final non è disponibile un metodo di annotazione dei dati - docs.efproject.net/en/latest/modeling/…
Edward Comeau

26

EF non supporta colonne univoche tranne le chiavi. Se stai usando EF Migrations, puoi forzare EF a creare un indice univoco sulla UserNamecolonna (nel codice di migrazione, non tramite annotazioni) ma l'unicità verrà applicata solo nel database. Se si tenta di salvare un valore duplicato, sarà necessario rilevare l'eccezione (violazione del vincolo) attivata dal database.


1
È esattamente quello che stavo cercando! Mi chiedevo se fosse possibile aggiungere tali vincoli utilizzando le migrazioni.
Alex Jorgenson

@Ladislav Mrnka: è possibile anche tramite il metodo Seed?
Raheel Khan

2
Vuoi fornire un esempio? Grazie!
Zero3

10

Dal tuo codice diventa evidente che usi POCO. Non è necessario avere un'altra chiave: puoi aggiungere un indice come suggerito da juFo .
Se utilizzi l'API Fluent invece di attribuire la proprietà UserName, l'annotazione della colonna dovrebbe essere simile a questa:

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

Questo creerà 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 tenti di inserire più utenti con lo stesso UserName, otterrai un'eccezione 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, le annotazioni di colonna non sono disponibili in Entity Framework prima della versione 6.1.


Che ne dici di creare un indice con più colonne utilizzando la configurazione?
FindOutIslamNow

Uno è su UserName, qual è l'altro?
Alexander Christov

5

Tieni presente che in Entity Framework 6.1 (attualmente in versione beta) supporterà IndexAttribute per annotare le proprietà dell'indice che risulteranno automaticamente in un indice (univoco) nelle tue migrazioni Code First.


2

In EF 6.2 usando FluentAPI , puoi usareHasIndex()

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

-13

Soluzione per EF4.3

Nome utente univoco

Aggiungi annotazione dati sulla colonna come:

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

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

IE:

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

Risposte alternative

utilizzando l'annotazione dei dati

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

utilizzando la mappatura

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

25
Stai attento con questa soluzione. L'aggiunta Keydell'attributo alla UserNameproprietà farà sì che la UserNameproprietà diventi la chiave primaria nel database. Solo la UserIdproprietà deve essere contrassegnata con l' Keyattributo. Questa soluzione ti fornirà il comportamento "corretto" sul lato della programmazione mentre ti fornirà una progettazione del database errata.
Alex Jorgenson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.