Kesan saya sampai saat ini adalah bahwa a DbContext
dimaksudkan untuk mewakili basis data Anda, dan dengan demikian, jika aplikasi Anda menggunakan satu basis data, Anda hanya menginginkan satu DbContext
.
Namun, beberapa rekan ingin membagi area fungsional ke dalam DbContext
kelas yang terpisah .
Saya percaya ini berasal dari tempat yang baik - keinginan untuk menjaga kode lebih bersih - tetapi tampaknya tidak stabil. Naluriku mengatakan itu adalah ide yang buruk, tapi sayangnya, naluriku bukanlah kondisi yang cukup untuk keputusan desain.
Jadi saya mencari:
A) contoh nyata mengapa ini bisa menjadi ide yang buruk;
B) menjamin bahwa ini semua akan berjalan dengan baik.
entity-framework
ef-code-first
entity-framework-4.3
dbcontext
Josh Schultz
sumber
sumber
Jawaban:
Anda dapat memiliki banyak konteks untuk satu basis data. Sebagai contoh, ini dapat berguna jika basis data Anda mengandung banyak skema basis data dan Anda ingin menangani masing-masingnya sebagai area mandiri yang terpisah.
Masalahnya adalah ketika Anda ingin menggunakan kode terlebih dahulu untuk membuat database Anda - hanya konteks tunggal dalam aplikasi Anda yang bisa melakukannya. Trik untuk ini biasanya satu konteks tambahan yang mengandung semua entitas Anda yang hanya digunakan untuk pembuatan basis data. Konteks aplikasi nyata Anda yang hanya berisi himpunan bagian entitas Anda harus memiliki penginisialisasi basis data yang disetel ke nol.
Ada masalah lain yang akan Anda lihat ketika menggunakan beberapa tipe konteks - misalnya tipe entitas bersama dan perpindahannya dari satu konteks ke konteks lainnya, dll. Secara umum dimungkinkan, itu dapat membuat desain Anda jauh lebih bersih dan memisahkan area fungsional yang berbeda tetapi memiliki biaya dalam kompleksitas tambahan.
sumber
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
berfungsi sekarang.Saya menulis jawaban ini sekitar empat tahun lalu dan pendapat saya belum berubah. Namun sejak itu ada perkembangan signifikan di bidang layanan mikro. Saya menambahkan catatan spesifik layanan mikro di akhir ...
Saya akan mempertimbangkan ide itu, dengan pengalaman dunia nyata untuk mendukung suara saya.
Saya dibawa ke aplikasi besar yang memiliki lima konteks untuk satu database. Pada akhirnya, kami akhirnya menghapus semua konteks kecuali satu - kembali ke satu konteks.
Pada awalnya ide tentang berbagai konteks sepertinya ide yang bagus. Kami dapat memisahkan akses data kami ke dalam domain dan menyediakan beberapa konteks ringan bersih. Kedengarannya seperti DDD, kan? Ini akan menyederhanakan akses data kami. Argumen lain adalah untuk kinerja karena kita hanya mengakses konteks yang kita butuhkan.
Namun dalam praktiknya, seiring pertumbuhan aplikasi kami, banyak dari tabel kami berbagi hubungan di berbagai konteks kami. Misalnya, kueri ke tabel A dalam konteks 1 juga diminta bergabung dengan tabel B dalam konteks 2.
Ini meninggalkan kita dengan beberapa pilihan yang buruk. Kita bisa menduplikasi tabel dalam berbagai konteks. Kami mencoba ini. Ini menciptakan beberapa masalah pemetaan termasuk kendala EF yang mengharuskan setiap entitas memiliki nama yang unik. Jadi kami berakhir dengan entitas bernama Person1 dan Person2 dalam konteks yang berbeda. Orang dapat berargumen bahwa ini adalah desain yang buruk di pihak kami, tetapi terlepas dari upaya terbaik kami, ini adalah bagaimana aplikasi kami sebenarnya tumbuh di dunia nyata.
Kami juga mencoba menanyakan kedua konteks untuk mendapatkan data yang kami butuhkan. Misalnya, logika bisnis kami akan meminta setengah dari yang diperlukan dari konteks 1 dan setengah lainnya dari konteks 2. Ini memiliki beberapa masalah besar. Alih-alih melakukan satu permintaan terhadap satu konteks, kami harus melakukan beberapa permintaan di berbagai konteks. Ini memiliki penalti performa nyata.
Pada akhirnya, kabar baiknya adalah mudah untuk menghapus berbagai konteks. Konteksnya dimaksudkan untuk menjadi objek yang ringan. Jadi saya tidak berpikir kinerja adalah argumen yang bagus untuk banyak konteks. Dalam hampir semua kasus, saya percaya satu konteks lebih sederhana, lebih kompleks, dan kemungkinan akan berkinerja lebih baik, dan Anda tidak perlu menerapkan banyak upaya untuk membuatnya bekerja.
Saya memikirkan satu situasi di mana banyak konteks bisa berguna. Konteks terpisah dapat digunakan untuk memperbaiki masalah fisik dengan database yang sebenarnya berisi lebih dari satu domain. Idealnya, konteks akan menjadi satu-ke-satu ke domain, yang akan menjadi satu-ke-satu ke database. Dengan kata lain, jika satu set tabel sama sekali tidak terkait dengan tabel lain dalam database yang diberikan, mereka mungkin harus ditarik ke dalam database yang terpisah. Saya menyadari ini tidak selalu praktis. Tetapi jika satu set tabel sangat berbeda sehingga Anda akan merasa nyaman memisahkan mereka ke dalam database yang terpisah (tetapi Anda memilih untuk tidak melakukannya) maka saya dapat melihat kasus untuk menggunakan konteks yang terpisah, tetapi hanya karena sebenarnya ada dua domain yang terpisah.
Mengenai layanan mikro, satu konteks tunggal masih masuk akal. Namun, untuk layanan mikro, setiap layanan akan memiliki konteksnya sendiri yang hanya mencakup tabel basis data yang relevan dengan layanan itu. Dengan kata lain, jika layanan x mengakses tabel 1 dan 2, dan layanan y mengakses tabel 3 dan 4, setiap layanan akan memiliki konteks uniknya sendiri yang mencakup tabel khusus untuk layanan tersebut.
Saya tertarik dengan pemikiran Anda.
sumber
Utas ini baru saja menggelegak di StackOverflow dan jadi saya ingin menawarkan jaminan "B) lain bahwa ini semua akan baik-baik saja" :)
Saya melakukan ini persis dengan pola DDD Bounded Context. Saya telah menulisnya di buku saya, Programming Entity Framework: DbContext dan itu adalah fokus modul 50 menit dalam salah satu kursus saya di Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
sumber
Membedakan konteks dengan mengatur skema default
Di EF6 Anda dapat memiliki beberapa konteks, cukup tentukan nama untuk skema database default dalam
OnModelCreating
metodeDbContext
kelas yang Anda peroleh (di mana konfigurasi Fluent-API adalah). Ini akan bekerja di EF6:Contoh ini akan menggunakan "Pelanggan" sebagai awalan untuk tabel basis data Anda (bukan "dbo"). Lebih penting lagi, ini juga akan mengawali
__MigrationHistory
tabel, misalnyaCustomer.__MigrationHistory
. Jadi Anda dapat memiliki lebih dari satu__MigrationHistory
tabel dalam satu database, satu untuk setiap konteks. Jadi perubahan yang Anda buat untuk satu konteks tidak akan berantakan dengan yang lain.Saat menambahkan migrasi, tentukan nama yang sepenuhnya memenuhi syarat kelas konfigurasi Anda (berasal dari
DbMigrationsConfiguration
) sebagai parameter dalamadd-migration
perintah:Sebuah kata pendek pada tombol konteks
Menurut artikel MSDN ini " Bab - Banyak Model Menargetkan Database yang Sama " EF 6 mungkin akan menangani situasi bahkan jika hanya ada satu
MigrationHistory
tabel, karena dalam tabel terdapat kolom ContextKey untuk membedakan migrasi.Namun saya lebih suka memiliki lebih dari satu
MigrationHistory
tabel dengan menentukan skema default seperti yang dijelaskan di atas.Menggunakan folder migrasi terpisah
Dalam skenario seperti itu Anda mungkin juga ingin bekerja dengan folder "Migrasi" yang berbeda di proyek Anda. Anda dapat mengatur
DbMigrationsConfiguration
kelas turunan Anda sesuai dengan menggunakanMigrationsDirectory
properti:Ringkasan
Semua dalam semua, Anda dapat mengatakan bahwa semuanya dipisahkan dengan bersih: Konteks, folder Migrasi dalam proyek dan tabel dalam database.
Saya akan memilih solusi seperti itu, jika ada kelompok entitas yang merupakan bagian dari topik yang lebih besar, tetapi tidak terkait (melalui kunci asing) satu sama lain.
Jika kelompok-kelompok entitas tidak memiliki sesuatu untuk dilakukan satu sama lain, saya akan membuat database terpisah untuk masing-masing dan mengaksesnya dalam proyek yang berbeda, mungkin dengan satu konteks tunggal di setiap proyek.
sumber
Contoh sederhana untuk mencapai di bawah ini:
Hanya lingkup properti dalam konteks utama: (digunakan untuk membuat dan memelihara DB) Catatan: Cukup gunakan protected: (Entitas tidak diekspos di sini)
MonitorContext: Paparkan Entitas terpisah di sini
Model diagnostik:
Jika Anda suka, Anda dapat menandai semua entitas sebagai terlindungi di dalam ApplicationDbContext utama, lalu buat konteks tambahan yang diperlukan untuk setiap pemisahan skema.
Mereka semua menggunakan string koneksi yang sama, namun mereka menggunakan koneksi terpisah, jadi jangan lintas transaksi dan waspadai masalah penguncian. Umumnya pemisahan desain Anda jadi ini seharusnya tidak terjadi.
sumber
DbSet<x>
definisi itu secara manual . Saya melakukannya di kelas parsial yang sesuai dengan apa yang dibuat oleh Desainer EF.Pengingat: Jika Anda menggabungkan beberapa konteks, pastikan Anda memotong dan menempelkan semua fungsi di berbagai
RealContexts.OnModelCreating()
Anda ke dalam tunggal AndaCombinedContext.OnModelCreating()
.Saya hanya membuang-buang waktu untuk mencari tahu mengapa hubungan penghapusan kaskade saya tidak dipertahankan hanya untuk mengetahui bahwa saya belum memindahkan
modelBuilder.Entity<T>()....WillCascadeOnDelete();
kode dari konteks saya yang sebenarnya ke dalam konteks gabungan saya.sumber
OtherContext.OnModelCreating()
dari konteks gabungan Anda?Naluri saya mengatakan hal yang sama ketika saya menemukan desain ini.
Saya sedang mengerjakan basis kode di mana ada tiga dbContexts ke satu database. 2 dari 3 dbcontext bergantung pada informasi dari 1 dbcontext karena ini menyajikan data administratif. Desain ini telah menempatkan kendala pada bagaimana Anda dapat meminta data Anda. Saya mengalami masalah ini di mana Anda tidak dapat bergabung di seluruh dbcontexts. Alih-alih apa yang harus Anda lakukan adalah meminta dua dbcontext yang terpisah kemudian melakukan join di memori atau beralih melalui keduanya untuk mendapatkan kombinasi keduanya sebagai hasil yang ditetapkan. Masalah dengan itu alih-alih meminta untuk hasil tertentu yang ditetapkan Anda sekarang memuat semua catatan Anda ke dalam memori dan kemudian melakukan gabungan terhadap dua set hasil dalam memori. Ini benar-benar dapat memperlambat segalanya.
Saya akan mengajukan pertanyaan "hanya karena Anda bisa, bukan? "
Lihat artikel ini untuk masalah yang saya temui terkait dengan desain ini. Ekspresi LINQ yang ditentukan berisi referensi ke kueri yang terkait dengan konteks yang berbeda
sumber
Terinspirasi oleh Artikel DDD MSDN Mag [@JulieLerman 2013] [1]
sumber
Dalam kode terlebih dahulu, Anda dapat memiliki beberapa DBContext dan hanya satu database. Anda hanya perlu menentukan string koneksi di konstruktor.
sumber
Sedikit "kebijaksanaan". Saya memiliki basis data yang menghadap ke internet, dan aplikasi internal. Saya memiliki konteks untuk setiap wajah. Itu membantu saya untuk menjaga pemisahan, disiplin aman.
sumber
Saya ingin membagikan sebuah kasus, di mana saya pikir kemungkinan memiliki beberapa DBContexts dalam database yang sama masuk akal.
Saya punya solusi dengan dua database. Salah satunya adalah untuk data domain kecuali informasi pengguna. Yang lain hanya untuk informasi pengguna. Divisi ini terutama didorong oleh Peraturan Perlindungan Data Umum UE . Dengan memiliki dua basis data, saya dapat dengan bebas memindahkan data domain (misalnya dari Azure ke lingkungan pengembangan saya) selama data pengguna tetap berada di satu tempat yang aman.
Sekarang untuk basis data pengguna, saya telah menerapkan dua skema melalui EF. Satu adalah standar yang disediakan oleh kerangka kerja AspNet Identity. Yang lain adalah kami sendiri menerapkan hal lain yang terkait pengguna. Saya lebih suka solusi ini daripada memperluas skema ApsNet, karena saya dapat dengan mudah menangani perubahan di masa depan untuk AspNet Identity dan pada saat yang sama pemisahan membuatnya menjadi jelas bagi para programmer, bahwa "informasi pengguna kami sendiri" masuk dalam skema pengguna tertentu yang telah kami tentukan .
sumber
Huh, menghabiskan cukup banyak waktu pada masalah dengan konteks DB yang terpisah untuk setiap skema DB, berharap itu akan membantu orang lain ...
Saya baru-baru ini mulai mengerjakan proyek yang memiliki satu database dengan 3 skema (pendekatan pertama DB), salah satunya untuk manajemen pengguna. Ada konteks DB scaffolded dari masing-masing skema terpisah. Tentu saja, pengguna juga terkait dengan skema lain, misalnya. skema KB memiliki Topik tabel, yang telah "dibuat oleh", "terakhir dimodifikasi oleh" dll. FK untuk skema identitas, pengguna tabel.
Objek-objek ini dimuat secara terpisah dalam C #, pertama, topik dimuat dari 1 konteks, kemudian pengguna dimuat melalui ID pengguna dari konteks db lainnya - tidak baik, harus memperbaikinya! (mirip dengan menggunakan beberapa dbcontext dalam database yang sama dengan EF 6 )
Pertama, saya mencoba menambahkan instruksi FK yang hilang dari skema identitas ke skema KB, ke EF modelBuilder dalam konteks KB DB. Sama seperti jika hanya ada 1 konteks, tapi saya pisahkan menjadi 2.
Itu tidak berhasil, karena konteks kb db tidak memiliki informasi tentang objek pengguna, postgres kembali kesalahan
relation "AppUsers" does not exist
. Pernyataan pilih tidak memiliki informasi yang tepat tentang skema, nama bidang dll.Saya hampir menyerah, tetapi kemudian saya perhatikan saklar "-d" saat berlari
dotnet ef dbcontext scaffold
. Ini singkat untuk -data-anotasi - Gunakan atribut untuk mengkonfigurasi model (jika memungkinkan). Jika dihilangkan, hanya API yang fasih yang digunakan. Dengan saklar ini ditentukan, properti objek didefinisikan bukan dalam konteks dbOnModelCreating()
, melainkan pada objek itu sendiri, dengan atribut.Dengan cara ini, EF mendapatkan informasi yang cukup untuk menghasilkan pernyataan SQL yang tepat dengan nama dan skema bidang yang tepat.
TL; DR: konteks DB yang terpisah tidak menangani hubungan (FK) di antara mereka dengan baik, setiap konteks hanya memiliki informasi tentang entitasnya sendiri. Saat menentukan "-data-anotasi" aktifkan
dotnet ef dbcontext scaffold
, informasi ini tidak disimpan dalam setiap konteks yang terpisah, tetapi pada objek DB sendiri.sumber