क्या जेनेरिक रिपॉजिटरी के लिए एक वास्तविक लाभ है?


28

एक नए ऐप ( उदाहरण ) के लिए जेनेरिक रिपॉजिटरी बनाने के फायदों पर कुछ लेखों के माध्यम से पढ़ रहा था । यह विचार अच्छा लगता है क्योंकि यह एक ही रिपॉजिटरी का उपयोग करने के लिए एक ही बार में कई अलग-अलग इकाई प्रकारों के लिए कई काम करता है:

IRepository repo = new EfRepository(); // Would normally pass through IOC into constructor 
var c1 = new Country() { Name = "United States", CountryCode = "US" };
var c2 = new Country() { Name = "Canada", CountryCode = "CA" };
var c3 = new Country() { Name = "Mexico", CountryCode = "MX" };
var p1 = new Province() { Country = c1, Name = "Alabama", Abbreviation = "AL" };
var p2 = new Province() { Country = c1, Name = "Alaska", Abbreviation = "AK" };
var p3 = new Province() { Country = c2, Name = "Alberta", Abbreviation = "AB" };
repo.Add<Country>(c1);
repo.Add<Country>(c2);
repo.Add<Country>(c3);
repo.Add<Province>(p1);
repo.Add<Province>(p2);
repo.Add<Province>(p3);
repo.Save();

हालांकि, रिपॉजिटरी के कार्यान्वयन के बाकी हिस्सों में लाइनक पर भारी निर्भरता है:

IQueryable<T> Query();
IList<T> Find(Expression<Func<T,bool>> predicate);
T Get(Expression<Func<T,bool>> predicate);
T First(Expression<Func<T,bool>> predicate);
//... and so on

इस रिपॉजिटरी पैटर्न ने एंटिटी फ्रेमवर्क के लिए शानदार काम किया, और बहुत ज्यादा DbContext / DbSet पर उपलब्ध तरीकों की 1 से 1 मैपिंग की पेशकश की। लेकिन एंटिटी फ्रेमवर्क के बाहर अन्य डेटा एक्सेस प्रौद्योगिकियों पर लाइनक की धीमी गति को देखते हुए, यह DbContext के साथ सीधे काम करने से क्या फायदा होता है?

मैंने रिपॉजिटरी के पेटाकोको संस्करण को लिखने का प्रयास किया , लेकिन पेटाकोको लाइनक एक्सप्रेशंस का समर्थन नहीं करता है, जो एक सामान्य IRepository इंटरफ़ेस को बहुत बेकार बनाता है जब तक कि आप इसे केवल मूल GetAll, GetById, Add, Update, Delete, और Save के लिए उपयोग न करें आधार वर्ग के रूप में विधियाँ और उसका उपयोग। फिर आपको सभी "जहां" खंडों को संभालने के लिए विशेष विधियों के साथ विशिष्ट रिपॉजिटरी तैयार करनी होगी जिन्हें मैं पहले एक विधेय के रूप में पारित कर सकता था।

क्या जेनेरिक रिपॉजिटरी पैटर्न एंटिटी फ्रेमवर्क के बाहर किसी भी चीज के लिए उपयोगी है? यदि नहीं, तो कोई व्यक्ति सीधे एंटिटी फ्रेमवर्क के साथ काम करने के बजाय इसका उपयोग क्यों करेगा?


मूल लिंक मेरे नमूना कोड में उपयोग किए जा रहे पैटर्न को प्रतिबिंबित नहीं करता है। यहाँ एक ( अद्यतन लिंक ) है।



1
क्या वास्तव में सवाल "जेनेरिक रिपॉजिटरी के एडवांटेज" के बारे में है या अधिक "जेनेरिक रिपॉजिटरी इंटरफेस के पीछे जटिल प्रश्नों को कैसे छिपाएं" है? क्या यह संभव हो सकता है कि अगर इसका इंटरफ़ेस और उपयोग लाइनक पर निर्भर करता है? हमारे रिपोजिटरी में एक QueryByExample विधि है जो खोज तकनीक से पूरी तरह से स्वतंत्र है और कार्यान्वयन को स्थानांतरित करने की अनुमति देगा।
k3b

"यह मुझे कई अलग-अलग इकाई प्रकारों के लिए कई चीजों को करने के लिए एक ही रिपॉजिटरी का उपयोग करने देता है" => क्या यह मुझे या आपको सिर्फ गलत समझा गया है कि एक सामान्य रिपॉजिटरी क्या है (उल्लिखित लेख के संबंध में)? मेरे लिए, सामान्य रिपॉजिटरी का मतलब हमेशा सभी रिपोज को एक ही वर्ग या इंटरफ़ेस से जोड़ना है, एक एकल रिपॉजिटरी का उदाहरण न होना जो सभी प्रकार की संस्थाओं की दृढ़ता का प्रबंधन करता है ...
guillaume31

जवाबों:


35

एंटिटी फ्रेमवर्क के लिए सामान्य रिपॉजिटरी और भी बेकार है (और IMHO भी खराब)। यह जो पहले से ही प्रदान किया गया है IDbSet<T>(जो कि btw है। सामान्य रिपॉजिटरी) के लिए कोई अतिरिक्त मूल्य नहीं लाता है ।

जैसा कि आप पहले ही यह तर्क पा चुके हैं कि जेनेरिक रिपॉजिटरी को अन्य डेटा एक्सेस तकनीक के लिए कार्यान्वयन द्वारा प्रतिस्थापित किया जा सकता है क्योंकि यह बहुत कमजोर है क्योंकि यह आपके खुद के Linq प्रदाता को लिखने की मांग कर सकता है।

सरलीकृत इकाई परीक्षण के बारे में दूसरा आम तर्क भी गलत है क्योंकि इन-मेमोरी डेटा स्टोरेज के साथ रिपॉजिटरी / सेट का उपयोग करना Linq प्रदाता को एक और एक के साथ बदल देता है जिसमें विभिन्न क्षमताएं होती हैं। Linq-to-इकाइयों प्रदाता केवल Linq सुविधाओं के सबसेट का समर्थन करता है - यह भी IQueryable<T>इंटरफ़ेस पर उपलब्ध सभी तरीकों का समर्थन नहीं करता है। डेटा एक्सेस लेयर और बिज़नेस लॉजिक लेयर्स के बीच एक्सप्रेशन ट्री शेयर करना, डेटा एक्सेस लेयर के किसी भी फ़ेकिंग को रोकता है - क्वेरी लॉजिक को अलग किया जाना चाहिए।

यदि आप मजबूत "सामान्य" अमूर्तता चाहते हैं तो आपको अन्य पैटर्न भी शामिल करने होंगे। इस मामले में आपको अमूर्त क्वेरी भाषा का उपयोग करने की आवश्यकता होती है, जिसे उपयोग की गई डेटा एक्सेस लेयर द्वारा समर्थित विशिष्ट क्वेरी भाषा में रिपॉजिटरी द्वारा अनुवादित किया जा सकता है। इसे स्पेसिफिकेशन पैटर्न द्वारा नियंत्रित किया जाता है। लाइनक ऑन IQueryableस्पेसिफिकेशन है (लेकिन अनुवाद के लिए प्रदाता की आवश्यकता होती है - या कुछ कस्टम विजिटर अभिव्यक्ति ट्री को क्वेरी में अनुवाद करते हैं) लेकिन आप अपने स्वयं के सरलीकृत संस्करण को परिभाषित कर सकते हैं और इसका उपयोग कर सकते हैं। उदाहरण के लिए NHibernate मानदंड एपीआई का उपयोग करता है। अभी भी सबसे सरल तरीका विशिष्ट तरीकों के साथ विशिष्ट रिपॉजिटरी का उपयोग कर रहा है। यह तरीका लागू करने के लिए सबसे सरल है, परीक्षण में सरल और इकाई परीक्षणों में नकली से सरलतम है क्योंकि क्वेरी तर्क पूरी तरह से छिपा हुआ है और अमूर्त के पीछे अलग हो गया है।


बस एक त्वरित सवाल है, NHibernate है ISessionजो आसानी से सामान्य इकाई परीक्षण प्रयोजनों के लिए नकली है, और मैं ख़ुशी से 'रिपॉजिटरी' को छोड़ दूंगा जब EF के साथ भी काम कर रहा हूँ - लेकिन क्या इसे फिर से बनाने का कोई आसान, सीधा तरीका है? कुछ ISessionऔर जैसा कि ISessionFactory, 'क्योंकि वहाँ नहीं IDbContextहै जहाँ तक मैं बता सकता हूँ ...
Patryk iewiek

कोई नहीं है IDbContext- यदि आप चाहते हैं कि IDbContextआप बस एक बना सकते हैं और इसे अपने व्युत्पन्न संदर्भ पर लागू कर सकते हैं।
लादिस्लाव मृका

तो आप कह रहे हैं कि हर रोज़ MVC ऐप के लिए, IDbSet <T> को रिपॉजिटरी पैटर्न के बारे में पूरी तरह से भूलने के लिए एक अच्छा पर्याप्त सामान्य भंडार प्रदान करना चाहिए। विशेष स्थितियों को छोड़कर, जहाँ आपको अपने MVC प्रोजेक्ट में किसी भी DAL संदर्भ की अनुमति नहीं है।
ProfK

1
अच्छा उत्तर। कुछ डेवलपर्स बिना किसी कारण के केवल अमूर्त की एक और परत बनाते हैं। IMO, EF को जेनेरिक रिपॉजिटरी की जरूरत नहीं है और न ही काम की एक यूनिट (वे बिल्ड-इन हैं)
ashraf

1
IDbSet <T> एंटिटी फ्रेमवर्क पर निर्भरता के साथ एक सामान्य रिपॉजिटरी है, जो एंटिटी फ्रेमवर्क पर निर्भरता को दूर करने के लिए जेनेरिक रिपॉजिटरी का उपयोग करने के उद्देश्य को पराजित करता है।
जोएल मैकबेथ

7

मुद्दा रिपॉजिटरी पैटर्न नहीं है। डेटा प्राप्त करने और आप इसे कैसे प्राप्त कर रहे हैं के बीच एक अमूर्तता होना एक अच्छी बात है।

यहां मुद्दा कार्यान्वयन का है। यह मानते हुए कि फ़िल्टरिंग के लिए एक मनमाना अभिव्यक्ति सबसे अच्छा है।

अपनी सभी वस्तुओं के लिए एक रिपॉजिटरी का काम करना सीधे तौर पर थोड़े चूक जाता है। डेटा ऑब्जेक्ट्स शायद ही कभी होंगे यदि कभी व्यावसायिक वस्तुओं को सीधे मैप करें। टी में फ़िल्टर करने के लिए पासिंग इन स्थितियों में बहुत कम समझ में आता है। और बहुत अधिक कार्यक्षमता प्रदान करने से यह गारंटी मिलती है कि एक अलग प्रदाता के साथ आने पर आप सभी का समर्थन नहीं कर सकते।


तो यह अधिक समझ में आता है कि GetById (int id), SortedList (), आदि जैसे विशिष्ट तरीकों के साथ डेटा ऑब्जेक्ट, या कसकर संबंधित वस्तुओं के समूह के लिए एक रिपॉजिटरी है? क्या मैं रिपॉजिटरी से डेटा ऑब्जेक्ट्स की सूची लौटा रहा हूं, या उन्हें आवश्यक फ़ील्ड के साथ व्यावसायिक ऑब्जेक्ट में बदल रहा हूं? किंडा ने सोचा कि सेवा / व्यवसाय की परत में क्या हुआ था।
सैम

1
@ ससम - मैं अधिक विशिष्ट रिपॉजिटरी का पक्ष लेता हूं, हां। यदि वे अनुवाद कर रहे हैं या नहीं, तो इस बात पर निर्भर करता है कि चीजें कहां बदल सकती हैं। यदि आपका डोमेन अच्छी तरह से परिभाषित है, तो मैं डोमेन के आकार में चीजें लौटाऊंगा। यदि डेटा अच्छी तरह से परिभाषित है, तो मैं डेटा संरचनाओं के आकार में चीजें लौटाऊंगा। यदि कोई नहीं है, तो मेरे पास एक ऐसी इकाई होगी जो निर्माण करने के लिए अच्छी तरह से परिभाषित आधार के रूप में कार्य करती है और फिर उसी से / से अनुकूलन करती है।
तेलस्टिन

1
ऐसा कोई कारण नहीं है कि आपके पास विशिष्ट रिपॉजिटरी नहीं हो सकती हैं जो सामान्य सामान को एक सामान्य रिपॉजिटरी में सौंपती हैं, लेकिन अधिक जटिल कॉल के लिए अतिरिक्त रिपॉजिटरी-विशिष्ट तरीके भी हैं। मैंने इसे कई बार इस तरह से देखा है।
एरिक किंग

@ EricKing मेरे पास भी है, और यह वहां अच्छा था, लेकिन यह कुछ अमूर्त लीक करने के लिए जाता है क्योंकि आम सामान केवल इस बात के लिए मौजूद है कि डेटा संग्रहीत कैसे किया जाता है (GetByID उदाहरण के लिए ID के साथ तालिकाओं की आवश्यकता होती है)।
तेलस्टिन

@ टेलस्टाइन हां, मैं इससे सहमत हूं, लेकिन यह विशिष्ट रिपॉजिटरी के साथ भी होता है। रिसाव अमूर्त जेनेरिक रिपॉजिटरी के लिए विशिष्ट नहीं हैं। (वाह, क्या मैं और अधिक अनाड़ी हो सकता है?)
एरिक किंग

2

जेनेरिक डेटा लेयर (रिपॉजिटरी एक विशेष प्रकार की डेटा लेयर है) का मूल्य कोड को कॉलिंग कोड पर अंतर्निहित या कम प्रभाव के साथ अंतर्निहित भंडारण तंत्र को बदलने की अनुमति देता है।

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

जेनेरिक डेटा लेयर बनाने का सबसे प्रभावी तरीका विभिन्न प्रकार के डेटा स्रोतों को जानना है जो एप्लिकेशन पहले से उपयोग करेगा। जैसा कि आपने देखा है, LINQ या SQL को सार्वभौमिक मानना ​​एक समस्या हो सकती है। नए डेटा स्टोर को फिर से अपडेट करने की कोशिश करने से परिणाम फिर से लिखना होगा।

[संपादित करें: निम्नलिखित जोड़ा गया।]

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


1

डेटाबेस के ऊपर एक कोड लेयर होना लगभग सभी मामलों में सार्थक है। मैं आम तौर पर उक्त कोड में "GetByXXXXX" पैटर्न पसंद करूंगा - यह आपको यूआई को डेटा इंटरफ़ेस अव्यवस्था से मुक्त रखते हुए आवश्यकतानुसार प्रश्नों का अनुकूलन करने देता है।

जेनेरिक का लाभ उठाना निश्चित रूप से उचित खेल है - एक Load<T>(int id)विधि होने के कारण कई मायने रखता है। लेकिन LINQ के चारों ओर रिपॉजिटरी का निर्माण 2010 के दशक में थोड़े अतिरिक्त प्रकार की सुरक्षा के साथ sql प्रश्नों को छोड़ने के बराबर है।


0

खैर, प्रदान किए गए लिंक के साथ मैं देख सकता हूं कि यह एक के लिए एक आसान आवरण हो सकता है DataServiceContext, लेकिन कोड हेरफेर को कम नहीं करता है और न ही पठनीयता में सुधार करता है। इसके अलावा, पहुंच DataServiceQuery<T>में बाधा है, लचीलेपन को सीमित करने .Where()और .Single()। न ही AddRange()विकल्प दिए गए हैं। न ही Delete(Predicate)प्रदान किया जाता है जो उपयोगी हो सकता है ( repo.Delete<Person>( p => p.Name=="Joe" );जो-एस को हटाने के लिए)। आदि।

निष्कर्ष: ऐसा एपीआई देशी एपीआई को बाधित करता है और इसे कुछ सरल कार्यों तक सीमित करता है।


तुम सही हो। मेरे नमूने कोड में मेरे पास मौजूद पैटर्न का उपयोग करते हुए यह लेख नहीं था। जब मैं घर पहुंचूंगा तो लिंक खोजने की कोशिश करूंगा।
सैम

अद्यतन लिंक प्रश्न के नीचे जोड़ा गया।
सैम

-1

मैं हाँ कहूँगा"। आपके डेटा मॉडल के आधार पर, एक अच्छी तरह से विकसित जेनेरिक रिपॉजिटरी डेटा एक्सेस टियर लीनर, एनटर, और बहुत अधिक मजबूत बना सकती है।

इस लेख की श्रृंखला पढ़ें ( @ क्रिस-प्रैट द्वारा ):

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.