2013-01-08 14 views
7

मैं अक्सर publishStart, publishEnd जैसे क्षेत्रों से चयन करता है सीमित करने के लिए की जरूरत है, activeLinq विस्तार विधि

मैं कई अलग अलग तालिकाओं में इन क्षेत्रों की है। तो केवल पंक्तियों चयनित होना चाहिए, कि कर रहे हैं

a: active == true; 
b: publishStart < now; 
c: publishEnd > now; 

तो, उदाहरण के लिए:

db.myTable.SingleOrDefault(a => (a.ID == _theID 
      //now the active and start-end part:    
         && ((a.publishEnd > DateTime.Now) || (a.publishEnd == null)) 
         && ((a.publishStart <= DateTime.Now) || (a.publishStart == null)) 
         && a.active == true)); 

इसमें कुछ समय लंबा है, इसलिए मुझे आश्चर्य है कि अगर यह एक बनाने के लिए संभव है - विधि (विस्तार?) जैसे:

db.myTable.SingleOrDefault(a => (a.ID == _theID).isActive() 

जहां isActive() ऊपर स्निपेट की 3 लाइनों प्रदान करता है।

मैं यह कैसे कर सकता हूं? क्या कोड साफ़ करने का कोई बेहतर तरीका है?

+0

ये सभी अलग-अलग तालिकाओं में हैं, है ना? संदर्भ में खुलासा नहीं किया गया एक भी टेबल? मैं पूछता हूं क्योंकि आप प्रीम्बल में इंगित करते हैं कि गुण अलग-अलग तालिकाओं पर हैं, जबकि आप फ़िल्टर में केवल एक संदर्भ का उपयोग करते हैं। यदि वे सभी एक ही टेबल पर हैं, तो यह आसान है, अगर वे अलग-अलग तालिकाओं पर हैं, तो यह सही जवाब को काफी बदल देता है। – casperOne

+0

उस स्थिति में आपको ** 'सिंगलऑफिफॉल्ट' ** से पहले 'IsActive' ** को कॉल करने की आवश्यकता होगी ताकि आप केवल एक ही लेने से पहले सक्रिय आइटम फ़िल्टर कर सकें, जब तक कि उस आईडी के साथ केवल एक ही आइटम न हो। – Servy

उत्तर

13

एक एक्सटेंशन को परिभाषित करने के लिए आपको एक स्थिर वर्ग की आवश्यकता है। आप इसे जो भी नामस्थान पसंद करते हैं उसे डाल सकते हैं, बस इसे अपने उपयोग में शामिल करना याद रखें।

public static class Extensions 
{ 
    public static IQueryable<T> Active<T>(this IQueryable<T> source) 
     where T : YourEntityType 
    { 
     return source.Where(a => ((a.publishEnd > DateTime.Now) || (a.publishEnd == null)) 
          && ((a.publishStart <= DateTime.Now) || (a.publishStart == null)) 
          && a.active == true); 
    } 
} 

नोटिस YourEntityType वहां। इसका उपयोग यह सुनिश्चित करने के लिए किया जाता है कि विधि publishStart, publishEnd, और active के अस्तित्व से अवगत है। यह या तो वर्ग होना चाहिए जो इन क्षेत्रों या अनुबंध (इंटरफ़ेस) को लागू करता है जो उन्हें परिभाषित करता है।

फिर आप तो इस तरह कहेंगे:

var item = db.myTable.Active().SingleOrDefault(...); 

अधिक विस्तार के तरीकों यहाँ पर: http://msdn.microsoft.com/en-us/library/bb383977.aspx


के रूप में वहाँ हर जगह ऊपर पॉपिंग टिप्पणियों के बहुत सारे हैं, मैं जा रहा हूँ यहां इंटरफ़ेस समाधान का एक संक्षिप्त विवरण जोड़ने के लिए ...

यह प्रश्न में अस्पष्ट है कि तीन फ़िल्टर किए गए एफ के लिए एक सामान्य कार्यान्वयन है या नहीं उन्हें परिभाषित करने के लिए ields या एक इंटरफ़ेस। यदि नहीं, उपर्युक्त काम करने के लिए, आप या तो नहीं होंगे:

  1. इन फ़ील्ड को लागू करने वाला एक बेस क्लास। इस परिदृश्य में आप को YourBaseEntityType के साथ प्रतिस्थापित करेंगे।
  2. फ़ील्ड को परिभाषित करने के लिए एक इंटरफ़ेस। इस परिदृश्य में आपको अपने वर्गों को खेतों को लागू करने की आवश्यकता होगी। यदि कक्षाएं ऑटो जनरेट की जाती हैं (उदा। इकाई फ्रेमवर्क मॉडल/डीबी पहले) तो आप इंटरफ़ेस को कार्यान्वित करते हुए आंशिक कक्षाओं को कार्यान्वित कर सकते हैं। इस मामले में आप YourEntityType को IYourContract के साथ प्रतिस्थापित करेंगे।
+0

क्या 'IQueryable ' 'IENumerable ' के बजाय 'IQueryable ' का उपयोग करने का कोई कारण है? – Default

+0

यह 'सिंगलऑर्डफॉल्ट' के कॉल में काम नहीं करेगा जो ओपी पूछता है। – casperOne

+1

@ डीफॉल्ट। मैं 'IQueryable ' का उपयोग करना पसंद करता हूं क्योंकि मेरे पास अतीत में पॉलीमोर्फिज्म समस्याएं थीं, 'आईनेमेरेबल '। यह देखते हुए कि 'IENumerable ' और 'IQueryable ' दोनों के लिए एक्सटेंशन मौजूद हैं, 'IENumerable ' लौटने पर परिणामस्वरूप गलत एक्सटेंशन को श्रृंखला में आगे कहा जा सकता है जिसके परिणामस्वरूप स्थगित प्रश्नों के बजाय गणना हो सकती है। –

3
public static class Extensions 
{ 
    public static IEnumerable<MyClass> isActive(this IEnumerable<MyClass> list) 
    { 
     return list.Where(a => 
       ((a.publishEnd > DateTime.Now) || (a.publishEnd == null)) 
       && ((a.publishStart <= DateTime.Now) || (a.publishStart == null)) 
       && a.active == true); 
    } 
} 
4

बस इस

public interface IHaveAActivityPeriod 
{ 
    Boolean active { get; } 

    DateTime? publishStart { get; } 

    DateTime? publishEnd { get; } 
} 

की तरह एक अंतरफलक को परिभाषित करने और सभी प्रासंगिक वर्गों में जोड़ें।

public class Foo : IHaveAActivityPeriod { [...] } 

public class Bar : IHaveAActivityPeriod { [...] } 

अब आप IHaveAActivityPeriod को लागू हर मामले पर इस विस्तार विधि

public static class Extensions 
{ 
    public static Boolean IsActive(this IHaveAActivityPeriod item) 
    { 
     var now = DateTime.Now; 

     return item.active && 
       (item.publishStart <= now) 
       (!item.publishEnd.HasValue || (item.publishEnd > now)); 
    } 
} 

उपयोग कर सकते हैं।

var foo = new Foo(); 

var isFooActive = foo.IsActive(); 

var bar = new Bar(); 

var isBarActive = bar.IsActive(); 

मैं पूरी तरह से एक एक्सटेंशन को बनाने की संभावना को याद करता हूं जो एक ही इकाई को एक बार में देखने के बजाय अनुक्रम की फ़िल्टरिंग करता है। इंटरफ़ेस में प्रकार की बाधा के रूप में फेंकने के जवाब से केवल विस्तार विधि को ले जाएं।

public static class Extensions 
{ 
    public IQueryable<T> IsActive<T>(this IQueryable<T> sequence) 
     where T : IHaveAActivityPeriod 
    { 
     return source.Where(item => 
        item.active && 
        (item.publishStart <= now) && 
        (!item.publishEnd.HasValue || (item.publishEnd > now)); 

    } 
} 
+0

यह एसक्यूएल में परिवर्तित नहीं होगा, और इसलिए फ़िल्टरिंग के लिए पूर्ण मूल्यांकन की आवश्यकता होगी। –

+0

यह सच है, लेकिन वास्तव में कोई अच्छा समाधान नहीं है जो एसक्यूएल (कस्टम प्रदाता के बिना) में अनुवाद योग्य है और इसलिए ऑब्जेक्ट्स समाधान में LINQ प्रस्तुत करने का निर्णय लिया गया है। –

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