2013-08-20 5 views
11

मैं इकाई की रूपरेखा सूची के लिए एक फिल्टर विधि बना सकते हैं और समझने की कोशिश कर रहा हूँ बेहतर Expression<Func<...इकाई की रूपरेखा फ़िल्टर "अभिव्यक्ति <समारोह <T, bool>>"

मैं इस तरह के टेस्ट समारोह है।

public IQueryable<T> Filter<T>(IEnumerable<T> src, Expression<Func<T, bool>> pred) 
{ 
    return src.AsQueryable().Where(pred); 
} 

और अगर मैं ऐसा करते हैं:

context.Table.Filter(e => e.ID < 500); 

या इस:

context.Table.Filter(e => e.SubTable.Where(et => et.ID < 500).Count() > 0 && e.ID < 500); 

यह सब अच्छी तरह से काम करता है।

लेकिन अगर मैं ऐसा करते हैं:

context.Table.Where(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500); 

मैं एक त्रुटि प्राप्त:

context.Table.Filter(e => e.SubTable.Filter(et => et.ID < 500).Count() > 0 && e.ID < 500); 

या इस। LINQ to Entities does not recognize the method ...Filter...

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

पहले दो मामलों में फ़िल्टर डेटाबेस में सही ढंग से चलता है।

उत्तर

20

जॉन और टिम ने पहले ही समझाया कि यह क्यों काम नहीं करता है।

मानते हैं कि Filter के अंदर फ़िल्टर कोड छोटा नहीं है, तो आप Filter बदल सकते हैं ताकि यह एक अभिव्यक्ति ईएफ अनुवाद कर सके।

Expression<Func<YourEntity, bool>> FilterByNameLength(int length) 
{ 
    return x => x.Name.Length > length; 
} 

प्रयोग इस तरह होगा::

context.Table.Where(FilterByNameLength(500)); 

context.Table.Where(x => x.Name.Length > 500); 

अब आप एक विधि रिटर्न इस अभिव्यक्ति बना सकते हैं:

मान लेते हैं तो आप इस कोड करते हैं अभिव्यक्ति जो आप FilterByNameLength के अंदर बनाते हैं, मनमाने ढंग से जटिल हो सकती है जब तक आप पास कर सकें यह सीधे Where पर।

+0

बहुत सारे पढ़ने और परीक्षण और त्रुटि से मुझे संदेह था कि यह एकमात्र तरीका था। क्या यह संदर्भ जैसे मामलों का काम करेगा। ठीक है। कहाँ (ई => e.subTable.Any (MyFilter())); –

+0

@ पेड्रो.किड: नहीं, यह नहीं होगा। इस विधि का परिणाम बाहरीतम 'कहां' को पारित करने की आवश्यकता है, क्योंकि आप जो बाहरी अभिव्यक्ति को पार करते हैं, वह वास्तव में निष्पादित नहीं किया जाता है लेकिन इसका अर्थ है। –

+0

मैंने एक परीक्षण किया और यह var filter = MyFilter() काम करता है; संदर्भ.Table.Where (ई => e.subTable.AsQueryable()। कोई भी (फ़िल्टर)); –

4

यह एक मामले में क्यों काम करता है, न कि योजक में?

क्योंकि ईएफ वास्तव में आपके Filter विधि के बारे में "पता" नहीं है। इसका कोई अर्थ नहीं है कि इसका क्या अर्थ है, इसलिए यह नहीं जानता कि इसे एसक्यूएल में कैसे अनुवादित किया जाए। तुलना करें कि Where आदि के साथ, यह समझता है।

संस्करण जहां आप इसे प्रारंभिक मेज पर फोन सीधे काम करता है क्योंकि इस तरह आप एक अभिव्यक्ति Filter के लिए एक कॉल युक्त पेड़ के साथ अंत नहीं है - यह सिर्फ Filter कॉल सीधे है, जो बारी में निर्माण करता है एक प्रश्न ऊपर ... लेकिन एक जो ईएफ समझता है।

मैं अगर आप एक एफई क्वेरी के भीतर काम करने के लिए अपने Filter विधि सक्रिय होने का तरीका बाहर काम कर सकता था बहुत आश्चर्य होगा ... लेकिन आप पहले से ही कहा है कि वैसे भी Where काम करता है का उपयोग कर, तो क्यों Filter बिल्कुल का उपयोग करें? मैं Where संस्करण का उपयोग करते हैं - या बेहतर अभी तक, Any अधिभार जो एक विधेय लेता है का उपयोग करें:

context.Table.Filter(e => e.SubTable.Any(et => et.ID < 500) && e.ID < 500); 
+0

क्या कोई तरीका है जिसे इसे एक अभिव्यक्ति वृक्ष चुड़ैल खुराक के साथ समाप्त करने के लिए बदला जा सकता है जिसमें विधि का नाम शामिल नहीं है? –

+0

@ पेड्रो.किड: आसानी से नहीं। आप एक विधि लिख सकते हैं जो अभिव्यक्ति वृक्ष को फिर से लिखता है और उस पर आधारित एक नई क्वेरी तैयार करता है, लेकिन यह स्पष्ट नहीं है कि आप ऐसा क्यों करना चाहते हैं, और यह मुश्किल होगा। –

+0

जहां वास्तविक वातावरण में परीक्षण के लिए बस इसके उपयोग के लिए यह अधिक जटिल होगा। –

6

यह Expression<Func<>> और Func<> के बीच अंतर को समझने के लिए उपयोगी है।

एक Expressione => e.ID < 500 भंडार है कि अभिव्यक्ति के बारे में जानकारी: वहाँ एक Te है कि यह है कि आप, संपत्ति ID तक पहुँच बना रहे int मूल्य 500 साथ < ऑपरेटर बुला।जब ईएफ उस पर दिखता है, तो यह इसे [SomeTable].[ID] < 500 जैसे कुछ में बदल सकता है।

एक Funce => e.ID < 500 के लिए एक विधि के बराबर है:

static bool MyMethod(T e) { return e.ID < 500; } 

यह आईएल कोड है कि यह करता है के रूप में संकलित किया गया है; इसे किसी SQL क्वेरी या किसी अन्य चीज़ में 'पुनर्निर्मित' करने के लिए डिज़ाइन नहीं किया गया है, केवल चलाएं।

जब ईएफ आपके Expression लेता है, तो इसे इसके प्रत्येक भाग को समझना चाहिए, क्योंकि यह SQL क्वेरी बनाने के लिए इसका उपयोग करता है। यह जानने के लिए प्रोग्राम किया गया है कि मौजूदा Where विधि का अर्थ क्या है। यह नहीं पता कि आपके Filter विधि का अर्थ क्या है, भले ही यह एक मामूली विधि है, इसलिए यह बस छोड़ देता है।

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