Pertanyaan
Apakah mungkin untuk mendefinisikan batasan unik pada properti menggunakan sintaks yang lancar atau atribut? Jika tidak, apa solusinya?
Saya memiliki kelas pengguna dengan kunci utama, tetapi saya ingin memastikan alamat emailnya juga unik. Apakah ini mungkin tanpa mengedit database secara langsung?
Solusi (berdasarkan jawaban Matt)
public class MyContext : DbContext {
public DbSet<User> Users { get; set; }
public override int SaveChanges() {
foreach (var item in ChangeTracker.Entries<IModel>())
item.Entity.Modified = DateTime.Now;
return base.SaveChanges();
}
public class Initializer : IDatabaseInitializer<MyContext> {
public void InitializeDatabase(MyContext context) {
if (context.Database.Exists() && !context.Database.CompatibleWithModel(false))
context.Database.Delete();
if (!context.Database.Exists()) {
context.Database.Create();
context.Database.ExecuteSqlCommand("alter table Users add constraint UniqueUserEmail unique (Email)");
}
}
}
}
ObjectContext
atauDbContext
.Jawaban:
Sejauh yang saya tahu, tidak ada cara untuk melakukan ini dengan Kerangka Entity saat ini. Namun, ini bukan hanya masalah dengan kendala unik ... Anda mungkin ingin membuat indeks, memeriksa kendala, dan mungkin pemicu dan konstruksi lainnya juga. Berikut adalah pola sederhana yang dapat Anda gunakan dengan pengaturan kode-pertama Anda, meskipun diakui itu bukan basis data agnostik:
Opsi lain adalah jika model domain Anda adalah satu-satunya metode memasukkan / memperbarui data ke dalam basis data Anda, Anda dapat mengimplementasikan sendiri persyaratan keunikan dan membiarkan basis data keluar darinya. Ini adalah solusi yang lebih portabel dan memaksa Anda untuk lebih jelas tentang aturan bisnis Anda dalam kode Anda, tetapi membiarkan database Anda terbuka untuk data yang tidak valid mendapatkan pintu belakang.
sumber
SaveChanges()
), tetapi masih ada kemungkinan penyisipan / pembaruan lainnya tergelincir di antara waktu pemeriksaan keunikan dan waktuSaveChanges()
. Jadi, tergantung pada seberapa kritis misi aplikasi tersebut dan kemungkinan pelanggaran keunikan, mungkin yang terbaik adalah menambahkan kendala ke database.serializable isolation level
(atau penguncian tabel khusus, ugh) yang benar-benar memungkinkan Anda untuk menjamin keunikan dalam kode Anda. Tetapi kebanyakan orang tidak menggunakanserializable isolation level
karena alasan kinerja. Default di MS Sql Server adalahread committed
. Lihat seri 4 bagian mulai dari: michaeljswart.com/2010/03/...Mulai dengan EF 6.1 sekarang dimungkinkan:
Ini akan membuat Anda mendapatkan indeks yang unik alih-alih kendala unik, secara tegas. Untuk tujuan paling praktis, keduanya sama .
sumber
Tidak benar-benar terkait dengan ini tetapi mungkin membantu dalam beberapa kasus.
Jika Anda ingin membuat indeks komposit unik di misalkan 2 kolom yang akan bertindak sebagai kendala untuk tabel Anda, maka pada versi 4.3 Anda dapat menggunakan mekanisme migrasi baru untuk mencapainya:
Pada dasarnya Anda perlu memasukkan panggilan seperti ini di salah satu skrip migrasi Anda:
Sesuatu seperti itu:
sumber
DropIndex("TableName", new[] { "Column1", "Column2" });
Saya melakukan hack lengkap untuk mengeksekusi SQL ketika database sedang dibuat. Saya membuat DatabaseInitializer saya sendiri dan mewarisi dari salah satu initializers yang disediakan.
Itulah satu-satunya tempat yang bisa saya temukan dalam pernyataan SQL saya.
Ini dari CTP4. Saya tidak tahu cara kerjanya di CTP5.
sumber
Hanya mencoba mencari tahu apakah ada cara untuk melakukan ini, satu-satunya cara yang saya temukan sejauh ini adalah menegakkannya sendiri, saya membuat atribut untuk ditambahkan ke setiap kelas di mana Anda memberikan nama bidang yang Anda harus unik:
Kemudian di kelas saya, saya akan menambahkannya:
Akhirnya, saya akan menambahkan metode di repositori saya, di metode Tambahkan atau ketika Menyimpan Perubahan seperti ini:
Tidak terlalu baik karena kita perlu mengandalkan refleksi tetapi sejauh ini adalah pendekatan yang cocok untuk saya! = D
sumber
Juga di 6.1 Anda dapat menggunakan versi sintaks yang lancar dari jawaban @ mihkelmuur seperti:
Metode fasih bukan IMO sempurna tetapi setidaknya mungkin sekarang.
Lebih banyak deet di blog Arthur Vickers http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/
sumber
Cara mudah dalam visual basic menggunakan Migrasi Kode Pertama EF5
Sampel Kelas Publik
Kelas Akhir
Atribut MaxLength sangat penting untuk indeks unik tipe string
Jalankan cmd: perbarui-database -verbose
setelah jalankan cmd: add-migrasi 1
dalam file yang dihasilkan
sumber
Mirip dengan jawaban Tobias Schittkowski tetapi C # dan memiliki kemampuan untuk memiliki beberapa bidang dalam kendala.
Untuk menggunakan ini, cukup tempatkan [Unik] di bidang apa pun yang Anda ingin menjadi unik. Untuk string, Anda harus melakukan sesuatu seperti (perhatikan atribut MaxLength):
karena bidang string default adalah nvarchar (maks) dan itu tidak akan diizinkan dalam kunci.
Untuk beberapa bidang dalam batasan yang dapat Anda lakukan:
Pertama, UniqueAttribute:
Kemudian, sertakan ekstensi yang berguna untuk mendapatkan nama tabel database dari suatu jenis:
Kemudian, penginisialisasi basis data:
sumber
Saya memecahkan masalah dengan refleksi (maaf, teman-teman, VB.Net ...)
Pertama, tentukan atribut UniqueAttribute:
Kemudian, tingkatkan model Anda seperti
Akhirnya, buat DatabaseInitializer kustom (Dalam versi saya, saya membuat kembali perubahan DB pada DB hanya jika dalam mode debug ...). Di DatabaseInitializer ini, indeks secara otomatis dibuat berdasarkan Atribut-Unik:
Mungkin ini membantu ...
sumber
Jika Anda mengganti metode ValidateEntity di kelas DbContext Anda, Anda bisa meletakkan logika di sana juga. Keuntungannya di sini adalah Anda akan memiliki akses penuh ke semua DbSets Anda. Ini sebuah contoh:
sumber
Jika Anda menggunakan EF5 dan masih memiliki pertanyaan ini, solusi di bawah ini menyelesaikannya untuk saya.
Saya menggunakan pendekatan kode pertama, oleh karena itu menempatkan:
dalam skrip migrasi melakukan pekerjaan dengan baik. Ini juga memungkinkan nilai NULL!
sumber
Dengan pendekatan EF Code First, seseorang dapat mengimplementasikan dukungan kendala unik berbasis atribut menggunakan teknik berikut.
Buat atribut marker
Tandai properti yang Anda ingin menjadi unik pada entitas, misalnya
Buat penginisialisasi basis data atau gunakan yang sudah ada untuk membuat batasan unik
Setel konteks basis data Anda untuk menggunakan penginisialisasi ini dalam kode startup (misalnya dalam
main()
atauApplication_Start()
)Solusi mirip dengan mheyman, dengan penyederhanaan tidak mendukung kunci komposit. Untuk digunakan dengan EF 5.0+.
sumber
Solusi Fluent Api:
sumber
Saya menghadapi masalah itu hari ini dan akhirnya saya bisa menyelesaikannya. Saya tidak tahu apakah ini pendekatan yang tepat tetapi setidaknya saya bisa terus:
sumber
Gunakan validator properti unik.
ValidateEntity
tidak dipanggil dalam transaksi basis data yang sama. Oleh karena itu, mungkin ada kondisi lomba dengan entitas lain dalam database. Anda harus meretas EF untuk memaksa transaksi di sekitarSaveChanges
(dan karenanya,ValidateEntity
).DBContext
tidak dapat membuka koneksi secara langsung, tetapiObjectContext
bisa.sumber
Menurut http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx , EF 6.1 akan memiliki IndexAttribute untuk membantu kami .
sumber
Setelah membaca pertanyaan ini, saya memiliki pertanyaan saya sendiri dalam proses mencoba menerapkan atribut untuk menentukan properti sebagai kunci unik seperti Mihkel Müür , Tobias Schittkowski, dan jawaban mheyman menyarankan: Map Entity Framework kode properti ke kolom basis data (CSpace ke SSpace)
Saya akhirnya tiba pada jawaban ini yang dapat memetakan properti skalar dan navigasi ke kolom database dan membuat indeks unik dalam urutan tertentu yang ditunjuk pada atribut. Kode ini mengasumsikan Anda telah mengimplementasikan UniqueAttribute dengan properti Sequence, dan menerapkannya pada properti kelas entitas EF yang harus mewakili kunci unik entitas (selain kunci utama).
Catatan: Kode ini bergantung pada EF versi 6.1 (atau lebih baru) yang mengekspos
EntityContainerMapping
tidak tersedia di versi sebelumnya.sumber
Bagi mereka yang menggunakan konfigurasi kode pertama Anda juga dapat menggunakan objek IndexAttribute sebagai ColumnAnnotation dan mengatur properti IsUnique menjadi true.
Sebagai contoh:
Ini akan membuat indeks unik bernama IX_name pada kolom Nama.
sumber
Maaf atas jawaban yang terlambat tetapi saya merasa senang jika harus bersamamu
Saya telah memposting tentang ini di proyek kode
Secara umum, itu tergantung pada atribut yang Anda letakkan di kelas untuk menghasilkan indeks unik Anda
sumber