एक नौकरी के साक्षात्कार के दौरान, मुझे यह बताने के लिए कहा गया था कि रिपॉजिटरी पैटर्न, ओआरएम के साथ काम करने के लिए एक अच्छा पैटर्न क्यों नहीं है जैसे कि एंटिटी फ्रेमवर्क। यह एक केस क्यों है?
एक नौकरी के साक्षात्कार के दौरान, मुझे यह बताने के लिए कहा गया था कि रिपॉजिटरी पैटर्न, ओआरएम के साथ काम करने के लिए एक अच्छा पैटर्न क्यों नहीं है जैसे कि एंटिटी फ्रेमवर्क। यह एक केस क्यों है?
जवाबों:
मैं रिपॉजिटरी पैटर्न के लिए एंटिटी फ्रेमवर्क के साथ काम नहीं करने का कोई कारण नहीं देखता हूं। रिपॉजिटरी पैटर्न एक अमूर्त परत है जिसे आपने अपने डेटा एक्सेस लेयर पर रखा है। आपकी डेटा एक्सेस लेयर शुद्ध ADO.NET संग्रहित प्रक्रियाओं से लेकर Entity Framework या XML फ़ाइल तक कुछ भी हो सकती है।
बड़ी प्रणालियों में, जहां आपके पास विभिन्न स्रोतों (डेटाबेस / एक्सएमएल / वेब सेवा) से आने वाले डेटा हैं, एक अमूर्त परत होना अच्छा है। इस परिदृश्य में रिपोजिटरी पैटर्न अच्छा काम करता है। मुझे विश्वास नहीं है कि पर्दे के पीछे क्या हो रहा है इसे छिपाने के लिए एंटिटी फ्रेमवर्क पर्याप्त अमूर्त है।
मैंने अपने डेटा एक्सेस लेयर विधि के रूप में एंटिटी फ्रेमवर्क के साथ रिपॉजिटरी पैटर्न का उपयोग किया है और अभी तक एक समस्या का सामना करना पड़ रहा है।
DbContext
रिपॉजिटरी के साथ अमूर्त करने का एक और फायदा यूनिट-टेस्टिबिलिटी है । आपके पास अपना IRepository
इंटरफ़ेस हो सकता है जिसमें 2 कार्यान्वयन हैं, एक (वास्तविक रिपॉजिटरी) जो DbContext
डेटाबेस और दूसरे से बात करने के लिए उपयोग करता है, FakeRepository
जो इन-मेमोरी ऑब्जेक्ट्स / मॉकडॉट डेटा को वापस कर सकता है। यह आपकी IRepository
इकाई-परीक्षण योग्य बनाता है , इस प्रकार कोड के अन्य भागों का उपयोग करता है IRepository
।
public interface IRepository
{
IEnumerable<CustomerDto> GetCustomers();
}
public EFRepository : IRepository
{
private YourDbContext db;
private EFRepository()
{
db = new YourDbContext();
}
public IEnumerable<CustomerDto> GetCustomers()
{
return db.Customers.Select(f=>new CustomerDto { Id=f.Id, Name =f.Name}).ToList();
}
}
public MockRepository : IRepository
{
public IEnumerable<CustomerDto> GetCustomers()
{
// to do : return a mock list of Customers
// Or you may even use a mocking framework like Moq
}
}
अब DI का उपयोग करके, आपको कार्यान्वयन मिलता है
public class SomeService
{
IRepository repo;
public SomeService(IRepository repo)
{
this.repo = repo;
}
public void SomeMethod()
{
//use this.repo as needed
}
}
एंटिटी फ्रेमवर्क के साथ रिपॉजिटरी पैटर्न का उपयोग न करने का सबसे अच्छा कारण? एंटिटी फ्रेमवर्क पहले से ही रिपॉजिटरी पैटर्न को लागू करता है। DbContext
आपका UoW (कार्य की इकाई) है और प्रत्येक DbSet
भंडार है। इसके ऊपर एक और परत को लागू करना न केवल निरर्थक है, बल्कि रखरखाव को कठिन बनाता है।
लोग पैटर्न के उद्देश्य को साकार किए बिना पैटर्न का पालन करते हैं। रिपॉजिटरी पैटर्न के मामले में, उद्देश्य निम्न स्तर के डेटाबेस क्वेरी तर्क को अमूर्त करना है। अपने कोड में वास्तव में SQL स्टेटमेंट लिखने के पुराने दिनों में, रिपॉजिटरी पैटर्न एक तरीका था जो आपके कोड बेस में बिखरे हुए अलग-अलग तरीकों से SQL को स्थानांतरित करने और इसे एक स्थान पर स्थानीय बनाने का एक तरीका था। एक ORM जैसे कि Entity Framework, NHibernate, आदि इस कोड अमूर्त के लिए एक प्रतिस्थापन है , और इस तरह, पैटर्न की आवश्यकता को नकारता है।
हालांकि, अपने ORM के शीर्ष पर एक अमूर्त बनाने के लिए एक बुरा विचार नहीं है, बस यूओडब्ल्यू / रिपॉजिटरी के रूप में जटिल कुछ भी नहीं है। मैं एक सेवा पैटर्न के साथ जाऊंगा, जहाँ आप एक एपीआई का निर्माण करते हैं जिसे आपका एप्लिकेशन बिना जाने या परवाह किए उपयोग कर सकता है कि डेटा एंटिटी फ्रेमवर्क, एनएचबर्नेट, या वेब एपीआई से आ रहा है या नहीं। यह बहुत सरल है, जैसा कि आप अपने एप्लिकेशन की डेटा को वापस करने के लिए अपने सेवा वर्ग में केवल तरीके जोड़ते हैं। यदि आप एक To-do ऐप लिख रहे थे, उदाहरण के लिए, आपके पास इस सप्ताह होने वाली वस्तुओं को वापस करने के लिए एक सेवा कॉल हो सकती है और अभी तक पूरी नहीं हुई है। आपका सभी ऐप जानता है कि अगर यह जानकारी चाहता है, तो वह उस पद्धति को कॉल करता है। उस पद्धति के अंदर और सामान्य रूप से आपकी सेवा में, आप एंटिटी फ्रेमवर्क या जो भी आप उपयोग कर रहे हैं, उसके साथ बातचीत करते हैं। फिर, यदि आप बाद में ORMs को स्विच करने या वेब API से जानकारी खींचने का निर्णय लेते हैं,
ऐसा लग सकता है कि रिपॉजिटरी पैटर्न का उपयोग करने के लिए यह एक संभावित तर्क है, लेकिन यहां महत्वपूर्ण अंतर यह है कि एक सेवा एक पतली परत है और पूरी तरह से पके हुए डेटा को वापस करने की दिशा में सक्षम है, बजाय इसके कि आप क्वेरी करना जारी रखें, जैसे भंडार।
DbContext
हैं । यहां तक कि कम संस्करणों में, आपको एक नकली उपयोग कर सकते हैं की तरह वर्ग मज़ाक उड़ाया साथ है, के बाद से , औजार एक iterface । DbContext
DbSet
DbSet
IDbSet
यहाँ एक आयेंड रहियन से लिया गया है: कयामत के गड्ढे में स्थापत्य: रिपॉजिटरी एब्सट्रैक्शन लेयर की बुराइयाँ
मुझे अभी तक यकीन नहीं है कि मैं उसके निष्कर्ष से सहमत हूं या नहीं। यह एक पकड़ -22 है - एक तरफ, यदि मैं क्वेरी-विशिष्ट डेटा पुनर्प्राप्ति विधियों के साथ अपने ईएफ संदर्भ को टाइप-विशिष्ट रिपॉजिटरी में लपेटता हूं, तो मैं वास्तव में इकाई कोड (प्रकार) का परीक्षण करने में सक्षम हूं, जो कि लगभग असंभव है अकेले फ्रेमवर्क। दूसरी ओर, मैं रिश्तों की समृद्ध क्वेरी और सिमेंटिक रखरखाव करने की क्षमता खो देता हूं (लेकिन तब भी जब मेरे पास उन विशेषताओं तक पूरी पहुंच होती है, मुझे हमेशा ऐसा लगता है कि मैं ईएफ या किसी अन्य ओआरएम के आसपास अंडे के छिलके पर चल रहा हूं या चुन सकता हूं। , क्योंकि मुझे कभी नहीं पता है कि इसके IQueryable कार्यान्वयन के तरीके क्या हो सकते हैं या समर्थन नहीं कर सकते हैं, क्या यह एक निर्माण के रूप में एक नेविगेशन संपत्ति संग्रह में मेरे जोड़ने की व्याख्या करेगा या केवल एक संघ होगा, चाहे वह आलसी या उत्सुक लोड हो रहा हो या बिल्कुल भी लोड न हो। डिफ़ॉल्ट, आदि, तो शायद यह बेहतर के लिए है। शून्य-प्रतिबाधा ऑब्जेक्ट-रिलेशनल "मैपिंग" पौराणिक जीव का कुछ है - शायद इसीलिए एंटिटी फ्रेमवर्क की नवीनतम रिलीज़ को "मैजिक यूनिकॉर्न" नाम दिया गया था।
हालांकि, क्वेरी-विशिष्ट डेटा पुनर्प्राप्ति विधियों के माध्यम से अपनी संस्थाओं को पुनः प्राप्त करने का मतलब है कि आपकी इकाई परीक्षण अब अनिवार्य रूप से सफेद-बॉक्स परीक्षण हैं और आपके पास इस मामले में कोई विकल्प नहीं है, क्योंकि आपको पहले से पता होना चाहिए कि परीक्षण के तहत इकाई किस रिपॉजिटरी विधि में जा रही है। इसे मॉक करने के लिए कॉल करें। और आप अभी भी वास्तव में स्वयं प्रश्नों का परीक्षण नहीं कर रहे हैं, जब तक कि आप एकीकरण परीक्षण भी नहीं लिखते हैं।
ये जटिल समस्याएं हैं जिन्हें एक जटिल समाधान की आवश्यकता है। आप इसे केवल यह दिखावा करके ठीक नहीं कर सकते हैं कि आपकी सभी इकाइयाँ उनके बीच कोई संबंध नहीं के साथ अलग-अलग प्रकार की हैं और प्रत्येक को अपने स्वयं के भंडार में रखती हैं। वैसे आप कर सकते हैं , लेकिन यह बेकार है।
अपडेट: मुझे एंटिटी फ्रेमवर्क के लिए एफर्ट प्रोवाइडर के उपयोग से कुछ सफलता मिली है । प्रयास एक इन-मेमोरी प्रदाता (ओपन सोर्स) है जो आपको परीक्षण में ईएफ का उपयोग करने की अनुमति देता है ठीक उसी तरह जिस तरह आप एक वास्तविक डेटाबेस के खिलाफ इसका उपयोग करेंगे। मैं इस परियोजना में सभी परीक्षणों को बदलने पर विचार कर रहा हूं, मैं इस प्रदाता का उपयोग करने के लिए काम कर रहा हूं, क्योंकि यह चीजों को इतना आसान बनाता है। यह एकमात्र समाधान है जो मैंने अब तक पाया है जो उन सभी मुद्दों को संबोधित करता है जिन्हें मैं पहले के बारे में बता रहा था। केवल एक चीज में थोड़ी देरी होती है जब मेरे परीक्षण शुरू करते हैं क्योंकि यह इन-मेमोरी डेटाबेस बना रहा है (यह ऐसा करने के लिए NMemory नामक एक अन्य पैकेज का उपयोग करता है), लेकिन मैं इसे वास्तविक समस्या के रूप में नहीं देखता हूं। एक कोड प्रोजेक्ट लेख है जो परीक्षण के लिए एफर्ट (बनाम एसक्यूएल सीई) का उपयोग करने की बात करता है।
DbContext
। अब आप पूरी तरह से नकली हो सकते हैं । भले ही, आप हमेशा मज़ाक कर सकते हैं DbSet
, और यह एंटिटी फ्रेमवर्क का मांस है, वैसे भी। एक स्थान (काम की इकाई) में DbContext
अपने DbSet
गुणों (रिपॉजिटरी) को रखने के लिए एक वर्ग से थोड़ा अधिक है , विशेष रूप से एक इकाई परीक्षण संदर्भ में, जहां सभी डेटाबेस इनिशियलाइज़ेशन और कनेक्शन सामान की आवश्यकता नहीं है या किसी भी तरह की आवश्यकता नहीं है।
आप शायद ऐसा क्यों करेंगे इसका कारण यह है कि यह थोड़ा बेमानी है। एंटिटी फ्रेमवर्क आपको कोडिंग और कार्यात्मक लाभ का एक धन देता है, इसीलिए आप इसका उपयोग करते हैं, यदि आप तब इसे लेते हैं और इसे एक रिपॉजिटरी पैटर्न में लपेटते हैं जो आप उन लाभों को दूर फेंक रहे हैं, तो आप किसी अन्य डेटा एक्सेस लेयर का उपयोग कर सकते हैं।
सिद्धांत रूप में मुझे लगता है कि यह डेटाबेस कनेक्शन तर्क को और अधिक आसानी से पुन: प्रयोज्य बनाने के लिए समझ में आता है, लेकिन नीचे दिए गए लिंक के रूप में, हमारे आधुनिक ढांचे अनिवार्य रूप से इस बात का ध्यान रखते हैं।
ISessionFactory
और ISession
आसानी से नकली हैं), यह DbContext
दुर्भाग्य से आसान नहीं है ...
रिपॉजिटरी पैटर्न का उपयोग करने का एक बहुत अच्छा कारण आपके व्यापार तर्क और / या आपके UI को System.Data.Elity से अलग करने की अनुमति देना है। इसके कई फायदे हैं, जिसमें इकाई परीक्षण में वास्तविक लाभ शामिल हैं, जिसमें वह फेक या मोक्स का उपयोग करने की अनुमति देता है।
हमें डुप्लिकेट लेकिन अलग-अलग एंटिटी फ्रेमवर्क DbContext के उदाहरणों में समस्याएँ आती हैं जब एक IoC कंटेनर जो कि नए () प्रकार के रिपॉजिटरी (उदाहरण के लिए एक UserRepository और एक GroupRepository उदाहरण है कि प्रत्येक DBContext से अपने स्वयं केbbet को कॉल करता है), कभी-कभी प्रति अनुरोध में कई संदर्भों का कारण बन सकता है। (एक एमवीसी / वेब संदर्भ में)।
अधिकांश समय यह अभी भी काम करता है, लेकिन जब आप उसके ऊपर एक सेवा परत जोड़ते हैं और उन सेवाओं को एक संदर्भ के साथ बनाई गई वस्तुओं को सही ढंग से संलग्न किया जाता है, तो बाल संग्रह को किसी अन्य संदर्भ में एक नई वस्तु के रूप में संलग्न किया जाता है, यह कभी-कभी विफल होता है और कभी-कभी नहीं होता है ' टी आवागमन की गति के आधार पर।
छोटे प्रोजेक्ट पर रिपॉजिटरी पैटर्न आज़माने के बाद मैं इसे इस्तेमाल न करने की दृढ़ता से सलाह देता हूं; इसलिए नहीं कि यह आपके सिस्टम को जटिल बनाता है, और इसलिए नहीं कि डेटा का मजाक उड़ाना दुःस्वप्न है, बल्कि इसलिए कि आपका परीक्षण बेकार हो जाता है !!
मॉकिंग डेटा आपको हेडर के बिना विवरण जोड़ने की अनुमति देता है, डेटाबेस की कमी का उल्लंघन करने वाले रिकॉर्ड्स को जोड़ें, और उन संस्थाओं को हटा दें जिन्हें डेटाबेस हटाने से इनकार करेगा। वास्तविक दुनिया में एक एकल अद्यतन कई तालिकाओं, लॉग, इतिहास, सारांश इत्यादि को प्रभावित कर सकता है, साथ ही अंतिम-संशोधित-दिनांक फ़ील्ड, ऑटो उत्पन्न कुंजी, गणना किए गए फ़ील्ड जैसे कॉलम।
वास्तविक डेटाबेस पर आपके परीक्षण को कम चलाने में आपको वास्तविक परिणाम मिलते हैं और आप न केवल अपनी सेवाओं और इंटरफेस बल्कि डेटाबेस व्यवहार का भी परीक्षण कर सकते हैं। आप जांच सकते हैं कि क्या आपकी संग्रहीत प्रक्रियाएं डेटा के साथ सही काम करती हैं, अपेक्षित परिणाम लौटाएं, या यह कि आपने जो रिकॉर्ड भेजा है वह वास्तव में हटा दिया गया है! इस तरह के परीक्षण भी ऐसे मुद्दों का पर्दाफाश कर सकते हैं जैसे संग्रहीत प्रक्रिया से त्रुटियों को उठाना, और हजारों ऐसे परिदृश्य।
मुझे लगता है कि अब तक पढ़े गए किसी भी लेख की तुलना में इकाई ढांचा रिपॉजिटरी पैटर्न को बेहतर तरीके से लागू करता है और यह उन चीजों से कहीं आगे निकल जाता है, जिन्हें वे पूरा करने की कोशिश कर रहे हैं।
रिपोजिटरी उन दिनों सबसे अच्छा अभ्यास था जहां हम XBase, AdoX और Ado.Net का उपयोग कर रहे थे, लेकिन इकाई के साथ !! (भंडार पर रिपॉजिटरी)
अंत में मुझे लगता है कि बहुत से लोग सीखने और रिपोजिटरी पैटर्न को लागू करने में बहुत समय लगाते हैं और वे इसे जाने देने से इनकार करते हैं। ज्यादातर खुद को साबित करने के लिए कि उन्होंने अपना समय बर्बाद नहीं किया।
माइग्रेशन के कारण इसकी: काम करने के लिए माइग्रेशन प्राप्त करना संभव नहीं है, क्योंकि कनेक्शन स्ट्रिंग वेब में रहता है ।config। लेकिन, DbContext रिपोजिटरी लेयर में रहता है। IDbContextFactory को डेटाबेस में कॉन्फ़िगरेशन स्ट्रिंग की आवश्यकता होती है। लेकिन ऐसा कोई तरीका नहीं है कि माइग्रेशन web.config से कनेक्शन स्ट्रिंग प्राप्त करता है।
चारों ओर काम कर रहे हैं, लेकिन मुझे अभी तक इसके लिए एक साफ समाधान नहीं मिला है!