रिपॉजिटरी पैटर्न का सही तरीके से उपयोग कैसे करें?


86

मैं सोच रहा हूं कि मुझे अपनी रिपॉजिटरी कैसे समूहीकृत करनी चाहिए? उदाहरण के रूप में मैंने asp.net mvc पर देखा और मेरी पुस्तकों में वे मूल रूप से प्रति डेटाबेस तालिका में एक रिपॉजिटरी का उपयोग करते हैं। लेकिन यह बहुत सारे रिपॉजिटरी की तरह लगता है जिसके कारण आपको कई रिपॉजिटरी को बाद में मॉकिंग और सामान के लिए कॉल करना पड़ता है।

इसलिए मैं अनुमान लगा रहा हूं कि मुझे उनका समूह बनाना चाहिए। हालांकि मुझे यकीन नहीं है कि उन्हें समूह कैसे बनाया जाए।

अभी मैंने अपनी सभी पंजीकरण सामग्री को संभालने के लिए एक पंजीकरण रिपॉजिटरी बनाई। हालाँकि, ऐसी 4 तालिकाएँ हैं जिन्हें मुझे अपडेट करने की आवश्यकता है और इससे पहले कि मेरे पास ऐसा करने के लिए 3 रिपॉजिटरी हों।

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

एक स्थान लॉगिन हो सकता है (यदि कुंजी समाप्त नहीं हुई है तो जांचें)।

तो इस स्थिति में मैं क्या करूंगा? कोड फिर से लिखें (DRY तोड़ें)? इन 2 रिपॉजिटरी को एक साथ मिलाने की कोशिश करें और उम्मीद करें कि किसी अन्य तरीके से किसी भी तरीके की आवश्यकता नहीं है (जैसे कि शायद मेरे पास एक ऐसा तरीका हो सकता है जो यह जाँचता है कि उपयोगकर्ता नाम का उपयोग किया जाता है - शायद मुझे इसकी आवश्यकता कहीं और होगी)।

इसके अलावा, अगर मैं उन्हें एक साथ मिला देता हूं तो मुझे या तो 2 रिपेरिटरी में एक ही रिपॉजिटरी में जाने के लिए 2 सर्विस लेयर की जरूरत होगी क्योंकि मुझे लगता है कि किसी साइट के 2 अलग-अलग हिस्सों के लिए सभी लॉजिक लंबे होंगे और मुझे ValidateLogin (), ValleateRegistrationForm () जैसे नाम रखने होंगे। , वल्दिअतेलोगिनरिट्रीवेपासवर्ड () और आदि।

या किसी भी तरह से रिपॉजिटरी को कॉल करें और बस एक अजीब सा लगने वाला नाम है?

यह सिर्फ एक रिपॉजिटरी बनाने के लिए कठिन लगता है जिसका एक सामान्य पर्याप्त नाम है ताकि आप इसे अपने आवेदन के कई स्थानों के लिए उपयोग कर सकें और अभी भी समझ में आए और मुझे नहीं लगता कि रिपॉजिटरी में एक और रिपॉजिटरी को कॉल करना एक अच्छा अभ्यास होगा?


11
+1। बड़ा सवाल है।
30:09

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

मैं मूल रूप से आपके जैसा ही कर रहा हूं और यदि आपके पास एक linq2sql वर्ग है जो 1 से अधिक रिपॉजिटरी में उपयोग किया जाता है और मुझे DRY को तोड़ने वाली तालिका संरचना को बदलने की आवश्यकता है। आदर्श से कम। मैं अब इसे थोड़ा बेहतर बनाता हूं, इसलिए मुझे एक से अधिक बार linq2sql वर्ग का उपयोग करने की आवश्यकता नहीं है, जो मुझे लगता है कि चिंताओं का अच्छा पृथक्करण है, लेकिन मैं एक दिन की उम्मीद करता हूं जब यह मेरे लिए एक वास्तविक मुद्दा होने जा रहा है।
30:09

मैंने यहां एक समान प्रश्न (लेकिन समान नहीं) पूछा: stackoverflow.com/questions/910156/…
Grokys

हां, लेकिन सभी स्थितियों के लिए इसकी योजना बनाना कठिन लगता है। जैसा मैंने कहा कि मैं एक प्रमाणीकरण में लॉगिन और पंजीकरण को मर्ज कर सकता हूं और 2 अलग-अलग परतें हैं। कि शायद मेरी समस्या हल हो जाएगी। लेकिन अगर मेरी साइट के प्रोफाइल पेज को मैं कहूं तो क्या होगा, जो भी कारण हो, मैं उन्हें उनकी कुंजी दिखाना चाहता हूं (शायद मैं htem इसे या कुछ और बदल दूंगा)। अब मैं DRY को क्या तोड़ूं और वही बात लिखूं? या एक रिपॉजिटरी बनाने की कोशिश करें जो किसी भी तरह इन तालिकाओं के सभी 3 को एक अच्छे नाम के साथ फिट कर सके।
चोबो 2

जवाबों:


41

एक बात जो मैंने गलत की थी जब रिपॉजिटरी पैटर्न के साथ खेला गया था - आपकी तरह, मैंने सोचा कि टेबल रिपॉजिटरी 1: 1 से संबंधित है। जब हम Domain Driven Design से कुछ नियम लागू करते हैं - समूहन रिपॉजिटरी समस्या अक्सर गायब हो जाती है।

रिपोजिटरी प्रति एग्रिगेट रूट के अनुसार होनी चाहिए न कि टेबल के नीचे। इसका मतलब है - यदि इकाई को अकेले नहीं रहना चाहिए (अर्थात - यदि आपके पास Registrantविशेष रूप से भाग लेता है Registration) - यह सिर्फ एक इकाई है, तो उसे भंडार की आवश्यकता नहीं है, इसे अद्यतन किया जाना चाहिए / समग्र रूट के भंडार के माध्यम से इसे पुनः प्राप्त / बनाया जाना चाहिए। अंतर्गत आता है।

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

लेकिन यह हमें कैस्केड रिपॉजिटरी तक सीमित नहीं करता है ( यदि आवश्यक हो तो रिपॉजिटरी Registrationको Licenseरिपॉजिटरी को संदर्भित करने की अनुमति दी जाती है )। यह Licenseसीधे Registrationवस्तु से सीधे भंडार (अधिमान्य - आईओसी के माध्यम से) को संदर्भित करने के लिए हमें प्रतिबंधित नहीं करता है ।

बस प्रौद्योगिकियों द्वारा प्रदान की गई जटिलताओं या किसी गलतफहमी के माध्यम से अपने डिजाइन को चलाने की कोशिश न करें। में खजाने समूहन ServiceXसिर्फ इसलिए कि आप 2 खजाने का निर्माण नहीं करना चाहती अच्छा विचार नहीं है।

बेहतर होगा कि इसे उचित नाम दिया जाए - RegistrationServiceयानी

लेकिन सेवाओं को सामान्य रूप से बचा जाना चाहिए - वे अक्सर कारण होते हैं जो एनीमिक डोमेन मॉडल की ओर ले जाते हैं ।

संपादित करें:
IoC का उपयोग करना शुरू करें। यह वास्तव में निर्भरता के इंजेक्शन के दर्द को कम करता है।
लिखने के बजाय:

var registrationService = new RegistrationService(new RegistrationRepository(),  
      new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());

आप लिख पाएंगे:

var registrationService = IoC.Resolve<IRegistrationService>();

Ps को तथाकथित सामान्य सेवा लोकेटर का उपयोग करना बेहतर होगा लेकिन यह केवल एक उदाहरण है।


17
Hahaha ... मैं सेवा लोकेटर का उपयोग करने के लिए सलाह दे रहा हूं। हमेशा यह देखने के लिए खुशी होती है कि अतीत में मैं कितना गूंगा था।
अर्निस लैप्सा

1
@ अर्निस ऐसा लगता है जैसे आपकी राय बदल गई है - मुझे दिलचस्पी है कि अब आप इस सवाल का अलग तरह से जवाब कैसे देंगे?
11:14 बजे एनसीएम

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

2
@ डायवर्टर नहीं, बिल्कुल नहीं। उन्हें अभी भी अज्ञानता से दूर रहना चाहिए। आप कुल रूट को बाहर से प्राप्त करते हैं और उस पर कॉल विधि करते हैं जो काम करता है। मेरे डोमेन मॉडल में शून्य संदर्भ हैं, बस मानक .net फ्रेमवर्क वाले। इसे प्राप्त करने के लिए, आपके पास समृद्ध डोमेन मॉडल और उपकरण होने चाहिए जो पर्याप्त स्मार्ट हों (NHibernate चाल करता है)।
अर्निस लैप्सा

1
इसके विपरीत। एक से अधिक ग्रैगेट बनाने का अर्थ है कि आप पीके या इंडेक्स का उपयोग कर सकते हैं। उन संबंधों का लाभ उठाने की तुलना में बहुत तेजी से जो ईएफ उत्पन्न करता है। छोटी रूट एग्रीगेट, उन पर प्रदर्शन प्राप्त करना आसान है।
jgauffin

5

एक बात जो मैंने संबोधित करने के लिए शुरू की है वह वास्तव में एन रिपॉजिटरी को लपेटने वाली सेवाओं को विकसित करना है। उम्मीद है कि आपके डीआई या आईओसी ढांचे को आसान बनाने में मदद मिल सकती है।

public class ServiceImpl {
    public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { }
}

क्या इसका कोई मतलब है? इसके अलावा, मैं समझता हूं कि इस मनोर में सेवाओं का बोलना वास्तव में DDD सिद्धांतों का पालन कर सकता है या नहीं, मैं सिर्फ इसलिए करता हूं क्योंकि यह काम करने लगता है।


1
Nopethat बहुत मतलब नहीं है। मैं इस मौजूदा समय में DI या IoC फ्रेमवर्क का उपयोग नहीं करता हूं क्योंकि मैं अपनी प्लेट पर पर्याप्त था क्योंकि यह है।
चोबो 2

1
यदि आप अपने रेपो w / सिर्फ एक नए () को इंस्टेंट कर सकते हैं, तो आप यह कोशिश कर सकते हैं ... सार्वजनिक सेवाइम्प्ल (): यह (नया रेपो 1, नया रेपो 2 ...) {} सेवा में एक अतिरिक्त निर्माता के रूप में।
neouser99 14

निर्भरता अन्तःक्षेपण? मैं ऐसा पहले से ही कर रहा हूं लेकिन अभी भी यह सुनिश्चित नहीं है कि आपका कोड क्या है और यह क्या हल करता है।
चोबो 2

मैं विशेष रूप से रिपॉजिटरी के विलय के बाद जा रहा हूं। किस कोड का कोई मतलब नहीं है? यदि आप DI का उपयोग कर रहे हैं, तो उत्तर में कोड इस अर्थ में काम करेगा कि आपका DI फ्रेमवर्क उन IRepo सेवाओं को इंजेक्ट करेगा, टिप्पणी कोड में यह मूल रूप से DI करने के लिए केवल एक छोटा सा काम है (मूल रूप से आपका कोई पैरामीटर निर्माता 'इंजेक्शन' नहीं है) आपकी सेवा में निर्भरता)।
neouser99

मैं पहले से ही DI का उपयोग करता हूं इसलिए मैं बेहतर परीक्षण कर सकता हूं। मेरी समस्या यह है कि यदि आप अपनी सेवा की परतें बनाते हैं और नामों के विस्तृत विवरण के साथ रिपॉजिट करते हैं। फिर अगर आपको कभी भी उन्हें कहीं और उपयोग करने की आवश्यकता होती है, तो यह पंजीकरण कॉलिंग सर्विस लियर की तरह अजीब कॉलिंग दिखाई देगी, जो किसी अन्य वर्ग में RegRepo को कॉल करता है जैसे कि प्रोफाइलक्लास। इसलिए मैं आपके उदाहरण से नहीं देख रहा हूं कि आपकी पूरी तरह से क्या हो रहा है। जैसे यदि आप एक ही सेवा की परत में बहुत अधिक रिपोज करना शुरू करते हैं तो आपके पास इतना अलग-अलग व्यापार तर्क और सत्यापन तर्क होगा। चूंकि सेवा परत में आप आमतौर पर सत्यापन तर्क में डालते हैं। इतने सारे मुझे और चाहिए ...
चोबो 2

2

मैं क्या कर रहा हूँ मैं एक सार आधार वर्ग निम्नानुसार परिभाषित किया गया है:

public abstract class ReadOnlyRepository<T,V>
{
     V Find(T lookupKey);
}

public abstract class InsertRepository<T>
{
     void Add(T entityToSave);
}

public abstract class UpdateRepository<T,V>
{
     V Update(T entityToUpdate);
}

public abstract class DeleteRepository<T>
{
     void Delete(T entityToDelete);
}

तब आप अमूर्त बेस क्लास से रिपॉजिटरी प्राप्त कर सकते हैं और अपने एकल रिपॉजिटरी का विस्तार कर सकते हैं जब तक कि सामान्य तर्क उदाहरण के लिए भिन्न होते हैं;

public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>,
                                     ReadOnlyRepository<string, IRegistrationItem> 

आदि....

मुझे अलग-अलग रिपॉजिटरी की आवश्यकता है क्योंकि हमारे कुछ रिपॉजिटरी पर प्रतिबंध है और यह हमें अधिकतम लचीलापन देता है। उम्मीद है की यह मदद करेगा।


तो इस सब से निपटने के लिए एक सामान्य रिपॉजिटरी बनाने की आपकी कोशिश?
चोबो 2

तो वास्तव में अद्यतन विधि कहने में क्या जाता है। जैसे आपको यह V अपडेट पसंद है और यह एक T एंटेरियो यूडेट में पास होता है लेकिन वास्तव में इसे अपडेट करने वाला कोई कोड नहीं है या है?
चोबो 2

हां .. अपडेट विधि में कोड होगा क्योंकि आप एक वर्ग लिखेंगे जो सामान्य रिपॉजिटरी से उतरता है। कार्यान्वयन कोड Linq2SQL या ADO.NET या आपके डेटा एक्सेस कार्यान्वयन तकनीक के रूप में आपने जो भी चुना है, वह हो सकता है
माइकल मैन

2

मेरे पास मेरी रिपॉजिटरी क्लास है और हाँ मैं टेबल / एरिया रिपॉजिटरी में विस्तार करता हूं लेकिन फिर भी मुझे कभी-कभी DRY तोड़ना पड़ता है।

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MvcRepository
{
    public class Repository<T> : IRepository<T> where T : class
    {
        protected System.Data.Linq.DataContext _dataContextFactory;

        public IQueryable<T> All()
        {
            return GetTable.AsQueryable();
        }

        public IQueryable<T> FindAll(Func<T, bool> exp)
        {
            return GetTable.Where<T>(exp).AsQueryable();
        }

        public T Single(Func<T, bool> exp)
        {
            return GetTable.Single(exp);
        }

        public virtual void MarkForDeletion(T entity)
        {
            _dataContextFactory.GetTable<T>().DeleteOnSubmit(entity);
        }

        public virtual T CreateInstance()
        {
            T entity = Activator.CreateInstance<T>();
            GetTable.InsertOnSubmit(entity);
            return entity;
        }

        public void SaveAll()
        {
            _dataContextFactory.SubmitChanges();
        }

        public Repository(System.Data.Linq.DataContext dataContextFactory)
        {
            _dataContextFactory = dataContextFactory;
        }

        public System.Data.Linq.Table<T> GetTable
        {
            get { return _dataContextFactory.GetTable<T>(); }
        }

    }
}

संपादित करें

public class AdminRepository<T> : Repository<T> where T: class
{
    static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString);

    public AdminRepository()
        : base( dc )
    {
    }

मेरे पास एक डेटोनेक्स्ट भी है जो Linq2SQL.dbml वर्ग का उपयोग करके बनाया गया था।

इसलिए अब मेरे पास ऑल एंड फाइंड जैसी मानक कॉलों को लागू करने वाला एक मानक रिपॉजिटरी है और मेरे एडमिनरिपेटरी में मेरे पास विशिष्ट कॉल हैं।

हालांकि मुझे नहीं लगता कि DRY के सवाल का जवाब नहीं है।


क्या "रिपोजिटरी" के लिए? और CreateInstance पसंद है? यकीन नहीं है कि आपके पास जो कुछ भी है वह सब कर रहा है।
चोबो 2

यह कुछ भी के रूप में सामान्य है। मूल रूप से आपको अपने क्षेत्र (क्षेत्र) के लिए एक विशिष्ट भंडार होना चाहिए। मेरे AdminRepository के लिए ऊपर दिए गए संपादन देखें।
दु: ख

1

यहां फ्लुएंनहाइबरनेट का उपयोग करते हुए एक सामान्य रिपॉजिटरी कार्यान्वयन का एक उदाहरण है। यह किसी भी वर्ग को मनाने में सक्षम है जिसके लिए आपने मैपर लिखा है। यह मैपर वर्गों के आधार पर आपके डेटाबेस को बनाने में भी सक्षम है।


1

रिपोजिटरी पैटर्न एक खराब डिजाइन पैटर्न है। मैं कई पुराने .नेट प्रोजेक्ट्स के साथ काम करता हूं और यह पैटर्न आमतौर पर "डिस्ट्रिब्यूटेड ट्रांजैक्शंस", "पार्टिकल रोलबैक" और "कनेक्शन पूल एग्जॉस्ट" एरर का कारण बनता है, जिससे बचा जा सकता है। समस्या यह है कि पैटर्न आंतरिक रूप से कनेक्शन और लेन-देन को संभालने की कोशिश करता है, लेकिन उन्हें नियंत्रक स्तर पर नियंत्रित किया जाना चाहिए। इसके अलावा EntityFramework पहले से ही बहुत सारे तर्कों का सार करता है। मैं साझा कोड का पुन: उपयोग करने के बजाय सेवा पैटर्न का उपयोग करने का सुझाव दूंगा।


0

मेरा सुझाव है कि आप शार्प आर्किटेक्चर को देखें । वे प्रति इकाई एक भंडार का उपयोग करने का सुझाव देते हैं। मैं वर्तमान में अपनी परियोजना में उपयोग कर रहा हूं और परिणामों से प्रसन्न हूं।


मैं यहां +1 देता, लेकिन उन्होंने संकेत दिया है कि DI या IoC कंटेनर काफी विकल्प नहीं हैं (बशर्ते वे केवल तीव्र लाभ का लाभ न हों)। मैं अनुमान लगा रहा हूँ कि कुछ मौजूदा कोड है जो वह काम कर रहा है।
neouser99 14

एक इकाई क्या माना जाता है? क्या वह पूरा डेटाबेस है? या वह एक डेटाबेस तालिका है? डीआई या आईओसी कंटेनर इस समय कोई विकल्प नहीं हैं क्योंकि मैं यह नहीं सीखना चाहता कि अन्य 10 चीजों को मैं एक ही समय में सीख रहा हूं। वे कुछ हैं जो मैं अपनी साइट या मेरे अगले प्रोजेक्ट के अपने अगले संशोधन में देखूंगा। भले ही मुझे यकीन नहीं हो रहा है कि यह साइट पर एक त्वरित नज़र होगी और ऐसा लगता है कि आप nirbrate का उपयोग करना चाहते हैं और मैं इस समय linq से sql का उपयोग कर रहा हूं।
चोबो 2
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.