Kolom unik pertama kode kerangka kerja

114

Saya menggunakan Entity Framework 4.3 dan menggunakan Code Fist.

saya ada kelas

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

Bagaimana cara memberitahu Entity Framework bahwa UserName harus unik saat membuat tabel database? Saya lebih suka menggunakan anotasi data daripada file konfigurasi jika memungkinkan.

cpoDesign
sumber

Jawaban:

257

Dalam Entity Framework 6.1+, Anda dapat menggunakan atribut ini pada model Anda:

[Index(IsUnique=true)]

Anda dapat menemukannya di namespace ini:

using System.ComponentModel.DataAnnotations.Schema;

Jika bidang model Anda adalah string, pastikan tidak disetel ke nvarchar (MAX) di SQL Server atau Anda akan melihat kesalahan ini dengan Kode Kerangka Kerja Entitas Pertama:

Kolom 'x' dalam tabel 'dbo.y' adalah jenis yang tidak valid untuk digunakan sebagai kolom kunci dalam indeks.

Alasannya karena ini:

SQL Server mempertahankan batas 900 byte untuk ukuran total maksimum dari semua kolom kunci indeks. "

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

Anda dapat menyelesaikannya dengan menyetel panjang string maksimum pada model Anda:

[StringLength(450)]

Model Anda akan terlihat seperti ini sekarang di EF CF 6.1+:

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

Memperbarui:

jika Anda menggunakan Fasih:

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

dan gunakan di modelBuilder Anda:

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

Perbarui 2

untuk EntityFrameworkCore, lihat juga topik ini: https://github.com/aspnet/EntityFrameworkCore/issues/1698

Perbarui 3

untuk EF6.2 lihat: https://github.com/aspnet/EntityFramework6/issues/274

Perbarui 4

ASP.NET Core Mvc 2.2 dengan EF Core:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Unique { get; set; }
juFo
sumber
23
Terima kasih telah membalas posting lama orang ini dengan beberapa info terkini yang relevan!
Jim Yarbro
3
mengapa indeks, mengapa tidak hanya menjadi kendala?
John Henckel
2
Untuk menjawab pertanyaan indeks vs perbedaan ... 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
Catatan; di Entity Framework Core 1.0.0-preview2-final metode anotasi data tidak tersedia - docs.efproject.net/en/latest/modeling/…
Edward Comeau
26

EF tidak mendukung kolom unik kecuali kunci. Jika Anda menggunakan Migrasi EF, Anda dapat memaksa EF untuk membuat indeks unik pada UserNamekolom (dalam kode migrasi, bukan dengan anotasi apa pun) tetapi keunikan tersebut hanya akan diberlakukan di database. Jika Anda mencoba untuk menyimpan nilai duplikat, Anda harus menangkap pengecualian (pelanggaran batasan) yang dipicu oleh database.

Ladislav Mrnka
sumber
1
Itulah yang saya cari! Saya bertanya-tanya apakah mungkin menambahkan batasan seperti itu menggunakan migrasi.
Alex Jorgenson
@ Ladislav Mrnka: Apakah ini juga mungkin melalui metode Benih?
Raheel Khan
2
Mau memberi contoh? Terima kasih!
Zero3
10

Dari kode Anda, terlihat jelas bahwa Anda menggunakan POCO. Tidak perlu memiliki kunci lain: Anda dapat menambahkan indeks seperti yang disarankan oleh juFo .
Jika Anda menggunakan Fluent API alih-alih mengaitkan properti UserName, anotasi kolom Anda akan terlihat seperti ini:

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

Ini akan membuat skrip SQL berikut:

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]

Jika Anda mencoba memasukkan beberapa Pengguna yang memiliki NamaPengguna yang sama, Anda akan mendapatkan DbUpdateException dengan pesan berikut:

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

Sekali lagi, penjelasan kolom tidak tersedia di Entity Framework sebelum versi 6.1.

Alexander Christov
sumber
Bagaimana membuat indeks dengan kolom mutliple menggunakan konfigurasi?
FindOutIslamNow
Yang satu ada di UserName, apa yang lainnya?
Alexander Christov
5

Perhatikan bahwa di Entity Framework 6.1 (saat ini dalam versi beta) akan mendukung IndexAttribute untuk menganotasi properti indeks yang secara otomatis akan menghasilkan indeks (unik) di Migrasi Pertama Kode Anda.

Robba
sumber
2

Di EF 6.2 menggunakan FluentAPI , Anda dapat menggunakanHasIndex()

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

Solusi untuk EF4.3

UserName Unik

Tambahkan anotasi data di atas kolom sebagai:

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

ID Unik , saya telah menambahkan dekorasi [Key] di atas kolom saya dan selesai. Solusi yang sama seperti yang dijelaskan di sini: https://msdn.microsoft.com/en-gb/data/jj591583.aspx

YAITU:

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

Jawaban alternatif

menggunakan anotasi data

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

menggunakan pemetaan

  mb.Entity<User>()
            .HasKey(i => i.UserId);
        mb.User<User>()
          .Property(i => i.UserId)
          .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
          .HasColumnName("UserId");
cpoDesign
sumber
25
Berhati-hatilah dengan solusi ini. Menambahkan Keyatribut ke UserNameproperti akan menyebabkan UserNameproperti menjadi kunci utama dalam database. Hanya UserIdproperti yang harus ditandai dengan Keyatribut. Solusi ini akan memberi Anda perilaku 'benar' di sisi pemrograman sambil memberi Anda desain database yang salah.
Alex Jorgenson