2009-09-11 16 views
35

मैं बीडीडी/डीडीडी की खोज कर रहा हूं और परिणामस्वरूप रिपोजिटरी पैटर्न के उचित कार्यान्वयन के साथ आने का प्रयास कर रहा हूं। अब तक, इसे लागू करने के सर्वोत्तम तरीके से सर्वसम्मति को ढूंढना मुश्किल है। मैंने इसे निम्नलिखित भिन्नताओं तक उबालने की कोशिश की है, लेकिन मुझे यकीन नहीं है कि सबसे अच्छा तरीका कौन सा है।रिपोजिटरी पैटर्न को लागू करने का सबसे अच्छा तरीका?

संदर्भ के लिए मैं एक एएसपी.एमवीसी अनुप्रयोग का निर्माण एनएचबीरनेट के साथ बैक एंड के रूप में कर रहा हूं।

public interface IRepository<T> { 
     // 1) Thin facade over LINQ 
     T GetById(int id); 
     void Add(T entity); 
     void Update(T entity); 
     void Remove(T entity); 
     IQueryable<T> Find(); 
     // or possibly even 
     T Get(Expression<Func<T, bool>> query); 
     List<T> Find(Expression<Func<T, bool>> query); 
} 

public interface IRepository<T> { 
     // 2) Custom methods for each query 
     T GetById(int id); 
     void Add(T entity); 
     void Update(T entity); 
     void Remove(T entity); 
     IList<T> FindAll(); 
     IList<T> FindBySku(string sku); 
     IList<T> FindByName(string name); 
     IList<T> FindByPrice(decimal price); 
     // ... and so on 
} 

public interface IRepository<T> { 
     // 3) Wrap NHibernate Criteria in Spec pattern 
     void Add(T entity); 
     void Update(T entity); 
     void Remove(T entity); 
     IList<T> FindAll(); 
     IList<T> FindBySpec(ISpecification<T> specification); 
     T GetById(int id); 
} 


public interface IRepository<T> { 
     // 4) Expose NHibernate Criteria directly 
     T GetById(int id); 
     void Add(T entity); 
     void Update(T entity); 
     void Remove(T entity); 
     IList<T> FindAll(); 
     IList<T> Find(ICriteria criteria); 
     // .. or possibly 
     IList<T> Find(HQL stuff); 
} 

मेरे प्रारंभिक विचार हैं कि

1) देखने का एक दक्षता बिंदु से महान है, लेकिन के रूप में चीजों को अधिक जटिल हो मैं मुसीबत में हो सकता है।

2) बहुत थकाऊ लगता है और बहुत भीड़ वाले वर्ग के साथ समाप्त हो सकता है, लेकिन अन्यथा मेरे डोमेन तर्क और डेटा परत के बीच उच्च स्तर की अलगाव प्रदान करता है जो मुझे पसंद है।

3) प्रश्न लिखने के लिए सामने और अधिक काम मुश्किल लगता है, लेकिन केवल चश्मा परत को पार संदूषण सीमित करता है।

4) जटिल प्रश्नों के लिए मेरा सबसे कम पसंदीदा, लेकिन संभवतः सबसे प्रत्यक्ष कार्यान्वयन और संभावित रूप से अधिकांश डेटाबेस कुशल, हालांकि यह कॉलिंग कोड पर बहुत ज़िम्मेदारी रखता है।

+0

+1। मैंने रिपोजिटरी पैटर्न के साथ भी संघर्ष किया है। – TrueWill

+3

शायद आप जो खोज रहे हैं वह नहीं, लेकिन मुझे स्पेक पैटर्न का यह कार्यान्वयन वास्तव में अच्छा लगता है: http://mathgeekcoder.blogspot.com/2008/07/advanced-domain-model-queries-using.html। मुख्य रूप से क्योंकि यह आपको Linq2Sql/Linq2NHibernate/आदि का उपयोग करने देता है। –

+0

धन्यवाद ट्रूविल और धन्यवाद मार्टिन्हो, जो वास्तव में हाल ही में http: // stackoverflow पोस्ट किए गए किसी अन्य विषय से बहुत अच्छी तरह से संबंधित है।कॉम/प्रश्न/1408553/विनिर्देश-पैटर्न-बनाम-spec-in-bdd –

उत्तर

10

मुझे लगता है कि वे सभी अच्छे विकल्प हैं (शायद 4 को छोड़कर यदि आप खुद को निषेध करने के लिए टाई नहीं चाहते हैं), और आपको लगता है कि आपके वर्तमान प्रयास के आधार पर स्वयं को निर्णय लेने के लिए पेशेवरों और विपक्ष का विश्लेषण किया गया है । अपने आप को भी पर हरा मत करो।

मैं वर्तमान में 2 और 3 के बीच एक मिश्रण पर काम कर रहा हूँ मुझे लगता है कि:

public interface IRepository<T> 
{ 
     ... 
     IList<T> FindAll(); 
     IList<T> FindBySpec(ISpecification<T> specification); 
     T GetById(int id); 
} 

public interface ISpecificRepository : IRepository<Specific> 
{ 
     ... 
     IList<Specific> FindBySku(string sku); 
     IList<Specific> FindByName(string name); 
     IList<Specific> FindByPrice(decimal price); 
} 

और वहाँ भी आधार वर्ग (टी की) एक भंडार है।

+1

मुझे संदेह है कि # 2 का थोड़ा सा समाधान हर समाधान में रेंग जाएगा। –

1

मैं 1 का बीआईएफ प्रशंसक हूं क्योंकि मैं फ़िल्टर विधि और पेजिंग एक्सटेंशन विधियों को बना सकता हूं, मैं IQueryable <> खोज विधि के लिए वापसी मूल्यों पर लागू कर सकता हूं। मैं डेटा परत में एक्सटेंशन विधियों को रखता हूं और फिर व्यापार परत में फ्लाई पर निर्माण करता हूं। (पूरी तरह से शुद्ध नहीं, स्वीकार्य रूप से।)

बेशक, जब सिस्टम स्थिर हो जाता है तो मेरे पास एक ही एक्सटेंशन विधियों का उपयोग करके विशिष्ट खोज विधियों को बनाने का विकल्प होता है और Func <> का उपयोग करके ऑप्टिमाइज़ किया जाता है।

public interface IReadOnlyRepository<T,V> 
{ 
    V Find(T); 
} 

इस उदाहरण केवल पढ़ने के भंडार सिर्फ डेटाबेस से हो जाता है करता है में:

5

बातें हम क्या कर रहे हैं में से एक हमारे खजाने के सभी विभिन्न आवश्यकताओं तो हम इंटरफेस का एक संग्रह का निर्माण कर रहे हैं कि है। टी के लिए कारण, वी वी क्या भंडार द्वारा दिया जाता है और टी का प्रतिनिधित्व करता है क्या में पारित हो जाता है का प्रतिनिधित्व करता है, तो आप कुछ इस तरह कर सकता है:

public class CustomerRepository:IReadOnlyRepository<int, Customer>, IReadOnlyRepository<string, Customer> 
{ 
    public Customer Find(int customerId) 
    { 
    } 

    public Customer Find(string customerName) 
    { 
    } 
} 

मैं भी जोड़ें के लिए अलग इंटरफेस बना सकते हैं , अद्यतन और हटाएं। इस तरह अगर मेरे भंडार को व्यवहार की आवश्यकता नहीं है तो यह इंटरफेस को लागू नहीं करता है।

+0

यह दिलचस्प है। मुझे IReadonlyRepository का उपयोग करने के संभावित लाभों के बारे में सोचना होगा, लेकिन पहली नज़र में, मुझे यह पसंद है। साझा करने के लिए धन्यवाद। –

+0

यदि आपको यह उपयोगी लगता है तो क्या आप मेरा उत्तर अप-वोट कर सकते हैं? –

1

Linq के साथ राष्ट्रीय राजमार्ग का उपयोग करते समय अपने भंडार हो सकता है:

session.Linq<Entity>() 

विनिर्देशों चीजें हैं जो के साथ सौदा कर रहे हैं:

IQueryable<Entity> 

आप यह सब मुखौटा कर सकते हैं दूर अगर आप चाहते हैं, लेकिन यह एक है अमूर्त एक अमूर्त करने के लिए बहुत सारे काम करते हैं।

सरल अच्छा है। हां, एनएच डेटाबेस करता है, लेकिन यह बहुत अधिक पैटर्न प्रदान करता है। एनएएल पर निर्भर डीएएल के अलावा अन्य पापों से बहुत दूर है।

+0

लेकिन सीधे तर्क में सत्र का उपयोग करते हुए, सरल होने पर, नियंत्रण में उलझन का उल्लंघन होगा और परीक्षण करना वाकई मुश्किल होगा, है ना? –

+0

इस पर निर्भर करता है कि आप अपना कोड कैसे बनाते हैं। यदि आप यूनिट ऑफ वर्क पैटर्न का उपयोग करते हैं, तो ISession आपका यूओडब्ल्यू है। यदि आप चीजों को बेहतर बनाते हैं (मैं नहीं) तो आप ISession पर पतला मुखौटा डाल सकते हैं। तो फिर आप भंडार के साथ छोड़ दिया जाता है। मैं भंडारों को बहुत बुनियादी मानता हूं - ऑब्जेक्ट प्राप्त करें, ऑब्जेक्ट सहेजें, ऑब्जेक्ट्स को संग्रह के रूप में बेनकाब करें (ISession यह सब करता है)। क्वेरीज/चश्मा IQueryable द्वारा संभाला जा सकता है। यदि आपके पास डोमेन तर्क है जो ISession के आधार पर समाप्त होता है तो यह एक रिपोजिटरी के आधार पर समाप्त हो जाता। ये दोनों समान रूप से खराब परिस्थितियां हैं। – anonymous

+0

तो आइसियान 'सबकुछ करें' इंटरफ़ेस का थोड़ा सा हो सकता है। यही कारण है कि इसे एक और इंटरफ़ेस के पीछे डालने पर यह और अधिक स्पष्ट हो सकता है कि इसका उपयोग कैसे किया जा रहा है (IUnitOfWork, IRepository , आदि)। मुझे लगता है कि हिस्सा व्यक्तिगत वरीयता है, और मैं इंजीनियरिंग पर सही अमूर्तता पर काफी समय नहीं लगाऊंगा। – anonymous

0

भंडार

LosTechies

http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/10/wither-the-repository.aspx

इसके अलावा के जिमी Bogard द्वारा एक प्रासंगिक लेख, सुझाव # 2 संस्करण कुछ टिप्पणियों के साथ एक और त्वरित लेख वास्तव में है सूख एक DOA पैटर्न और नहीं एक भंडार।

http://fabiomaulo.blogspot.com/2009/06/linq-and-repository.html

22

वहाँ भी दृष्टिकोण "ऊपर में से कोई नहीं" के लिए एक अच्छा तर्क है।

सामान्य भंडारों के साथ समस्या यह है कि आप यह मानते हैं कि आपके सिस्टम में सभी ऑब्जेक्ट्स सभी चार सीआरयूडी संचालन का समर्थन करेंगे: बनाएं, पढ़ें, अपडेट करें, हटाएं। लेकिन जटिल प्रणालियों में, आपके पास ऐसी ऑब्जेक्ट्स होंगी जो केवल कुछ संचालन का समर्थन करती हैं। उदाहरण के लिए, आपके पास ऐसी ऑब्जेक्ट्स हो सकती हैं जो केवल पढ़ने योग्य हों, या ऑब्जेक्ट्स जो बनाई गई हों लेकिन कभी अपडेट न हों।

आप रीड, डिलीट इत्यादि के लिए छोटे इंटरफेस में आईरिपोजिटरी इंटरफ़ेस को तोड़ सकते हैं, लेकिन यह बहुत तेज़ी से गन्दा हो जाता है।

ग्रेगरी यंग एक अच्छा तर्क (डीडीडी/सॉफ्टवेयर लेयरिंग परिप्रेक्ष्य से) बनाता है कि प्रत्येक भंडार को केवल उस डोमेन या ऑब्जेक्ट के लिए विशिष्ट संचालन का समर्थन करना चाहिए जो आप काम कर रहे हैं। यहां उसका आलेख generic repositories पर है।

और वैकल्पिक दृश्य के लिए, इस Ayende blog post देखें।

+1

मैं सहमत हूं। मैं बस इतना जोड़ूंगा कि इसका मतलब यह नहीं है कि आपके पास सामान्य कार्यान्वयन नहीं हो सकता है, आपके पास सामान्य जेनेरिक इंटरफ़ेस नहीं होना चाहिए। आपके पास सभी विधियों की सुरक्षा के साथ एक अमूर्त रिपोजिटरी (और कोई आईरिपॉजिटरी इंटरफ़ेस) हो सकता है। प्रत्येक विशिष्ट भंडार तब इसे बढ़ा सकता है और ISpecificRepository इंटरफ़ेस को लागू करने के लिए वांछित विधियों को सार्वजनिक कर सकता है। – svallory

+0

दरअसल! मेरे अनुभव में रिपोजिटरी पैटर्न को लागू करने का सबसे अच्छा तरीका है * इसे * लागू नहीं करना है। इसके बजाए, उपयोग करने में आसान बनाने के लिए एक अच्छा ओआरएम एपीआई (जैसे जावा में जेपीए) और एक "एप्लीकेशनडेटाबेस" कक्षा का उपयोग करें। जावा ईई ऐप के लिए यह मेरी पसंद है, वैसे भी; मुझे लगता है कि यह अतिरिक्त "EntityAbcRepository" कक्षाओं का समूह होने से एप्लिकेशन कोड को सरल, छोटा और अधिक समेकित रखता है। –

1

मेरा मानना ​​है कि यह आपकी आवश्यकताओं पर निर्भर करता है। आपके द्वारा उपयोग किए जाने वाले अन्य डिज़ाइन पैटर्न के संयोजन के साथ भंडार के बारे में सोचना महत्वपूर्ण है। अंत में, यह बहुत निर्भर करता है कि आप भंडार से क्या अपेक्षा करते हैं (इसका उपयोग करने के मुख्य कारण क्या हैं)।

क्या आपको सख्त परत बनाने की आवश्यकता है (उदाहरण के लिए आपको भविष्य में एनएचबीर्नेट को इकाई फ्रेमवर्क के साथ प्रतिस्थापित करने की आवश्यकता होगी)? क्या आप विशेष रूप से भंडार विधियों के लिए परीक्षण लिखना चाहते हैं?

भंडार बनाने का कोई अच्छा तरीका नहीं है। केवल कुछ ही तरीके हैं और यह निश्चित रूप से आपके ऊपर है, आपकी आवश्यकताओं के लिए सबसे व्यावहारिक क्या है। समय पर प्रश्न के लिए

संबंधित मुद्दे