Havuz kalıbı ne zaman kullanılır?


20

Son zamanlarda, bir ORM ile birlikte veri havuzu modelini kullanmanın iyi bir uygulama olmadığını okudum. Anladığım kadarıyla bu, SQL veritabanı üzerinde sağladıkları soyutlamanın kalıp tarafından içerilemeyecek kadar sızıntılı olması.

Bununla ilgili birkaç sorum var:

  1. ORM'leri kapatmak istiyorsanız ne yaparsınız? Bir havuzda içermezseniz, uygulamanızda ORM'ye özel kodunuz olacaktır.

  2. Bir ORM kullanmadığınızda depo deseni hala geçerli mi ve veri erişimi ve nesne verilerini kendiniz doldurmak için ADO.NET kullanıyor musunuz?

  3. Bir ORM kullanırsanız, ancak çoğaltma desenini kullanmazsanız, sık kullanılan sorguları nerede tutuyorsunuz? Her sorguyu bir sınıf olarak temsil etmek ve örnekler oluşturmak için bir çeşit sorgu fabrikası bulundurmak akıllıca olur mu?


1
1) Farklı davranışları nedeniyle ORM'yi asla değiştiremezsiniz, her ikisi de linq'i desteklese bile, uygulamanızın kırılması için yeterince farklı davranırlar. tembel yükleme davranışı, kirli izleme, hayalet vekil vs vs .. Ancak test için bir mem içi uygulama için ORM takas edebilmek güzel ..
Roger Johansson

Değeri ne olursa olsun, Depo / ORM tartışmasına katılmam burada: stackoverflow.com/questions/13180501/…
Eric King

Kötü bir uygulama olduğunu nereden okudunuz?
Dave Hillier

Yanıtlar:


3

1) Doğru, ancak bir ORM'yi ne sıklıkla kapatıyorsunuz?
2) Bunu söyleyebilirim, çünkü bir ORM bağlamı bir tür havuzdur ve sorgu oluşturma, veri alma, haritalama vb. İçeren bir çok işi gizler. Eğer bir ORM kullanmazsanız, bu mantık hala bir yerde kalmak zorundadır. Bunun kelimenin en katı anlamında depo modeli olarak
nitelenip nitelenmediğini bilmiyorum ... 3) Sorguları kapsül haline getirmek sık sık gördüğüm bir şeydir, ancak bu genellikle daha çok test / stubbing amaçlıdır. Bunun dışında, bir uygulamanın farklı bölümlerinde bir sorguyu yeniden kullanırken dikkatli olurum, çünkü o zaman n-zamanını değiştirebilecek bir şeye bağımlılık oluşturma riski vardır (n, sorguyu kullandığınız yerlerin sayısıdır).


1
1) Yanlış soruyu soruyorsun. Ne sıklıkta olduğu önemli değil, sadece bir kez olmak zorunda. Mevcut ORM seçeneklerinin sayısı göz önüne alındığında, zaten kullandığınızdan daha iyi bir seçenek olabilir. Şimdi soru şu oluyor: Yaptığınızda ne olur? Depo size güzel bir soyutlama sağlar. Orada bulundum ve keşke ilk etapta böyle bir soyutlama yapsaydım.
devnull

3
@devnull Kabul etmiyorum. En fazla bir kere olursa, kabul edilebilir bir risk olduğunu düşünürdüm. Yanlış seçim yapmaktan korkuyorsanız: birine karar vermeden önce daha fazla deneme yapın. Teorik olarak, böyle bir soyutlama kulağa hoş geliyor, ancak pratikte ORM'nizin api'sinin oldukça büyük bir bölümünü yeniden yaratırsınız, çünkü bir gün, bir yerde başka bir tane seçebilirsin. Benim için, bu çaba ve yedek kod ve korumak ve garanti etmek zorunda olduğunuz daha fazla kod. Ayrıca, bir ORM'yi değiştirmek tüm uygulamayı etkilememelidir; alan sınırları koymayı öğrenir.
Stefan Billiet

Depo için tek neden ORM değişikliği değildir. Uygulamanıza [dağıtılmış] önbellek eklemeniz gerekiyorsa - tüm değişiklikler depoda yapılacak ve veri erişim katmanındaki değişiklikler nedeniyle BL'niz değişmeyecektir.
Valery

Çoğu durumda dağıtılmış önbellek ORM içine yerleştirilmez mi?
user1450877

Bence ORM'ye bağlı. NHibernate veya EF'den daha hafif ORM ile gitmeye karar verebilirsiniz.
Valery

2

1) ORM'leri devre dışı bırakmak isterseniz ne yaparsınız, eğer onu bir depoda içermezseniz uygulamanızda belirli ORM kodunuz olur.

Şirketin aniden veri erişim teknolojisini değiştirmeye karar verdiği bir pozisyonda bulunmadım. Bu olursa, biraz çalışma gerekecektir. Arayüzler üzerinden veri erişim işlemlerini soyutlama eğilimindeyim. Depo bunu çözmenin bir yoludur.

Daha sonra veri erişim katmanımın somut bir şekilde uygulanması için farklı bir montaj yapacağım. Örneğin, ben olabilir:

Company.Product.Datave Company.Product.Data.EntityFrameworkmontajlar. İlk montaj tamamen arayüzler için kullanılacak, diğeri Entity Framework'ün veri erişim mantığının somut bir uygulaması olacaktı.

2) Bir ORM kullanılmadığında depo deseni hala geçerli mi ve veri erişimi ve nesne verilerini kendiniz doldurmak için ADO.net'i mi kullanıyorsunuz?

Hangi kalıbın geçerli olup olmadığına karar vermek size kalmış. Sunum katmanında bir depo deseni kullandım. Akılda tutulması gereken bir şey, insanların depolara sorumluluk atmaktan hoşlandığıdır. Bilmeden önce, depo sınıfınız dans edecek, şarkı söyleyecek ve her türlü şeyi yapacak. Bundan kaçınmak istersiniz.

GetAll, GetById, Update ve Delete sorumluluklarına sahip olarak başlayan bir depo sınıfı gördüm, ki bu iyi. Proje tamamlandığında, aynı sınıfta hiç bulunmaması gereken düzinelerce yöntem (sorumluluk) vardı. Örneğin GetByForename, GetBySurname, UpdateWithExclusions ve her türlü çılgınca şeyler.

Bu, sorguların ve komutların devreye girdiği yerdir.

3) ORM kullanıyorsanız, ancak yaygın olarak kullanılan sorguları sakladığınız veri havuzu modelini kullanmıyorsanız. Her sorguyu bir sınıf olarak temsil etmek ve örnekler oluşturmak için bir çeşit sorgu fabrikası bulundurmak akıllıca olur mu?

Depolar yerine sorgu ve komutları kullanmak çok iyi bir fikir. Aşağıdakileri yaparım:

  • Bir sorgu için arayüz tanımlayın. Bu birim testi yapmanıza yardımcı olacaktır. Örneğinpublic interface IGetProductsByCategoryQuery { ... }

  • Bir sorgu için somut uygulamayı tanımlayın. Bunları, seçtiğiniz IoC çerçevesi aracılığıyla enjekte edebileceksiniz. Örneğinpublic class GetProductsByCategoryQuery : IGetProductsByCategoryQuery

Şimdi deposu onlarca sorumlulukla kirletmek yerine, sorgularımı ad alanlarında gruplandırıyorum. Örneğin, yukarıdaki sorgu için bir arayüz şu ülkelerde Company.SolutionName.Products.Queriesyaşayabilir:Company.SolutionName.Products.Queries.Implementation

Verileri güncelleme veya kaldırma söz konusu olduğunda, komut desenini aynı şekilde kullanıyorum.

Bazıları buna katılmayabilir ve proje tamamlanmadan düzinelerce sınıfınız ve ad alanınız olacağını söyleyebilir. Evet yapacaksın. Benim fikrime göre, seçtiğiniz IDE'deki çözüme göz atabileceğiniz ve belirli bir bileşenin ne tür sorumluluklara sahip olduğunu anında görebileceğiniz için iyi bir şey. Bunun yerine bir havuz kalıbı kullanmaya karar verdiyseniz, sorumluluklarını çözmeye çalışan her bir depo sınıfının içine bakmanız gerekir.


Genel işlevler yerine komutlara sahip olma fikrini seviyorum. Bunların veri erişimi bağlamında nasıl uygulanacağı hakkında daha fazla bilgiyi nerede bulabilirim?
ankush981

1

SORUMLULUK REDDİ: Takip eden şey, söz konusu model hakkındaki anlayışım ve kısa deneyimime dayanmaktadır (yani Depo). Yanlış yapıyor olabilirim ... aslında, yanlış yaptığım için oldukça olumluyum :). Yani, bu bir cevap girişimi olsa da, aynı zamanda kılık değiştirmiş bir sorudur.

Çoğu durumda bir ORM olan veri erişim katmanını soyutlamak için Havuz desenini kullanıyorum. Şimdiye kadar LINQ to SQL ve EF için Oluşturma, Okuma, Güncelleme, Silme ve uygulama sınıfları için yöntemler içeren genel bir arayüzdür. Diskteki XML dosyalarına (onunla ne yapabileceğimin sadece vahşi bir örneği) yazan bir uygulama yapabilirim. ORM'ler tarafından desteklendiği için İş Birimi uygulamıyorum. Gerekirse, muhtemelen uygulayabilirim. Bu şekilde hoşuma gitti çünkü şimdiye kadar bana güzel bir ayrılık verdi. Daha iyi alternatifler olmadığını söylemiyorum.

Sorularınızı cevaplamak için:

  1. Beğenip beğenmediğinizde değişiklik olacaktır. Ve bir sürü uygulama yazdıysanız ve bunları korumak için zaman geldi, ancak mevcut ORM ile çalışmak için bir acı olduğunu hissediyorum ve değiştirmek istiyorsanız, böyle bir soyutlama yaptığınız için kendinizi öveceksiniz. Depo ya da başka bir desen / konsept olsun, kendinizi rahat hissettiğiniz her şeyi kullanın.
  2. Evet, veri erişimini ayırmak için kullandığınız sürece. Daha önce de belirttiğim gibi, düz dosyalara veri yazan bir uygulama yapabilirsiniz.
  3. Ben ince ayar yapmak istediğim sorgulara sahip olduğumda (ki bu çok fazla değil) için yaygın olarak kullanılan sorgularımı ve sorgu nesnelerini saklamak için depoyu kullanıyorum .

Size başka bir örnek vermek gerekirse, Umbraco'daki çocuklar DI konteynerini soyutladılar, sadece başka bir şeye geçmek isteyebilirler.


0

ORM, LINQ, istekli yükleme vb. Esneklik sunuyorsa, ekstra bir katmanın arkasına saklamam.
Ham sql (mikro ORM) içeriyorsa, yeniden kullanılabilirliği sağlamak için yine de "sorgu başına yöntem" kullanılmalıdır, böylece havuz kalıbı iyi bir uyum sağlar.

What do you do if you want to switch out ORMs? 
You would have ORM specific code in your application if you do not contain it in a repository.

Neden geçiş yapmanız gerekiyor?
İhtiyacınız olan özelliklerin çoğuna sahip olanı kullanılmalıdır. OrmX'in yeni bir sürümünün yeni özellikler getirmesi ve mevcut olandan daha iyi olduğu ortaya çıkabilir, ancak ... Orm'u
gizlemeyi seçerseniz, yalnızca tüm adayların ortak özelliklerini kullanabilirsiniz.
Örneğin Dictionary<string, Entity>, varlıklarınızdaki özellikleri kullanamazsınız çünkü ormY bu özellikleri kaldıramaz.

LINQ kullanıldığını varsayarsak, orm anahtarının çoğunluğu sadece kütüphane referanslarını değiştiriyor session.Query<Foo>()ve context.Foosderlenene kadar onunla veya benzeriyle değiştiriyor . Sıkıcı görev, ancak soyutlama katmanını kodlamaktan daha az zaman alır.

Is the repository pattern still valid when not using an ORM and you are using ADO.NET for data access and populating object data yourself?

Evet. Kod yeniden kullanılabilir olmalı ve bu, sql binası, nesne materyalizasyonu vb. Tek bir yerde (ayrı sınıf) koymak anlamına gelir. Ayrıca "XRepository" sınıfını çağırabilir ve ondan bir arabirim çıkarabilirsiniz.

If you use an ORM but not the repository pattern where do you keep commonly used queries? 
Would it be wise to represent each query as a class and have some sort of query factory to create instances?

LINQ kullanıldığını varsayarsak, bir sınıf sarıcısı IMHO'dan fazla olabilir. Daha güzel bir yol uzatma yöntemleri olacaktır

public static IQueryable<T> Published<T>(this IQueryable<T> source) where T : Page
{
    // at some point someone is going to forget to check that status
    // so it makes sense to extract this thing
    return source.Where(x => x.Status == Status.Published && x.PublishTime <= DateTime.UtcNow);
}

Birden fazla yerde kullanılan (veya potansiyele sahip) ve yeterince karmaşık olan (hata eğilimli) herhangi bir kod merkezi bir yere çıkarılmalıdır.

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.