12

रिपब्लिकरी-आधारित समाधान के आधार के रूप में LINQ से SQL का उपयोग करके Subrecords लोड हो रहा है। मेरे कार्यान्वयन इस प्रकार है:रिपोजिटरी पैटर्न

WhereSomethingEqualsTrue() ... 

मेरा प्रश्न इस प्रकार है::

IRepository

FindAll 
FindByID 
Insert 
Update 
Delete 
तो मैं विस्तार तरीकों कि जैसे परिणाम क्वेरी करने के लिए उपयोग किया जाता है है

मेरे उपयोगकर्ता भंडार में एन भूमिकाएं हैं। क्या मैं भूमिकाओं का प्रबंधन करने के लिए एक भूमिका भंडार बना सकता हूं? मुझे चिंता है कि अगर मैं इस मार्ग पर जाता हूं तो मैं दर्जनों रिपोजिटरीज (तालिका में शामिल होने के अलावा लगभग 1 तालिका) बना दूंगा। प्रति तालिका एक रिपोजिटरी आम है?

उत्तर

31

यदि आप अपनी रिपोजिटरी को एक इकाई (तालिका) के लिए विशिष्ट बनाने के लिए बना रहे हैं, जैसे कि प्रत्येक इकाई में आपके आईआरपीपॉजिटरी इंटरफेस में विधियों की सूची है जो आपने ऊपर सूचीबद्ध की है, तो आप वास्तव में क्या कर रहे हैं Active Record का कार्यान्वयन है पैटर्न।

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

मैं आपकी पोस्ट से अनुमान लगा रहा हूं कि आपके पास seen this example है। इस उदाहरण के साथ समस्या यह है कि सभी भंडार आधार स्तर पर एक ही सीआरयूडी कार्यक्षमता साझा कर रहे हैं, लेकिन वह इससे परे नहीं जाते हैं और किसी भी डोमेन फ़ंक्शन को लागू नहीं करते हैं। उस उदाहरण में सभी रिपॉजिटरीज समान दिखते हैं - लेकिन हकीकत में, वास्तविक भंडार सभी समान दिखते नहीं हैं (हालांकि उन्हें अभी भी इंटरफेस किया जाना चाहिए), प्रत्येक के साथ जुड़े विशिष्ट डोमेन ऑपरेशंस होंगे।

आपका भंडार डोमेन प्रक्रिया अधिक तरह दिखना चाहिए:

userRepository.FindRolesByUserId(int userID) 
userRepository.AddUserToRole(int userID) 
userRepository.FindAllUsers() 
userRepository.FindAllRoles() 
userRepository.GetUserSettings(int userID) 

आदि ...

इन विशिष्ट कार्यों है कि आपके आवेदन अंतर्निहित डेटा पर प्रदर्शन करना चाहता है, और भंडार है कि प्रदान करना चाहिए। इसके बारे में सोचें क्योंकि रिपोजिटरी परमाणु संचालन के सेट का प्रतिनिधित्व करता है जो आप डोमेन पर करेंगे। यदि आप एक सामान्य भंडार के माध्यम से कुछ कार्यक्षमता साझा करना चुनते हैं, और विस्तार विधियों के साथ विशिष्ट भंडारों का विस्तार करते हैं, तो यह एक ऐसा दृष्टिकोण है जो आपके ऐप के लिए ठीक काम कर सकता है।

अंगूठे का एक अच्छा नियम यह है कि यह आपके आवेदन के लिए दुर्लभ होना चाहिए ताकि आपके ऑपरेशन को पूरा करने के लिए एकाधिक रिपॉजिटरीज़ को तुरंत चालू करने की आवश्यकता हो। आवश्यकता उत्पन्न होती है, लेकिन यदि आपके ऐप में प्रत्येक ईवेंट हैंडलर केवल उपयोगकर्ता के इनपुट को लेने के लिए छः रिपॉजिटरीज को जोड़ रहा है और इनपुट का प्रतिनिधित्व करने वाली इकाइयों को सही ढंग से चालू करता है, तो आपके पास शायद डिज़ाइन समस्याएं होंगी।

+1

वैसे आप वहां जाते हैं। हर दिन कुछ सीखो। मुझे अपना दृष्टिकोण समायोजित करने की आवश्यकता होगी :-) – Dylan

+0

हाँ। मैं इस जवाब के साथ कुछ भी सीखता हूं। मुझे पता था कि कई रिपॉजिटरीज़ होने के लिए तार्किक था लेकिन यह नहीं पता था कि प्रत्येक भंडार को समेकन के आसपास बनाया जाना चाहिए। कुल समझ में आता है। –

+0

उत्कृष्ट पोस्ट। –

4

प्रति तालिका एक रिपोजिटरी आम है?

नहीं, लेकिन आपके पास अभी भी कई रिपोजिटरी हो सकती हैं। आपको कुल मिलाकर एक भंडार बनाना चाहिए।

इसके अलावा, आप कर सकते हैं तो आप शायद सभी खजाने से सार कुछ कार्यक्षमता के लिए सक्षम हो सकता है ... और, जब से तुम Linq करने वाली Sql उपयोग कर रहे हैं, ...

आप एक आधार भंडार लागू कर सकते हैं जो एक सामान्य तरीके से यह सभी सामान्य कार्यक्षमता लागू करता है।

निम्नलिखित उदाहरण केवल इस बिंदु को साबित करने के लिए कार्य करता है। इसे शायद बहुत सुधार की जरूरत है ...

interface IRepository<T> : IDisposable where T : class 
    { 
     IEnumerable<T> FindAll(Func<T, bool> predicate); 
     T FindByID(Func<T, bool> predicate); 
     void Insert(T e); 
     void Update(T e); 
     void Delete(T e); 
    } 

    class MyRepository<T> : IRepository<T> where T : class 
    { 
     public DataContext Context { get; set; } 

     public MyRepository(DataContext context) 
     { 
      Context = Context; 
     } 

     public IEnumerable<T> FindAll(Func<T,bool> predicate) 
     { 
      return Context.GetTable<T>().Where(predicate); 
     } 

     public T FindByID(Func<T,bool> predicate) 
     { 
      return Context.GetTable<T>().SingleOrDefault(predicate); 
     } 

     public void Insert(T e) 
     { 
      Context.GetTable<T>().InsertOnSubmit(e); 
     } 

     public void Update(T e) 
     { 
      throw new NotImplementedException(); 
     } 

     public void Delete(T e) 
     { 
      Context.GetTable<T>().DeleteOnSubmit(e); 
     } 

     public void Dispose() 
     { 
      Context.Dispose(); 
     } 
    } 
+2

नहीं, प्रत्येक भंडार को एक समग्र रूट –

+0

@ जोहान्स हां के लिए दृढ़ता तर्क को समाहित करना चाहिए, लेकिन कैसे? –

+0

क्या आप कृपया बता सकते हैं कि क्लाइंट क्लास फ़ंक्शन का उपयोग कैसे करता है "टी FindByID (Func predicate)"। मैं एक कोड डेमो के लिए lloking हूँ। – Lijo

1

मेरे लिए रिपोजिटरी पैटर्न आपके डेटा एक्सेस पद्धति के चारों ओर एक पतली रैपर डालने के बारे में है। LINQ से SQL आपके मामले में, लेकिन NHibernate, दूसरों में हाथ से लुढ़का। जो मैंने खुद को पाया है वह एक भंडार-प्रति-तालिका बना रहा है, जिसके लिए यह बेहद सरल है (ब्रूनो सूचियों की तरह और आपके पास पहले से ही है)। चीजों को खोजने और सीआरयूडी संचालन करने के लिए यह ज़िम्मेदार है।

लेकिन फिर मेरे पास एक सेवा स्तर है जो समग्र जड़ों के साथ अधिक सौदों करता है, जैसा कि जोहान्स का उल्लेख है। मेरे पास GetExistingUser (int id) जैसी विधि के साथ उपयोगकर्ता सेवा होगी। यह उपयोगकर्ता को पुनर्प्राप्त करने के लिए आंतरिक रूप से UserRepository.GetById() विधि को कॉल करेगा। यदि आपकी व्यावसायिक प्रक्रिया के लिए GetExistingUser() द्वारा लौटाए गए उपयोगकर्ता वर्ग की आवश्यकता होती है तो उसे हमेशा उपयोगकर्ता की आवश्यकता होती है। IInInRoles() प्रॉपर्टी भरने के लिए, तो बस उपयोगकर्ता सेवा दोनों UserRepository और रोलरिपॉजिटरी पर निर्भर करती है। छद्म कोड में यह कुछ इस तरह दिखाई दे सकता है:

public class UserRep : IUserRepository 
{ 
    public UserRep(string connectionStringName) 
    { 
     // user the conn when building your datacontext 
    } 

    public User GetById(int id) 
    { 
     var context = new DataContext(_conString); 
     // obviously typing this freeform but you get the idea... 
     var user = // linq stuff 
     return user; 
    } 

    public IQueryable<User> FindAll() 
    { 
     var context = // ... same pattern, delayed execution 
    } 
} 

व्यक्तिगत तौर पर मैं आंतरिक रूप से scoped भंडार वर्गों होगा:

public class UserService 
{ 
    public UserService(IUserRepository userRep, IRoleRepository roleRep) {...} 
    public User GetById(int id) 
    { 
     User user = _userService.GetById(id); 
     user.Roles = _roleService.FindByUser(id); 
     return user; 
} 

userRep और roleRep एसक्यूएल करने के लिए अपने LINQ का निर्माण किया जाएगा कुछ इस तरह बिट्स और उपयोगकर्ता सेवा और अन्य XXXXX सेवा कक्षाएं सार्वजनिक हैं इसलिए अपने उपभोक्ताओं को सेवा API के ईमानदार रखें। तो फिर मैं रिपॉजिटरीज़ को डेटास्टोर से बात करने के कार्य से अधिक निकटता से जोड़ता हूं, लेकिन आपकी सेवा परत आपकी व्यावसायिक प्रक्रिया की आवश्यकताओं के अनुरूप अधिक निकटता से जुड़ी हुई है।

मैं अक्सर पाया है अपने आप को वास्तव में वस्तुओं के लिए LINQ के लचीलेपन और सभी सामान overthinking और का उपयोग कर IQuerable एट अल बजाय सिर्फ निर्माण सेवा तरीकों कि थूक से बाहर मैं वास्तव में क्या जरूरत है की।उपयोगकर्ता LINQ जहां उपयुक्त है लेकिन सशस्त्र बनाने के लिए सब कुछ करने की कोशिश मत करो।

public IList<User> ActiveUsersInRole(Role role) 
{ 
    var users = _userRep.FindAll(); // IQueryable<User>() - delayed execution; 
    var activeUsersInRole = from users u where u.IsActive = true && u.Role.Contains(role); 
    // I can't remember any linq and i'm type pseudocode, but 
    // again the point is that the service is presenting a simple 
    // interface and delegating responsibility to 
    // the repository with it's simple methods. 
    return activeUsersInRole; 
} 

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

1

अगर हम अपनी रिपोजिटरी परत को विस्तृत करते हैं तो विस्तृत जानकारी के अनुसार, हम अपनी सेवा परत में क्या डालते हैं। क्या हमें एक ही विधि कॉल दोहराना है, जिसमें हमारे नियंत्रकों या कोडबेइंड्स में उपयोग के लिए ज्यादातर संबंधित भंडार विधि में कॉल शामिल होंगे? यह मानता है कि आपके पास एक सेवा परत है, जहां आप अपना सत्यापन, कैशिंग, वर्कफ़्लो, प्रमाणीकरण/प्रमाणीकरण कोड लिखते हैं, है ना? या मैं आधार से दूर रास्ता हूँ?

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