2012-03-22 5 views
6

वेब अनुप्रयोग परिदृश्यों में, डेटा पुनर्प्राप्ति के संबंध में आमतौर पर दो आवश्यकताएं होती हैं: 1. सभी प्रश्नों को वैकल्पिक रूप से पर पेज़ किया जाना आवश्यक है। उपयोगकर्ता द्वारा आवश्यक "फ़िल्टरिंग" क्वेरी के बहुत सारे हैं (उदाहरण के लिए खोज व्यक्ति के नाम और मेल और आयु) द्वारा 3. छंटाई प्रश्नों कुछ clientside ग्रिडवेब अनुप्रयोगों में एनएचबर्ननेट क्वेरी रणनीतियों

और निश्चित रूप से संयुक्त मामले से गर्भित: छानने, पृष्ठांकित प्रश्नों जो हल कर रहे हैं :)

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

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

अन्य डेवलपर ऐसी आवश्यकताओं को कैसे प्रबंधित करते हैं?

अग्रिम

उत्तर

7

रिपोजिटरीज, generic repositories और IQueryable का खुलासा करने वाले भंडार एक बहुत ही गर्म बहस है।

नीचे की रेखा एक भंडार है जो जेनेरिक है या खुलासा करता है IQueryable एक असली भंडार नहीं है, यह केवल आपकी डेटा परत का एक अमूर्त है।

अब यह एक बुरी बात नहीं है लेकिन इसे एक भंडार नहीं कहें, इसे कॉल करें। डेटा लेयर अबास्ट्रक्शन आपको अपने यूआई में कुछ डालने की अनुमति देता है जहां आप यूआई में अपने डेटा लेयर फ्रेमवर्क को लीक किए बिना इकाइयों को पढ़ते और लिखते हैं। आप निश्चित रूप से ISession इंजेक्ट कर सकते हैं और इसके साथ किया जा सकता है।

public interface IRepository<T> {} 

public class NHibernateRepository<T> : IRepository<T> 
{ 
    private ISession session; 

    public NHibernateRepository(ISession session) 
    { 
     this.session = session; 
    } 

    T Get(object id) { return session.GetById<T>(id)); } 

    IQueryable<T> Query { get { return session.Query<T>(); } 
} 

new NHibernateRepository<Customer>(session).Query().Where(customer => customer.Name == Fred); 

लेकिन यदि आप कुछ पुन: प्रयोज्य तर्क को पकड़ने और अपनी सेवाओं या यूआई और आपका डेटा स्तर के बीच एक स्पष्ट अनुबंध प्रदान करना चाहते हैं तो एक Repository सिर्फ इतना है कि नहीं करता है। आप स्पष्ट विधियों को परिभाषित करते हैं जो कहता है कि यह क्या प्राप्त कर रहा है और कैसे।इसके अतिरिक्त एक भंडार के साथ आप केवल aggregate roots का पर्दाफाश करना चाहते हैं, ये मूल इकाइयां हैं जिनके लिए आपका अन्य डेटा लटका हुआ है, ये Customer और Supplier जैसी चीजें हो सकती हैं। आप किसी पते पर सीधे पहुंचने की कोशिश नहीं करेंगे, फिर आप एक ग्राहक को लोड करेंगे और फिर उसके पते पर पूछेंगे। आप जो चीजें आपूर्ति करते हैं उसके आधार पर आप आपूर्तिकर्ताओं की एक सूची लोड करेंगे लेकिन आप 'आइटम रिपोजिटरी' के माध्यम से नहीं जाएंगे। मेरे उदाहरण सबसे अच्छे नहीं हो सकते हैं लेकिन वे आपको एक विचार देते हैं।

public class CustomerRepository 
{ 
    public Customer GetCustomerWithName(string name); 
} 

public class SupplierRepository 
{ 
    public IEnumerable<Supplier> GetSuppliersWhoStockItem(string itemName) 
} 

अंत में अगर आपके साहसी आप CQRS को देखने के लिए चाहते हो सकता है, यह एक विषय यहाँ की रूपरेखा तैयार करने लेकिन उदाहरण के बहुत देखते हैं की बड़ी है।

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

+0

धन्यवाद Bronumski , मुझे लगता है कि मैं एक संयुक्त अपमान लेगा: वेब सेवाओं द्वारा जेनेरिक प्रश्नों को संभालने के लिए वेब सेवाओं और अतिरिक्त IQueryable-इंटरफ़ेस द्वारा बुलाए जाने वाले अच्छी तरह से परिभाषित विधियां। – mbue

1

में धन्यवाद आप अपने भंडार एक IQueryable प्रदान कर सकता है और ActionMethod यह पता लगाने क्या प्रदर्शित करने के लिए करते हैं। उदाहरण के लिए:

public System.Linq.IQueryable<Models.MyModel> Query() 
    { 
     return mSession.Query<Models.MyModel>(); 
    } 
3

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

http://richarddingwall.name/2010/06/15/brownfield-cqrs-part-1-commands/

http://codebetter.com/gregyoung/2009/01/20/ddd-specification-or-query-object/

http://devlicio.us/blogs/casey/archive/2009/02/13/ddd-command-query-separation-as-an-architectural-concept.aspx

http://blog.jonathanoliver.com/2009/10/dddd-why-i-love-cqrs/

http://www.udidahan.com/2007/03/28/query-objects-vs-methods-on-a-repository/

3

आप एक समग्र रूट की गणना करने के लिए एक रिपोजिटरी का उपयोग करते हैं। अक्सर पर्याप्त, आपके नियंत्रक एक समग्र रूट के साथ काम करते हैं, जिसे आप फ़िल्टर कर सकते हैं, सॉर्ट इत्यादि। उपयोगकर्ता को आवश्यकता होती है।

इसलिए, मैं पहले से ही उल्लेख किया गया है कि लाइनों के साथ एक भंडार का उपयोग करें।

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

मामलों के इन प्रकार में, मैं भी ICommand/IQuery परिभाषित किया है, एक राष्ट्रीय राजमार्ग आधार कार्यान्वयन के साथ (जैसा कोई सामान्य Repository करता है) पाइपलाइन सामान की देखभाल करने के लिए।

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

मेरा मतलब यह है कि मेरा क्या मतलब है इसका एक कच्चा उदाहरण है। ध्यान दें कि मैं एक मनमाने ढंग से ICommandProvider का उपयोग करता हूं, जो कुछ ऑब्जेक्ट है जो आवश्यकतानुसार कमांड के नए उदाहरण बनाता है (यदि आपको एक ऑपरेशन में कई कमांड जारी करने की आवश्यकता है)। मैं अपने आदेशों को एक आईओसी के साथ पंजीकृत करूंगा और प्रदाता उदाहरणों को बनाने के लिए प्रदाता के साथ काम करूँगा। एक नियंत्रक में

public interface ICommand 
{ 

} 

public interface ICommandProvider 
{ 
    TCommand Create<TCommand>() 
     where TCommand : ICommand; 

} 

public interface IQuery<TResult> : ICommand 
{ 
    TResult Execute(); 
} 

public class NhCommand : ICommand 
{ 
    // plumbing stuff here, like finding the current session 
} 

public class DelinquentAccountViewModel 
{ 
    public string AccountName { get; set; } 
    public decimal Amount { get; set; } 
} 

public interface IDelinquentAccountsQuery : IQuery<IEnumerable<DelinquentAccountViewModel>> 
{ 
    void AmountGreaterThan(decimal amount); 
    // you could define members for specifying sorting, etc. here 
} 

public class DelinquentAccountsQuery : NhCommand 
{ 
    public IEnumerable<DelinquentAccountViewModel> Execute() 
    { 
     // build HQL and execute results, resulting in a list of DelinquentAccountViewModels 
     // using _amountGreaterThan as a parameter 
     return null; 
    } 

    private Decimal _amountGreaterThan; 

    public void AmountGreaterThan(Decimal amount) 
    { 
     _amountGreaterThan = amount; 
    } 
} 

प्रयोग कुछ इस तरह हो सकता है:

public class DelinquentAccountsController : Controller 
{ 
    protected ICommandProvider CommandProvider { get; private set; } 

    public DelinquentAccountsController(ICommandProvider commandProvider) 
    { 
     CommandProvider = commandProvider; 
    } 

    public ActionResult Index(decimal amount) 
    { 
     var query = CommandProvider.Create<IDelinquentAccountsQuery>(); 
     query.AmountGreaterThan(amount); 
     return View(query.Execute()); 

    } 
} 

कुछ भी नहीं कहते हैं तो आप अपने डेटा का उपयोग के सभी एक आदेश/क्वेरी का उपयोग नहीं कर सकते, लेकिन इसे और अधिक काम है की तुलना में मैं की जरूरत है। मुझे लगता है कि मानक भंडार दृष्टिकोण (NHBernate के खिलाफ LINQ का उपयोग करके) मेरे अनुप्रयोगों की आवश्यक डेटा पहुंच के 95% या उससे अधिक संभालता है।

1

इमो ओआरएम पहले से ही पर्याप्त अमूर्त है। आपको इसके शीर्ष पर भंडार की आवश्यकता नहीं है। यदि आप कुछ सेटिंग के साथ फ्लाई पर ओआरएम बदलने जा रहे हैं तो आपको केवल अमूर्तता की आवश्यकता है। कहां, छोड़ें, ले लो, ऑर्डरबी आदि ओआरएम अज्ञेयवादी हैं और IQueryable को उजागर करके उपयोग किया जा सकता है। लेकिन कुछ विशेषताएं ओआरएम विशिष्ट हैं (जैसे fetch बनाम।शामिल हैं) और उन वास्तव में बदसूरत खजाने (मिलियन तरीकों या मिलियन मानकों के साथ विधि)

मैं आम तौर पर सिर्फ विस्तार तरीकों

public static class QueryExtensions 
{ 
    public static IQueryable<T> Published(this IQueryable<T> pages) where T : IPage 
    { 
     return pages.Where(p => p.State == PageState.Public && p.Published <= DateTime.UtcNow); 
    } 
    public static IQueryable<T> By(this IQueryable<T> pages, User author) where T : IPage 
    { 
     return pages.Where(p => p.Author == author); 
    } 

    public static IEnumerable<Foo> AdvancedThing(this ISession session, string text) 
    { 
     // I get all the power of NHibernate :) 
     return session.CreateQuery("...").SetString("text", text).List<Foo>(); 
    } 
} 

बनाने के लिए और कार्रवाई के तरीकों में सीधे ISession का उपयोग कर

var posts = session.Query<Post>().By(user).Published().FetchMany(p => p.Tags).ToList(); 

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

  • कोई संबंधित समस्या नहीं^_^