2012-09-13 8 views
6

के आधार पर IEnumerable को फ़िल्टर करने के लिए कैसे करें मैं अब इकाई फ्रेमवर्क का उपयोग कर रहा हूं- लेकिन यह सभी ओआरएम और यहां तक ​​कि IENumerable के बीच "साझा" की समस्या है।किसी इनपुट इनपुट पैरामीटर

मान लीजिए कि मैं MVC में एक विधि इस तरह दिखता है दो:

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(???).ToList(); 
    return View(data); 
} 

मैं जैसे इनपुट पैरामीटर के आधार पर संदर्भ क्वेरी करना चाहते हैं:

var data = context.Foo.Where(x => x.Date == model.Date && 
          x.Name == model.Name && 
          x.ItemCode = model.ItemCode).ToList(); 

लेकिन यह उससे कहीं अधिक जटिल है, क्योंकि अगर उपरोक्त पैरामीटर में से एक (Date \ Name \ ItemCode) शून्य है, तो मैं इसे क्वेरी के अंदर शामिल नहीं करना चाहता हूं।
मैं मुश्किल कोड यह कर सकते हैं इस के समान दिखाई देता है:

var query = context.Foo; 

if (model.Date != null) 
    query =query.Where(x => x.Date == model.Date); 

if (model.ItemCode != null) 
    query =query.Where(x => x.ItemCode == model.ItemCode); 
... 

इस से एक सरल तरीका होना चाहिए।
मुझे विधि विधि में उपयोग किए जाने के लिए Expression<T, bool> प्रकार की अभिव्यक्ति उत्पन्न करने का एक तरीका चाहिए।

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(THE_EXPRESSION).ToList(); 
    return View(data); 
} 

क्या अभिव्यक्ति बनाने का एक अंतर्निहित तरीका है? क्या नाजेट में कोई पैकेज है जो करता है?


अद्यतन: मॉडल इकाई में 30 से अधिक प्रॉपर्टीज़ हो सकती है; 30 बार लिखना जहां प्रत्येक क्वेरी के लिए गर्दन में दर्द हो सकता है:

.Where(model.Date != null, x => x.Date == model.Date) 
.Where(model.Name != null, x => x.Name == model.Name) 
.Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
... 
... 
... 
.ToList(); 

उत्तर

5

इसे आजमाएं। यह क्वेरी को गतिशील रूप से बनाने के लिए प्रतिबिंब और अभिव्यक्तियों का उपयोग कर रहा है। मैंने केवल वस्तुओं के साथ इसका परीक्षण किया।

static IQueryable<T> Filter<T>(IQueryable<T> col, T filter) 
{ 
    foreach (var pi in typeof(T).GetProperties()) 
    { 
     if (pi.GetValue(filter) != null) 
     { 
      var param = Expression.Parameter(typeof(T), "t"); 
      var body = Expression.Equal(
       Expression.PropertyOrField(param, pi.Name), 
       Expression.PropertyOrField(Expression.Constant(filter), pi.Name)); 
      var lambda = Expression.Lambda<Func<T, bool>>(body, param); 
      col = col.Where(lambda); 
     } 
    } 

    return col; 
} 
+0

एक उदाहरण जो दिखाता है कि इस विधि का उपयोग कैसे किया जाता है, यह बहुत उपयोगी होगा। – devinbost

5

आपकी हार्ड कोडित विधि आम तौर पर सबसे अच्छी विधि है।

हालांकि आप कोड को साफ रखने में मदद के लिए एक उचित विस्तार विधि लिखकर अपने जीवन को थोड़ा आसान बनाने का प्रयास कर सकते हैं।

उदाहरण के लिए इस प्रयास करें:

public static class QueryableEx 
{ 
    public static IQueryable<T> Where<T>(
     this IQueryable<T> @this, 
     bool condition, 
     Expression<Func<T, bool>> @where) 
    { 
     return condition ? @this.Where(@where) : @this; 
    } 
} 

अब आप इस कोड को लिख सकते हैं:

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    using (var context = new Context()) 
    { 
     var data = context.Foo 
      .Where(model.Date != null, x => x.Date == model.Date) 
      .Where(model.Name != null, x => x.Name == model.Name) 
      .Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
      .ToList(); 
     return View(data); 
    } 
} 

(कृपया मत भूलना अपने संदर्भ के निपटान या using का उपयोग आप के लिए यह करने के लिए करने के लिए।)

+0

+1 यह मेरी वोट स्क्रीन प्राप्त करता है जो उपयोगकर्ता को एन द्वारा बड़ी तालिका खोजने की अनुमति देता है! विभिन्न क्रमपरिवर्तन इसे डीबी स्तर पर सूचकांक के लिए एक दुःस्वप्न बनाते हैं। प्रत्येक फिल्टर को देव को दृश्यमान बनाकर, कम से कम परिणामस्वरूप क्वेरी में कुछ दृश्यता होती है, और कुछ पुनर्विचार का कारण बन सकता है कि किस फ़ील्ड (या उसके संयोजन) उपयोगकर्ता के सामने आ सकते हैं। – StuartLC

+0

आपके इनपुट और विचार के लिए धन्यवाद।लेकिन अगर मेरी मॉडल-इकाई में ** से अधिक ** उचित हैं, तो यह 30 बार लिखता है जहां (...) दर्द हो सकता है। – gdoron

+0

@gdoron - हाँ, लेकिन आपको उन्हें कहीं लिखना होगा। यदि आप प्रतिबिंब और बिल्डिंग अभिव्यक्तियों के साथ ऐसा करने का प्रयास करते हैं तो मुझे डर है कि अब आपको दो समस्याएं होंगी। – Enigmativity

1

मुझे लगता है कि आपको अपने तर्क को अपनी फू इकाई में समाहित करना चाहिए, उदाहरण के लिए

public Foo 
    { 
    public bool isMatch(Model model) 
    { 
     // check your rules and return result 
    } 
    } 

और इसे linq में उपयोग करें। या Specification pattern

+1

वह केवल LINQ से ऑब्जेक्ट्स के साथ काम करता है, न कि इकाई फ्रेमवर्क के साथ। –

+0

आप सार्वजनिक अभिव्यक्ति > IsSisfisfiedBy() – syned

+0

जो आपकी इकाई को पूरी तरह से विनियमित कर सकते हैं। –