Kerangka Entitas dan Penggabungan Koneksi

268

Saya baru-baru ini mulai menggunakan Entity Framework 4.0 di aplikasi .NET 4.0 saya dan saya ingin tahu tentang beberapa hal yang berkaitan dengan penyatuan.

  1. Penyatuan koneksi yang saya tahu dikelola oleh penyedia data ADO.NET, dalam kasus saya MS SQL server. Apakah ini berlaku ketika Anda instantiate konteks entitas baru ( ObjectContext), yaitu parameterless new MyDatabaseModelEntities()?

  2. Apa kelebihan dan kekurangan dari a) menciptakan konteks entitas global untuk aplikasi (yaitu satu contoh statis) atau b) membuat dan mengekspos konteks entitas untuk setiap operasi / metode yang diberikan, dengan sebuah usingblok.

  3. Adakah rekomendasi lain, praktik terbaik, atau pendekatan umum untuk skenario tertentu yang harus saya ketahui?

Noldorin
sumber

Jawaban:

369
  1. Penyambungan koneksi ditangani seperti pada aplikasi ADO.NET lainnya. Koneksi entitas masih menggunakan koneksi database tradisional dengan string koneksi tradisional. Saya percaya Anda dapat mematikan koneksi koneksi dalam string koneksi jika Anda tidak ingin menggunakannya. (baca lebih lanjut tentang SQL Server Connection Pooling (ADO.NET) )
  2. Jangan pernah menggunakan konteks global. ObjectContext secara internal mengimplementasikan beberapa pola termasuk Identity Map dan Unit of Work. Dampak penggunaan konteks global berbeda untuk setiap jenis aplikasi.
  3. Untuk aplikasi web gunakan konteks tunggal per permintaan. Untuk layanan web, gunakan satu konteks per panggilan. Dalam aplikasi WinForms atau WPF gunakan konteks tunggal per formulir atau per presenter. Mungkin ada beberapa persyaratan khusus yang tidak memungkinkan untuk menggunakan pendekatan ini tetapi dalam kebanyakan situasi ini sudah cukup.

Jika Anda ingin tahu dampak apa yang memiliki konteks objek tunggal untuk aplikasi WPF / WinForm, periksa artikel ini . Ini tentang Sesi NHibernate tetapi idenya sama.

Edit:

Saat Anda menggunakan EF, secara default memuat setiap entitas hanya satu kali per konteks. Kueri pertama membuat instace entitas dan menyimpannya secara internal. Kueri selanjutnya yang memerlukan entitas dengan kunci yang sama mengembalikan instance yang disimpan ini. Jika nilai dalam penyimpanan data berubah, Anda masih menerima entitas dengan nilai dari kueri awal. Ini disebut pola peta Identitas . Anda bisa memaksa konteks objek untuk memuat ulang entitas tetapi akan memuat ulang satu contoh bersama.

Setiap perubahan yang dilakukan pada entitas tidak bertahan sampai Anda memanggil SaveChangeskonteksnya. Anda dapat melakukan perubahan di banyak entitas dan menyimpannya sekaligus. Ini disebut pola Unit Kerja . Anda tidak dapat secara selektif mengatakan entitas terlampir yang dimodifikasi yang ingin Anda simpan.

Kombinasikan dua pola ini dan Anda akan melihat beberapa efek menarik. Anda hanya memiliki satu instance entitas untuk seluruh aplikasi. Setiap perubahan pada entitas memengaruhi seluruh aplikasi meskipun perubahan belum dilakukan (berkomitmen). Dalam kebanyakan kali ini bukan yang Anda inginkan. Misalkan Anda memiliki formulir edit dalam aplikasi WPF. Anda bekerja dengan entitas dan Anda memutuskan untuk membatalkan editasi kompleks (mengubah nilai, menambahkan entitas terkait, menghapus entitas terkait lainnya, dll.). Tetapi entitas sudah dimodifikasi dalam konteks bersama. Apa yang akan kamu lakukan? Petunjuk: Saya tidak tahu tentang CancelChanges atau UndoChanges aktif ObjectContext.

Saya pikir kita tidak perlu membahas skenario server. Cukup berbagi satu entitas di antara beberapa permintaan HTTP atau panggilan layanan Web membuat aplikasi Anda tidak berguna. Setiap permintaan dapat memicu SaveChangesdan menyimpan sebagian data dari permintaan lain karena Anda berbagi satu unit kerja di antara semuanya. Ini juga akan memiliki masalah lain - konteks dan manipulasi dengan entitas dalam konteks atau koneksi database yang digunakan oleh konteks tidak aman thread.

Bahkan untuk aplikasi yang hanya bisa dibaca, konteks global bukanlah pilihan yang baik karena Anda mungkin menginginkan data baru setiap kali Anda meminta aplikasi.

Ladislav Mrnka
sumber
Terima kasih untuk balasan Anda. Mungkin Anda bisa menguraikan mengapa tidak baik menggunakan satu konteks global? Itu membuat akses paralel lebih sulit, pasti, tapi apa lagi ...?
Noldorin
Ok, itu jauh lebih jelas sekarang, terima kasih. Sekadar mengonfirmasi, meskipun konteks global tidak pernah benar-benar tepat, konteks tunggal untuk "dialog edit" atau semacamnya mungkin cara yang benar? Dalam situasi lain, seperti layanan web dan ASP.NET, konteks dalam metode hanya lebih masuk akal. Tentang yang benar?
Noldorin
Saya menerima saran Anda dan menghapus singelton. Sekarang saya mendapatkan kesalahan lain: stackoverflow.com/questions/14795899/…
Elad Benda
Saya memahami bahwa menerapkan pola satuan Kerja dan merangkum DbContext harus memisahkan logika bisnis dan operasi basis data. Saya tidak dapat memahami bagaimana menerapkan pola Unit kerja dan menggunakan TransactionScope hanya untuk beberapa operasi.
Rudolf Dvoracek
4
@RudolfDvoracek: Mudah. TransactionScopebukan milik unit kerja, itu milik logika bisnis Anda karena logika itu sendiri mendefinisikan transaksi. Unit kerja hanya menentukan apa yang harus bertahan bersama sedangkan ruang lingkup transaksi memungkinkan Anda menggunakan unit kerja yang gigih beberapa kali dalam transaksi yang sama.
Ladislav Mrnka
70

Menurut Daniel Simmons:

Buat instance ObjectContext baru dalam pernyataan Menggunakan untuk setiap metode layanan sehingga dibuang sebelum metode kembali. Langkah ini sangat penting untuk skalabilitas layanan Anda. Itu memastikan bahwa koneksi database tidak tetap terbuka di seluruh panggilan layanan dan bahwa keadaan sementara yang digunakan oleh operasi tertentu adalah sampah yang dikumpulkan ketika operasi itu selesai. Entity Framework secara otomatis menyimpan metadata dan informasi lain yang diperlukan dalam domain aplikasi, dan ADO.NET menggabungkan koneksi database, jadi menciptakan kembali konteks setiap kali adalah operasi yang cepat.

Ini dari artikel komprehensifnya di sini:

http://msdn.microsoft.com/en-us/magazine/ee335715.aspx

Saya percaya saran ini meluas ke permintaan HTTP, jadi akan berlaku untuk ASP.NET. Aplikasi stateful, klien-gemuk seperti aplikasi WPF mungkin satu-satunya kasus untuk konteks "bersama".

Dave Swersky
sumber
Terima kasih, itu kutipan yang sangat informatif di sana. Namun, saya masih bertanya-tanya apakah konteks bersama (global) akan sesuai bahkan untuk aplikasi WPF klien atau semacamnya. Apakah ada setiap bahkan keuntungan dalam kasus ini?
Noldorin
Tidak akan ada keuntungan untuk konteks global dalam aplikasi WPF, tetapi mungkin juga tidak akan ada kerugian yang signifikan. Jika Anda menerapkan konteks global, Anda mungkin harus melakukan beberapa pengelolaan koneksi database secara manual (penutupan koneksi secara eksplisit) dalam kasus tingkat permintaan yang tinggi.
Dave Swersky
1
Baik; jadi pada dasarnya saya tidak pernah bisa benar-benar salah dengan menggunakan beberapa konteks sementara (mengingat saya tahu koneksi pooling terjadi)? ... Jika Anda menggunakan konteks global tunggal, tidak bisakah koneksi dalam teori turun secara acak?
Noldorin
1
@Nolodrin: Saya tidak berpikir koneksi akan turun "secara acak" ... risikonya adalah koneksi bisa dibuka terlalu lama dan memenuhi kolam koneksi.
Dave Swersky
1
Mengimplementasikan ObjectContext / DbContext IDisposable, oleh karena itu harus terbuka untuk waktu yang masuk akal terpendek, adalah pandangan saya.
nicodemus13
12

Dokumentasi Accoriding ke EF6 (4,5 juga): https://msdn.microsoft.com/en-us/data/hh949853#9

9.3 Konteks per permintaan

Konteks Entity Framework dimaksudkan untuk digunakan sebagai instance yang berumur pendek untuk memberikan pengalaman kinerja yang paling optimal . Konteks diharapkan berumur pendek dan dibuang, dan dengan demikian telah diterapkan untuk menjadi sangat ringan dan menggunakan kembali metadata bila memungkinkan. Dalam skenario web, penting untuk mengingat hal ini dan tidak memiliki konteks lebih dari durasi permintaan tunggal. Demikian pula, dalam skenario non-web, konteks harus dibuang berdasarkan pemahaman Anda tentang berbagai level caching di Entity Framework. Secara umum, seseorang harus menghindari memiliki instance konteks sepanjang umur aplikasi, serta konteks per thread dan konteks statis.

Raj Rao
sumber
2
Saya tahu balasan ini sudah ada di sini sebentar, tetapi saya harus mengatakan ini menyelamatkan saya dari sakit kepala. Terus mendapatkan kesalahan "Pooled Connection" saat menggunakan EF dengan Oracle, dan tidak dapat menemukan alasannya. Saya telah mengatur dbContext sebagai variabel kelas, instantiate pada penciptaan. Mengubahnya untuk menciptakan konteks sesuai kebutuhan memperbaiki semua penyakit dunia saya. Terima kasih!
Fletchius
1

Kode di bawah ini membantu objek saya untuk di-refresh dengan nilai basis data yang segar. Perintah Entry (objek) .Reload () memaksa objek untuk memanggil kembali nilai basis data

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();
HGMamaci
sumber
dan juga ini untuk koleksi (kode VB):CType(myContext, IObjectContextAdapter).ObjectContext.Refresh(RefreshMode.StoreWins,myCustomers)
Ivan Ferrer Villa