ORM katmanı üzerinde bir soyutlama katmanı oluşturma


12

Havuzlarınız varsa, veritabanından zaten soyutlanmış bir ORM kullandığınıza inanıyorum.

Ancak, şu anda çalıştığım yerde, birisi daha sonra ORM'yi değiştirmek istediğimizde ORM'yi soyutlayan bir katmana sahip olmamız gerektiğine inanıyor.

Birçok ORM üzerinde çalışacak bir katman oluşturmak gerçekten gerekli mi yoksa başın üstünde mi?

Düzenle

Daha fazla ayrıntı vermek için:

  1. AutoMapper ile eşlenen POCO sınıfımız ve Entity Sınıfımız var. Varlık sınıfı, Depo katmanı tarafından kullanılır. Depo katmanı daha sonra Entity Framework ile iletişim kurmak için ek soyutlama katmanını kullanır.
  2. İş katmanının hiçbir şekilde Entity Framework'e doğrudan erişimi yoktur. ORM üzerinde ek bir soyutlama katmanı olmasa bile, bunun depo katmanını kullanan hizmet katmanını kullanması gerekir. Her iki durumda da, iş katmanı ORM'den tamamen ayrılmıştır.
  3. Ana argüman gelecekte ORM'yi değiştirebilmektir. Depo katmanının içinde gerçekten yerel olduğundan, bana çok iyi ayrılmış durumda ve neden "kalite" koduna sahip olmak için ek bir soyutlama katmanının gerekli olduğunu görmüyorum.

3
Ek katmanın gerekçelendirilmesi gerekiyor, aksi takdirde YAGNI'yı ihlal ediyor. Başka bir deyişle, buna ihtiyacınız olduğuna inanan birinin bunu kanıtlamak için bir yükü vardır
gnat

2
Yalnızca istenen bir işlem alt kümesini ortaya çıkaran bir etki alanı katmanı istemeyi anlayabilirim - ORM'ler bir yüzey alanı biraz fazla geniş olma eğilimindedir (başka bir kapsayıcı varlık tarafından yönlendirilmeyen bir varlığa güncellemelere izin vermek istemediğinizi varsayalım). Böyle bir soyutlama katmanına sahip olmak buna yardımcı olur.
Oded

4
İlk katmanı da değiştirmek istiyorsanız, ORM'nin üzerindeki ilk soyutlama katmanı için muhtemelen ikinci bir soyutlama katmanına ihtiyacınız olacaktır.
David Peterman

1
@David Redudancy eklerken, tüm if (boolean) değerini if ​​(boolean == true) olarak değiştirin ve eğer daha fazlasını yeniden oluşturmak istiyorsanız, (boolean == true == true ...) ve benzeri
brian

Yanıtlar:


12

Bu şekilde delilik yatar. ORM'leri değiştirmeniz gerekmeyecektir. ORM'yi değiştirmeye karar verirseniz, eşlemeleri yeniden yazmanın maliyeti, kendi meta-ORM'nizi geliştirme ve sürdürme maliyetinin küçük bir kısmı olacaktır. ORM'leri değiştirmek için gereken işin% 95'ini yapmak için birkaç komut dosyası yazmanızı bekleyebilirim.

Şirket içi çerçeveler neredeyse her zaman bir felakettir. Gelecekteki ihtiyaçların beklentisiyle bir tane inşa etmek neredeyse garantili bir felakettir. Başarılı çerçeveler, hayali ihtiyaçları karşılamak için önceden inşa edilmeyen başarılı projelerden çıkarılır.


12

ORM, veri katmanınızın RDBMS'sinden bağımsız olması için bir soyutlama sağlar, ancak iş katmanınızı veri katmanınızdan "çözmek" için yeterli olmayabilir. Özellikle, RDBMS tablolarıyla eşlenen nesnelerin doğrudan iş katmanına "sızmasına" izin vermemelisiniz.

En azından işletme katmanınızın, veri katmanındaki ORM tarafından yönetilen, tablo eşlemeli nesnelerinizin potansiyel olarak uygulayabileceği arabirimlere programlaması gerekir. Ayrıca, ORM'nizin yerel sorgulama özelliklerini gizlemek için arabirim tabanlı bir soyut sorgu oluşturma katmanı oluşturmanız gerekebilir. Ana hedef, belirli bir ORM'yi veri katmanının ötesinde çözümünüzde "pişirmekten" kaçınmaktır. Örneğin , iş katmanında HQL ( Hazırda Bekleme Sorgu Dili ) dizeleri oluşturmak cazip gelebilir . Ancak, bu görünüşte masum bir karar, iş katmanınızı Hazırda Bekletme'ye bağlar, böylece iş ve veri erişim katmanlarını bir araya getirir; bu durumdan mümkün olduğunca kaçınmaya çalışmalısınız.

DÜZENLEME: Sizin durumunuzda, havuzun içindeki ek katman zaman kaybıdır: ikinci noktanıza bağlı olarak, iş katmanınız deponuzdan yeterince yalıtılmıştır. Ek yalıtım sağlamak, hiçbir ek fayda olmadan gereksiz karmaşıklık getirecektir.

Deponuzun içinde fazladan bir soyutlama katmanı oluşturmayla ilgili sorun, ORM'in belirli "markasının" onunla etkileşim şeklinizi belirlemesi. ORM'nize benzeyen ancak kontrolünüz altında olan ince bir ambalaj oluşturursanız, alttaki ORM'yi değiştirmek kabaca bu ek katman olmadan olduğu kadar sert olacaktır. Öte yandan, ORM'nize benzemeyen bir katman oluşturursanız, nesne-ilişkisel haritalama teknolojisi seçiminizi sorgulamalısınız.


.NET'in Query Object'i platforma ekleyerek bu sorunu çözdüğüne çok sevindim. Hibernate'in .NET portu bile onu destekler.
Michael Brown

2
@MikeBrown Yeah ve .NET, her ikisi de LINQ teknolojisini kullanarak iki rakip ORM teknolojisi sağladı!
dasblinkenlight

@dasblinkenlight Size daha fazla bilgi vermek için soruyu güncelledim.
Patrick Desjardins

Son zamanlarda, iş katmanının, durumu depolamak için harita benzeri ve set benzeri arayüzlere dayanan bir veri katmanına bağımlı olma yaklaşımını benimsedim. Şimdi bu arayüzlerin devlet tutma endişesini yeterince iyi temsil ettiğine (fonksiyonel programlama tarzından esinlenerek) ve oldukça ince bir uygulama yoluyla tercih edilen ORM'den güzel bir ayrım sağladığına inanıyorum.
Mart'ta beluchin

2

UnitOfWork genellikle bu soyutlamayı sağlar. Değişmesi gereken bir yer, depolarınız bir Arayüz üzerinden ona bağlı. O / RM'yi değiştirmeniz gerekirse, üzerine yeni bir UOW uygulayın. Bir ve bitti.

BTW sadece O / RM'yi değiştirmenin ötesine geçer, birim testini düşünün. Üç tane UnitOfWork uygulamam var, biri EF, biri NH için (çünkü aslında Oracle desteği isteyen bir istemci için O / RM'leri proje ortasında değiştirmek zorunda kaldım) ve diğeri InMemory kalıcılığı için. InMemory sürekliliği, bir veritabanını arkasına koymaya hazır olmadan önce birim testleri ve hatta hızlı prototipleme için mükemmeldi.

Çerçevenin uygulanması kolaydır. Önce jenerik IRepository arayüzünüz var

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);

}

Ve IUnitOfWork arayüzü

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;
}

Sonraki temel depo (soyut olup olmayacağına dair seçiminiz

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);
   }
}

IUnitOfWork'un uygulanması EF, NH ve In Memory için çocuk oyunudur. IQueryable'ı iade etmemin nedeni, aynı nedenden dolayı, Ayende görevinde belirtildi, müşteri LINQ kullanarak sonucu daha fazla filtreleyebilir, sıralayabilir, gruplayabilir ve hatta yansıtabilir ve yine de sunucu tarafında yapılıyor.


1
Ancak buradaki soru, yukarıdaki katmanın yararlı olup olmadığını ve tüm veri erişimine kapı bekçisi olup olmayacağını belirlemektir.
brian

Çalışma Birimi / Depo uygulamasındaki blog yayınımı gösterebilseydim. OP'nin kesin kaygılarını tartışıyor.
Michael Brown

Katmana bir ad vermek, gerekli veya kullanışlı olduğu anlamına gelmez.
kevin cline

OP'ye göre, veri erişimi ve iş katmanı arasında ekstra bir haritaya sahip olduğunu unutmayın. Benim için iş objelerim ile varlık objelerim aynı. EF ve NH, veri eşlemenin nadiren (eğer varsa) endişe kaynağı olacağı şekilde şaşırtıcı eşleme API'leri sağlar.
Michael Brown

Rasgele bir İfadeyi verimli bir ORM çağrısına nasıl çevirirsiniz? Her şeyi getirip filtreyle eşleşmeyen satırları atamazsınız.
kevin cline
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.