Membuat lapisan abstraksi di atas lapisan ORM

12

Saya percaya bahwa jika Anda memiliki repositori Anda menggunakan ORM yang sudah cukup disarikan dari database.

Namun, di mana saya bekerja sekarang, seseorang percaya bahwa kita harus memiliki lapisan yang mengabstraksi ORM jika kita ingin mengubah ORM nanti.

Apakah ini benar-benar diperlukan atau itu hanya banyak over head untuk membuat layer yang akan berfungsi pada banyak ORM?

Edit

Hanya untuk memberikan lebih banyak detail:

  1. Kami memiliki kelas POCO dan Kelas Entitas yang dipetakan dengan AutoMapper. Kelas entitas digunakan oleh lapisan Repositori. Lapisan repositori kemudian menggunakan lapisan abstraksi tambahan untuk berkomunikasi dengan Entity Framework.
  2. Lapisan bisnis sama sekali tidak memiliki akses langsung ke Entity Framework. Bahkan tanpa lapisan tambahan abstraksi atas ORM, yang satu ini perlu menggunakan lapisan layanan yang menggunakan lapisan repositori. Dalam kedua kasus, lapisan bisnis benar-benar terpisah dari ORM.
  3. Argumen utama adalah untuk dapat mengubah ORM di masa depan. Karena itu benar-benar terlokalisasi di dalam lapisan Repositori, bagi saya, sudah terpisah dengan baik dan saya tidak melihat mengapa lapisan tambahan abstraksi diperlukan untuk memiliki kode "kualitas".
Patrick Desjardins
sumber
3
lapisan tambahan perlu pembenaran, kalau tidak itu melanggar YAGNI. Dengan kata lain, seseorang yang percaya bahwa Anda membutuhkannya, memiliki beban untuk membuktikan bahwa
nyamuk
2
Saya dapat memahami menginginkan lapisan domain yang hanya memperlihatkan subhimpunan operasi yang diinginkan - ORM cenderung sedikit terlalu luas area permukaan (misalnya Anda tidak ingin mengizinkan pembaruan untuk entitas yang tidak diarahkan oleh entitas yang mengandung lainnya). Memiliki lapisan abstraksi semacam itu membantu dalam hal ini.
Oded
4
Anda mungkin perlu lapisan kedua abstraksi untuk lapisan pertama abstraksi di atas ORM jika Anda ingin mengubah lapisan pertama juga.
David Peterman
1
@ David Sementara kami menambahkan redudancy, ubah semua if Anda (boolean) menjadi if (boolean == true) dan jika Anda ingin memuntahkan lebih banyak hal yang sama, if (boolean == true == true ...) dan sebagainya
brian
1
Pos terkait yang menarik: ayende.com/blog/3955/repository-is-the-new-singleton
RMalke

Jawaban:

12

Dengan begitu terletak kegilaan. Sangat tidak mungkin Anda perlu mengubah ORM. Dan jika Anda pernah memutuskan untuk mengubah ORM, biaya penulisan ulang pemetaan akan menjadi sebagian kecil dari biaya untuk mengembangkan dan mempertahankan meta-ORM Anda sendiri. Saya berharap Anda dapat menulis beberapa skrip untuk melakukan 95% dari pekerjaan yang diperlukan untuk mengganti ORM.

Kerangka kerja internal hampir selalu merupakan bencana. Membangun satu untuk mengantisipasi kebutuhan di masa depan hampir merupakan bencana yang dijamin. Kerangka kerja yang sukses diambil dari proyek-proyek yang sukses, tidak dibangun sebelumnya untuk memenuhi kebutuhan imajiner.

kevin cline
sumber
12

ORM menyediakan abstraksi untuk lapisan data Anda agar tidak tergantung pada RDBMS-nya, tetapi mungkin tidak cukup untuk "melepaskan" lapisan bisnis Anda dari lapisan data Anda. Khususnya, Anda tidak boleh membiarkan objek yang memetakan ke tabel RDBMS untuk "bocor" langsung ke lapisan bisnis.

Paling tidak, lapisan bisnis Anda perlu memprogram untuk antarmuka yang dapat dikelola oleh ORM, objek yang dipetakan tabel dari lapisan data yang berpotensi diimplementasikan. Selain itu, Anda mungkin perlu membuat lapisan berbasis permintaan abstrak bangunan untuk menyembunyikan kemampuan query asli ORM Anda. Tujuan utamanya adalah untuk menghindari "memasukkan" ORM tertentu ke dalam solusi Anda di luar lapisan datanya. Misalnya, mungkin tergoda untuk membuat string HQL ( Hibernate Query Language ) di lapisan bisnis. Namun, keputusan yang tampaknya tidak bersalah ini akan mengikat lapisan bisnis Anda ke Hibernate, sehingga memadukan lapisan bisnis dan akses data; Anda harus berusaha menghindari situasi ini sebanyak mungkin.

EDIT: Dalam kasus Anda, lapisan tambahan di dalam repositori adalah buang-buang waktu: berdasarkan poin nomor dua Anda, lapisan bisnis Anda cukup terisolasi dari repositori Anda. Memberikan isolasi tambahan akan menimbulkan kompleksitas yang tidak perlu, tanpa manfaat tambahan.

Masalah dengan membangun lapisan abstraksi ekstra di dalam repositori Anda adalah bahwa "merek" ORM menentukan cara Anda berinteraksi dengannya. Jika Anda membuat pembungkus tipis yang terlihat seperti ORM Anda, tetapi berada di bawah kendali Anda, mengganti ORM yang mendasarinya akan kira-kira sama sulitnya dengan tanpa lapisan tambahan itu. Jika, di sisi lain, Anda membangun lapisan yang tidak terlihat seperti ORM Anda, maka Anda harus mempertanyakan pilihan Anda atas teknologi pemetaan objek-relasional.

dasblinkenlight
sumber
Saya sangat senang. NET telah memecahkan masalah ini dengan memanggang Obyek Kueri ke dalam platform. Port .NET Hibernate bahkan mendukungnya.
Michael Brown
2
@MikeBrown Ya, dan .NET juga memasok dua teknologi ORM yang bersaing, keduanya menggunakan teknologi LINQ!
dasblinkenlight
@dasblinkenlight Saya memperbarui pertanyaan untuk memberi Anda informasi tambahan.
Patrick Desjardins
Akhir-akhir ini, saya telah mengadopsi pendekatan agar lapisan bisnis bergantung pada lapisan data berdasarkan antarmuka peta-suka dan set-suka untuk menyimpan keadaan. Saya sekarang percaya bahwa antarmuka mewakili perhatian menjaga negara cukup baik (terinspirasi oleh gaya pemrograman fungsional) dan memberikan pemisahan yang bagus dari ORM pilihan melalui implementasi yang agak tipis.
beluchin
2

UnitOfWork biasanya menyediakan abstraksi ini. Ini adalah satu tempat yang perlu diubah, repositori Anda bergantung padanya melalui Antarmuka. Jika Anda perlu mengubah O / RM, cukup terapkan UoW baru di atasnya. Satu dan selesai.

BTW melampaui hanya beralih O / RM, pikirkan pengujian unit. Saya memiliki tiga implementasi UnitOfWork, satu untuk EF, satu untuk NH (karena saya sebenarnya DID harus mengganti proyek tengah O / RM untuk klien yang menginginkan dukungan Oracle), dan satu untuk ketekunan InMemory. Kegigihan InMemory sempurna untuk pengujian unit atau bahkan untuk prototyping cepat sebelum saya siap untuk meletakkan database di belakangnya.

Kerangka kerja ini sederhana untuk diterapkan. Pertama, Anda memiliki antarmuka IRepository generik

public interface IRepository<T>
  where T:class
{
  IQueryable<T> FindBy(Expression<Func<T,Bool>>filter);
  IQueryable<T> GetAll();
  T FindSingle(Expression<Func<T,Bool>> filter);
  void Add(T item);
  void Remove(T item);

}

Dan antarmuka IUnitOfWork

public interface IUnitOfWork
{
   IQueryable<T> GetSet<T>();
   void Save();
   void Add<T>(T item) where T:class;
   void Remove<T>(T item) where T:class;
}

Berikutnya adalah repositori dasar (pilihan Anda apakah itu abstrak atau tidak

public abstract class RepositoryBase<T>:IRepository<T>
  where T:class
{
   protected readonly IUnitOfWork _uow;

   protected RepositoryBase(IUnitOfWork uow)
   { 
      _uow=uow;
   }

   public IQueryable<T> FindBy(Expression<Func<T,Bool>>filter)
   {
      return _uow.GetSet<T>().Where(filter);
   }

   public IQueryable<T> GetAll()
   {
      return _uow.GetSet<T>();
   }

   public T FindSingle(Expression<Func<T,Bool>> filter)
   {
      return _uow.GetSet<T>().SingleOrDefault(filter);
   }

   public void Add(T item)
   {
      return _uow.Add(item);
   }

   public void Remove(T item)
   {
      return _uow.Remove(item);
   }
}

Menerapkan IUnitOfWork adalah permainan anak-anak untuk EF, NH, dan In Memory. Alasan saya mengembalikan IQueryable, adalah untuk alasan yang sama, Ayende disebutkan dalam posnya, klien dapat memfilter lebih lanjut, mengurutkan, mengelompokkan, dan bahkan memproyeksikan hasilnya menggunakan LINQ dan Anda masih mendapatkan manfaat dari semuanya yang dilakukan di sisi server.

Michael Brown
sumber
1
Tetapi pertanyaan di sini adalah menentukan apakah layer di atas berguna atau tidak dan harus menjadi penjaga pintu untuk semua akses data.
brian
Seandainya saya bisa menunjuk ke posting blog saya pada implementasi Unit Kerja / Repositori. Itu membahas keprihatinan yang tepat dari OP.
Michael Brown
Memberi layer nama tidak berarti itu perlu atau berguna.
kevin cline
Catatan menurut OP, ia memiliki pemetaan ekstra antara akses data dan lapisan bisnis. Bagi saya, objek bisnis dan objek entitas saya sama. EF dan NH menyediakan API pemetaan yang luar biasa sehingga pemetaan data jarang (jika pernah) menjadi perhatian.
Michael Brown
Bagaimana Anda menerjemahkan Ekspresi sewenang-wenang ke panggilan ORM yang efisien? Anda tidak bisa mengambil semuanya dan membuang baris yang tidak cocok dengan filter.
kevin cline