2009-09-30 23 views
85

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

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

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

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

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

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

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

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

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

+9

+1। महान सवाल – griegs

+0

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

+0

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

उत्तर

39

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

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

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

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

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

बहुत यह एक उचित नाम देने के लिए किया जाएगा बेहतर - RegistrationService अर्थात

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

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

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

पी.एस.:

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

आप लिखने में सक्षम हो जाएगा:
इसके बजाय लेखन के तथाकथित common service locator का उपयोग करना बेहतर होगा लेकिन यह सिर्फ एक उदाहरण है।

+16

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

+3

हाहाहा ... मैं भंडार पैटर्न का उपयोग करने के लिए सलाह दे रहा हूं। हमेशा खुशी ... –

+1

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

5

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

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

क्या यह समझ में आता है? साथ ही, मैं समझता हूं कि इस मनोरंजक में सेवाओं की बात करना वास्तव में डीडीडी सिद्धांतों का पालन नहीं कर सकता है या नहीं, मैं ऐसा इसलिए करता हूं क्योंकि ऐसा लगता है।

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); 
} 

फिर आप प्राप्त कर सकते हैं सार आधार वर्ग से भंडार और जब तक पर सामान्य बहस के लिए अलग अपने एकल भंडार का विस्तार:

+1

नोपेथैट ज्यादा समझ में नहीं आता है। मैं वर्तमान समय में डीआई या आईओसी ढांचे का उपयोग नहीं करता क्योंकि मुझे अपनी प्लेट पर पर्याप्त मात्रा में मिला है। – chobo2

+1

यदि आप अपने रिपोज़ डब्ल्यू/बस एक नया() को तुरंत चालू कर सकते हैं, तो आप इसे आजमा सकते हैं ... सार्वजनिक सेवा Iplpl(): यह (नया रिपो 1, नया रिपो 2 ...) {} सेवा में एक अतिरिक्त निर्माता के रूप में। – neouser99

+0

निर्भरता इंजेक्शन? मैं पहले से ही ऐसा करता हूं लेकिन अभी भी यह सुनिश्चित नहीं करता कि आपका कोड डोंग क्या है और यह क्या हल करता है। – chobo2

2

मैं क्या कर रहा हूँ मैं एक सार आधार वर्ग इस प्रकार के रूप में परिभाषित किया है उदाहरण;

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

आदि ....

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

+0

तो क्या आप इस सब से निपटने के लिए एक सामान्य भंडार बनाने की कोशिश कर रहे हैं? – chobo2

+0

हां। अब तक सब ठीक है। –

+0

तो वास्तव में अद्यतन विधि कहां जाता है।जैसे कि आपको यह वी अपडेट पसंद है और यह एक टी इकाई में अपडेट हो गया है लेकिन वास्तव में कोई कोड अपडेट नहीं कर रहा है या वहां है? – chobo2

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) 
    { 
    } 

मैं भी एक DataContext जो Linq2SQL.dbml वर्ग का उपयोग कर बनाया गया था।

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

डीआरवाई के सवाल का जवाब नहीं देता है हालांकि मुझे नहीं लगता है।

+0

के रूप में चुना है, के लिए "रिपोजिटरी" क्या हो सकता है? और CreateInstance की तरह? सुनिश्चित नहीं है कि आपके पास जो कुछ भी है वह कर रहा है। – chobo2

+0

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

0

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

+0

मैं यहां एक +1 दूंगा, लेकिन उसने संकेत दिया है कि डीआई या आईओसी कंटेनर काफी विकल्प नहीं हैं (माना जाता है कि वे तीव्र आर्क का एकमात्र लाभ नहीं हैं)। मुझे लगता है कि वह कुछ मौजूदा कोड के लिए कुछ है जो वह काम कर रहा है। – neouser99

+0

एक इकाई माना जाता है? क्या वह पूरा डेटाबेस है? या वह डेटाबेस टेबल है? डीआई या आईओसी कंटेनर इस समय एक विकल्प नहीं हैं क्योंकि मैं सिर्फ यह नहीं जानना चाहता हूं कि अन्य 10 चीजों के बारे में मैं एक ही समय में सीख रहा हूं। वे कुछ हैं जो मैं अपनी साइट या मेरी अगली परियोजना के अगले संशोधन में देखूंगा। भले ही मुझे यकीन नहीं है कि यह साइट पर एक त्वरित नजरिया होगी और ऐसा लगता है कि आप निहिब्रेट का उपयोग करना चाहते हैं और मैं इस वर्तमान समय में linq के लिए linq का उपयोग कर रहा हूं। – chobo2

1

Here is an example FluentNHibernate का उपयोग कर एक सामान्य रिपोजिटरी कार्यान्वयन के। यह किसी भी वर्ग को बनाए रखने में सक्षम है जिसे आपने मैपर लिखा है। यह मैपर वर्गों के आधार पर आपके डेटाबेस को उत्पन्न करने में भी सक्षम है।

1

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

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