Kod Entity Framework pierwsza unikatowa kolumna

114

Używam Entity Framework 4.3 i używam Code Fist.

mam klasę

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

Jak powiedzieć Entity Framework, że nazwa użytkownika musi być unikatowa podczas tworzenia tabeli bazy danych? Jeśli to możliwe, wolałbym używać anotacji danych zamiast pliku konfiguracyjnego.

cpoDesign
źródło

Odpowiedzi:

258

W Entity Framework 6.1+ możesz użyć tego atrybutu w swoim modelu:

[Index(IsUnique=true)]

Możesz go znaleźć w tej przestrzeni nazw:

using System.ComponentModel.DataAnnotations.Schema;

Jeśli pole modelu jest ciągiem, upewnij się, że nie jest ustawione na nvarchar (MAX) w programie SQL Server lub zobaczysz ten błąd z Entity Framework Code First:

Kolumna „x” w tabeli „dbo.y” jest typu, którego nie można używać jako kolumny kluczowej w indeksie.

Powód jest taki:

SQL Server zachowuje limit 900 bajtów dla maksymalnego całkowitego rozmiaru wszystkich kolumn klucza indeksu. "

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

Możesz rozwiązać ten problem, ustawiając maksymalną długość łańcucha w swoim modelu:

[StringLength(450)]

Twój model będzie teraz wyglądał tak w EF CF 6.1+:

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

Aktualizacja:

jeśli używasz 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 } }));
    }
  }

i użyj w swoim modelBuilder:

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

Zaktualizuj 2

dla EntityFrameworkCore zobacz także ten temat: https://github.com/aspnet/EntityFrameworkCore/issues/1698

Zaktualizuj 3

dla EF6.2 patrz: https://github.com/aspnet/EntityFramework6/issues/274

Zaktualizuj 4

ASP.NET Core Mvc 2.2 z EF Core:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Unique { get; set; }
juFo
źródło
23
Dziękujemy za odpowiedź na stary post tego gościa i podanie aktualnych informacji!
Jim Yarbro,
3
dlaczego indeks, dlaczego nie tylko ograniczenie?
John Henckel
2
Aby odpowiedzieć na pytanie dotyczące indeksu i "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."
przeciwdziałania
3
Uwaga; w Entity Framework Core 1.0.0-preview2-final metoda adnotacji danych nie jest dostępna - docs.efproject.net/en/latest/modeling/ ...
Edward Comeau
26

EF nie obsługuje unikatowych kolumn z wyjątkiem kluczy. Jeśli używasz migracji EF, możesz zmusić EF do utworzenia unikatowego indeksu w UserNamekolumnie (w kodzie migracji, a nie przez żadną adnotację), ale unikatowość zostanie wymuszona tylko w bazie danych. Jeśli spróbujesz zapisać zduplikowaną wartość, będziesz musiał wychwycić wyjątek (naruszenie ograniczeń) wywołany przez bazę danych.

Ladislav Mrnka
źródło
1
Właśnie tego szukałem! Zastanawiałem się, czy można dodać takie ograniczenia za pomocą migracji.
Alex Jorgenson
@Ladislav Mrnka: Czy jest to również możliwe dzięki metodzie Seed?
Raheel Khan
2
Chcesz podać przykład? Dzięki!
Zero3
10

Z twojego kodu wynika, że ​​używasz POCO. Posiadanie innego klucza jest niepotrzebne: możesz dodać indeks zgodnie z sugestią juFo .
Jeśli używasz Fluent API zamiast przypisywać właściwość UserName, adnotacja kolumny powinna wyglądać następująco:

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

Spowoduje to utworzenie następującego skryptu 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]

Jeśli spróbujesz wstawić wielu użytkowników o tej samej nazwie użytkownika, otrzymasz wyjątek DbUpdateException z następującym komunikatem:

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

Ponownie adnotacje kolumn nie są dostępne w Entity Framework wcześniejszych niż wersja 6.1.

Aleksandra Christowa
źródło
A co z utworzeniem indeksu z wieloma kolumnami przy użyciu konfiguracji?
FindOutIslamNow
Jeden znajduje się w UserName, a co drugi?
Alexander Christov
5

Należy pamiętać, że w Entity Framework 6.1 (obecnie w wersji beta) będzie obsługiwać IndexAttribute w celu dodawania adnotacji do właściwości indeksu, które automatycznie spowodują utworzenie (unikatowego) indeksu w migracji Code First.

Robba
źródło
2

W EF 6.2 używającym FluentAPI możesz używaćHasIndex()

modelBuilder.Entity<User>().HasIndex(u => u.UserName).IsUnique();
Anas Alweish
źródło
-13

Rozwiązanie dla EF4.3

Unikalna nazwa użytkownika

Dodaj adnotację danych do kolumny jako:

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

Unikalny identyfikator , dodałem dekorację [klucz] nad moją kolumną i gotowe. To samo rozwiązanie, co opisane tutaj: https://msdn.microsoft.com/en-gb/data/jj591583.aspx

TO ZNACZY:

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

Alternatywne odpowiedzi

za pomocą adnotacji danych

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

za pomocą mapowania

  mb.Entity<User>()
            .HasKey(i => i.UserId);
        mb.User<User>()
          .Property(i => i.UserId)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
          .HasColumnName("UserId");
cpoDesign
źródło
25
Uważaj na to rozwiązanie. Dodanie Keyatrybutu do UserNamewłaściwości spowoduje, że UserNamewłaściwość stanie się kluczem podstawowym w bazie danych. Tylko UserIdwłaściwość powinna być oznaczona Keyatrybutem. To rozwiązanie zapewni „prawidłowe” zachowanie po stronie programowania, dając jednocześnie niepoprawny projekt bazy danych.
Alex Jorgenson