Saya pro-repositori, meskipun saya telah pindah dari pola repositori generik. Sebaliknya saya menyelaraskan repositori saya dengan fungsi bisnis yang mereka layani. Repositori tidak ditujukan untuk mengabstraksi ORM, karena ini bukan sesuatu yang saya harapkan akan berubah, dan pada saat yang sama saya menghindari membuat repositori terlalu terperinci. (Yaitu CRUD) Alih-alih repositori saya melayani dua hingga tiga tujuan utama:
- Penerimaan data
- Pembuatan data
- Penghapusan sulit
Untuk pengambilan data, repositori selalu kembali IQueryable<TEntity>
. Untuk pembuatan data, ia mengembalikan TEntity. Repositori menangani pemfilteran tingkat dasar saya seperti status "aktif" otorisasi untuk sistem yang menggunakan pola hapus-lunak, dan status "saat ini" untuk sistem yang menggunakan data historis. Pembuatan data bertanggung jawab hanya untuk memastikan bahwa referensi yang diperlukan diselesaikan dan dikaitkan dan bahwa entitas diatur dan siap untuk pergi.
Pembaruan data adalah tanggung jawab logika bisnis yang bekerja dengan entitas yang dipertanyakan. Ini dapat mencakup hal-hal seperti aturan validasi. Saya tidak mencoba merangkumnya dalam metode repositori.
Penghapusan di sebagian besar sistem saya adalah soft-delete sehingga akan jatuh di bawah pembaruan data. (IsActive = false) Dalam kasus hard-delete, ini akan menjadi satu-baris dalam Repositori.
Kenapa harus repositori? Kemampuan uji. Tentu, DbContext dapat diejek, tetapi lebih mudah untuk mengejek kelas yang kembaliIQueryable<TEntity>
. Mereka juga bermain bagus dengan pola UoW, secara pribadi saya menggunakan pola DbContextScope Mehdime untuk lingkup unit kerja pada tingkat yang saya inginkan (Yaitu Pengendali di MVC) dan biarkan pengendali dan kelas layanan penolong saya menggunakan repositori tanpa perlu memberikan referensi ke UoW / dbContext sekitar. Menggunakan IQueryable berarti Anda tidak memerlukan banyak metode pembungkus dalam repositori, dan kode Anda dapat mengoptimalkan bagaimana data akan dikonsumsi. Misalnya repositori tidak perlu mengekspos metode seperti "Ada" atau "Hitung", atau mencoba untuk membungkus entitas dengan POCO lain dalam kasus di mana Anda ingin sub-set data. Mereka bahkan tidak perlu menangani opsi pemuatan cepat untuk data terkait yang mungkin atau mungkin tidak Anda butuhkan. Dengan melewati IQueryable, kode panggilan dapat:
.Any()
.Count()
.Include() // Generally avoided, instead I use .Select()
.Where()
.Select(x => new ViewModel or Anon. Type)
.Skip().Take()
.FirstOrDefault() / .SingleOrDefault() / .ToList()
Sangat fleksibel, dan dari PoV pengujian, repositori tiruan saya hanya perlu mengembalikan Daftar objek entitas yang dihuni.
Adapun repositori generik, saya telah pindah dari ini untuk sebagian besar karena ketika Anda berakhir dengan repositori per tabel pengendali / layanan Anda berakhir dengan referensi ke beberapa repositori untuk melakukan satu tindakan bisnis. Dalam kebanyakan kasus, hanya satu atau dua dari repositori ini yang benar-benar melakukan operasi penulisan (asalkan Anda menggunakan properti navigasi dengan benar) sementara sisanya mendukung yang dengan Reads. Saya lebih suka memiliki sesuatu seperti OrdersRepository yang mampu membaca dan membuat pesanan, dan membaca setiap pencarian yang relevan, dll. (Objek pelanggan ringan, produk, dll.) Untuk referensi ketika membuat pesanan, daripada memukul 5 atau 6 repositori yang berbeda. Ini mungkin melanggar puritan DNRY, tetapi argumen saya adalah bahwa tujuan repositori adalah untuk melayani pembuatan Pesanan yang mencakup referensi terkait.Repository<Product>
untuk mendapatkan produk yang berdasarkan pesanan saya hanya membutuhkan entitas dengan beberapa bidang. Tempat penyimpanan saya mungkin memiliki .GetProducts()
metode pengembalian IQueryable<ProductSummary>
yang saya temukan lebih bagus daripada Repository<Product>
yang akhirnya memiliki beberapa metode "Dapatkan" untuk mencoba dan melayani area yang berbeda dari kebutuhan aplikasi, dan / atau beberapa ekspresi penyaringan pass-in yang kompleks.
Saya memilih kode sederhana yang mudah diikuti, diuji, dan disesuaikan. Itu bisa disalahgunakan dengan cara yang buruk, tapi saya lebih suka memiliki sesuatu di mana pelanggaran mudah dikenali dan diperbaiki daripada mencoba untuk "mengunci" kode dengan cara yang tidak dapat disalahgunakan, gagal, dan kemudian memiliki sesuatu yang mimpi buruk untuk benar-benar melakukan apa yang dibayar klien untuk dilakukan pada akhirnya. :)