Repositori Generik Dengan EF 4.1 apa gunanya

145

Ketika saya menggali lebih dalam ke DbContext, DbSet dan antarmuka terkait, saya bertanya-tanya mengapa Anda perlu menerapkan Repositori "Generik" yang terpisah di sekitar implementasi ini?

Sepertinya DbContext dan IDbSet lakukan semua yang Anda butuhkan dan sertakan "Unit Kerja" di dalam DbContext.

Apakah saya kehilangan sesuatu di sini atau apakah orang-orang senang menambahkan lapisan ketergantungan lain tanpa alasan.

Kode Jammr
sumber
Ini adalah masalah berbasis sengketa / opini sedikit. Saya sudah membahas ini di sini .
Amit Joshi

Jawaban:

202

Anda sebenarnya benar. DbContextadalah implementasi dari pola satuan kerja dan IDbSetmerupakan implementasi dari pola repositori.

Repositori saat ini sangat populer dan digunakan secara berlebihan. Semua orang menggunakannya hanya karena ada lusinan artikel tentang membuat repositori untuk kerangka kerja entitas tetapi tidak ada yang benar-benar menggambarkan tantangan terkait dengan keputusan ini.

Alasan utama untuk menggunakan repositori biasanya:

  • Sembunyikan EF dari lapisan atas
  • Buat kode lebih mudah diuji

Alasan pertama adalah semacam kemurnian arsitektonik dan ide bagus bahwa jika Anda membuat lapisan atas Anda mandiri pada EF, Anda nantinya dapat beralih ke kerangka kerja ketekunan lainnya. Berapa kali Anda melihat hal seperti itu di dunia nyata? Alasan ini membuat bekerja dengan EF jauh lebih sulit karena repositori Anda harus mengekspos banyak fitur tambahan yang membungkus apa yang diizinkan oleh EF secara default.

Pada saat yang sama, membungkus kode EF dapat membuat kode Anda lebih teratur dan mengikuti aturan Separation of concern. Bagi saya ini bisa menjadi satu-satunya keuntungan nyata dari repositori dan unit kerja, tetapi Anda harus memahami bahwa mengikuti aturan ini dengan EF mungkin akan membuat kode Anda lebih mudah dikelola dan lebih mudah dibaca tetapi dalam upaya awal untuk membuat aplikasi Anda akan jauh lebih tinggi dan untuk aplikasi yang lebih kecil ini bisa menjadi kompleksitas yang tidak perlu.

Alasan kedua sebagian benar. Kerugian besar dari EF adalah arsitektur kaku yang hampir tidak bisa dipermainkan jadi jika Anda ingin menguji lapisan atas, Anda harus membungkus EF entah bagaimana untuk memungkinkan mengejek implementasinya. Tetapi ini memiliki banyak konsekuensi lain yang saya jelaskan di sini .

Saya mengikuti blog Ayende . Jika Anda pernah menggunakan NHibernate, Anda mungkin tahu artikelnya. Orang ini baru-baru ini menulis beberapa artikel yang menentang penggunaan repositori dengan NHibernate tetapi NHibernate jauh lebih baik dapat dipermainkan.

Ladislav Mrnka
sumber
3
Anda dapat mengejek IDbSetAnda juga dapat mendefinisikan antarmuka khusus dalam konteks turunan Anda, tetapi hanya itu saja. Setelah kode Anda menggunakan ChangeTracker, Entri atau apa pun itu akan membutuhkan upaya besar untuk membungkus mereka semua.
Ladislav Mrnka
1
Ya EF bukan alat yang sangat berorientasi kinerja. Setidaknya MS memiliki banyak peluang untuk menjadikan ini lebih baik di versi mendatang.
Ladislav Mrnka
2
@ chiccodoro: Benar. Tetapi begitu kelas tiruan Anda mengekspos IQueryableatau menerima Expression<>sebagai parameter yang dimasukkan secara internal ke permintaan Linq-to-entitas Anda mendefinisikan logika di luar komponen yang diolok-olok dengan efek samping yang tidak dapat diuji dengan unit test.
Ladislav Mrnka
8
Jika saya menggunakan DbSet dan BdContext langsung di sana di lapisan bisnis saya, saya harus referensi EntityFramework.dll di sana juga di proyek DataLayer saya. Itu saja memberitahu saya bahwa itu perlu semacam pembungkus.
Ingó Vals
2
downvote: tidak lengkap - abstraksi EF di belakang antarmuka repositori dapat membuat kode klien yang sama persis berjalan di SL dan WPF.
h.alex
21

Saya berjuang dengan masalah yang sama, dan kemampuan mengejek untuk pengujian unit pada lapisan EF adalah penting. Tapi saya membaca artikel hebat ini yang menjelaskan cara mengatur EF 4.1 DbContext agar bisa dipermainkan dengan memastikan DbContext yang diturunkan Anda mengimplementasikan antarmuka umum dan mengekspos IDbSet daripada DbSet. Karena saya menggunakan pendekatan Basis Data, karena basis data kami sudah ada, saya cukup memodifikasi templat T4 yang digunakan untuk membuat turunan DbContext saya untuk menghasilkannya untuk mengembalikan antarmuka IDbSet, serta berasal dari antarmuka generik saya. Dengan begitu seluruh hal dapat dengan mudah diejek, dan Anda tidak perlu menerapkan Unit Kerja atau pola penyimpanan Anda sendiri. Cukup tulis kode layanan Anda untuk menggunakan antarmuka generik Anda, dan ketika Anda pergi ke unit mengujinya,

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/

Kendall Bennett
sumber
5

Salah satu alasan untuk membuat repositori adalah agar Anda dapat menyembunyikan implementasi DBSet dan DbContext jika Anda memutuskan untuk beralih dari EntityFramework ke sesuatu yang lain atau sebaliknya.

Sebagai contoh, saya menggunakan NHibernate dan saya membungkus semua panggilan ke framework itu di dalam kelas repositori saya. Mereka mengembalikan IEnumerable agar menjadi "generik" dan repositori saya memiliki operasi CRUD standar (perbarui, hapus, dll.). Saya sudah lama pindah ke Entity Framework. Setelah melakukannya, saya tidak perlu mengubah apa pun di kelas ViewModel atau lebih karena mereka menunjuk ke repositori saya - Saya hanya perlu mengubah bagian dalam repositori saya. Ini membuat hidup jauh lebih mudah saat bermigrasi.

(Saya menggunakan NHibernate karena kami terhubung ke ISeries, dan pada saat itu, tidak ada biaya implementasi afektif menggunakan EF dengan ISeries. Satu-satunya yang tersedia adalah membayar $ 12.000 kepada IBM untuk DB2Connect mereka)

Leniel Maccaferri
sumber
"Hampir" (dengan menyembunyikan DBSet dan DbContext) Anda akan menemukan bahwa Anda tidak perlu memaparkan EF kepada konsumen mana pun (misalnya jika Anda memanfaatkan DI) tetapi Anda memang memerlukan antarmuka yang mengekspos properti IDbSet <T> atau melangkah lebih jauh dan ketik semua properti Anda sebagai IQueryable <T>, tapi poin saya adalah bahwa Anda dapat sepenuhnya menyembunyikan ketergantungan Anda pada DbSet dan DbContext. Operasi CRUD kemudian dapat ditulis sebagai metode ekstensi, Anda dapat menulis beberapa metode ekstensi untuk berbagai toko dukungan. Anda tidak akan menyembunyikan penggunaan LINQ.
Shaun Wilson