2012-04-27 9 views
10

मैं एक फिल्टर है कि मैं कई तरीकों भर में उपयोग किया है:बच्चों के आधार पर फ़िल्टर करने के लिए System.Linq.Expressions.Expression का उपयोग कैसे करें?

Expression<Func<Child, bool>> filter = child => child.Status == 1; 

(वास्तव में उस से अधिक जटिल है) और मैं जहां हालत है निम्नलिखित

return db.Parents.Where(parent => parent.Status == 1 && 
            parent.Child.Status == 1); 

क्या करना है उपरोक्त फ़िल्टर में जैसा ही है।

मैं इस विधि में फ़िल्टर का पुन: उपयोग करना चाहता हूं। लेकिन मुझे नहीं पता कि कैसे। मैं

return db.Parents.Where(parent => parent.Status == 1 && 
            filter(parent.Child)); 

कोशिश की, लेकिन एक अभिव्यक्ति एक विधि के रूप में उपयोग नहीं किया जा सकता है

उत्तर

3

यदि आप अभिव्यक्तियों को जोड़ना चाहते हैं और अभी भी linq-to-sql का उपयोग करने में सक्षम हैं, तो आप LinqKit पर एक नज़र रखना चाहेंगे। यह आपकी अभिव्यक्ति के अंदर चलता है और एसक्यूएल रूपांतरण से पहले सभी फ़ंक्शन कॉल को उनकी सामग्री द्वारा प्रतिस्थापित करता है।

इस तरह से आप सीधे

return db.Parents 
     .AsExpandable() 
     .Where(parent => parent.Status == 1 && filter(parent.Child)); 
1

आप इस कोशिश कर सकते हैं:

var compiledFilter = filter.Compile(); 
foreach (var parent in db.Parents.Where(parent => parent.Status == 1)) 
    if (compiledFilter(parent.Child)) 
     yield return parent; 

यह माता पिता के सभी खींच करने की आवश्यकता है, लेकिन विपरीत @ HugoRune के समाधान, इसे माता-पिता के 1: 1 संबंध की आवश्यकता नहीं है: चाइल्ड।

मुझे नहीं लगता कि इस वजह से अलग अलग प्रकार के शामिल अपनी स्थिति के लिए उपयोगी हो सकता है, लेकिन सिर्फ मामले में, यहाँ आप Expression कैसे जोड़ सकते हैं का एक उदाहरण है: How do I combine LINQ expressions into one?

संपादित करें: मैं पहले था Compile() का उपयोग करने का सुझाव दिया गया है, लेकिन यह LINQ-to-SQL पर काम नहीं करता है।

+0

मुझे नहीं लगता कि आप linq-to-sql कथन के अंदर अभिव्यक्ति संकलित कर सकते हैं। Lambdas केवल सामान्य linq – HugoRune

+0

एचएम में काम करते हैं, लगता है कि आप सही हैं, दुर्भाग्य से। मैं एक और विकल्प सुझाऊंगा। –

+0

मुझे लगता है कि मैं संयुक्त अभिव्यक्तियों या डाइनैमिक लिंक का उपयोग करूंगा, क्योंकि @HugoRune ने –

1

ठीक है, अगर वहाँ एक 1: माता-पिता और बच्चे के बीच 1 संबंध (संभावना नहीं है, लेकिन उदाहरण के होने का संकेत देने लगता है) तो आप इसे इस तरह कर सकता है:

return db.Parents 
    .Where(parent => parent.Status == 1) 
    .Select(parent => parent.Child) 
    .Where(filter) 
    .Select(child=> child.Parent); 

अन्यथा यह मुश्किल हो जाएगा ।

आप इसे dynamic linq के साथ कर सकते हैं लेकिन यह शायद अधिक है।

आप generate your expression tree manually कर सकते हैं, लेकिन यह भी काफी जटिल है। मैंने खुद कोशिश नहीं की है।

एक अंतिम उपाय आप निश्चित रूप से हमेशा yourQuery.AsEnumerable() कह सकते हैं, यह LINQ करने वाली एसक्यूएल इस मुद्दे पर एसक्यूएल अप में आपकी क्वेरी का अनुवाद और क्लाइंट-साइड पर काम के आराम के प्रदर्शन करने के लिए कारण होगा; तो आप अपनी अभिव्यक्ति को .compile() कर सकते हैं। लेकिन अगर आप LINQ करने वाली एसक्यूएल के प्रदर्शन लाभ खो (और संकलन() अपने आप में काफी धीमी है, जब भी यह मार डाला है, यह JIT-संकलक कॉल):

return db.Parents 
    .Where(parent => parent.Status == 1) 
    .AsEnumerable() 
    .Where(parent => filter.Compile().Invoke(parent.Child)) 

निजी तौर पर मैं सिर्फ अभिव्यक्ति निर्धारित करेंगे दो बार, एक बार बच्चे के लिए और एक बार parent.child के लिए:

Expression<Func<Child, bool>> filterChild = child => child.Status == 1; 
    Expression<Func<Parent, bool>> filterParent = parent => parent.Child.Status == 1; 

नहीं सबसे खूबसूरत, लेकिन शायद आसान अन्य समाधान

0

से बनाए रखने के लिए बस इस के साथ आते हैं, तो देखें कि यह काम करेगा हो सकता है आपके लिए

public interface IStatus { public int Status { get; set; } } 
public class Child : IStatus { } 
public class Parent : IStatus 
{public Child Child { get; set; } } 

Func<IStatus, bool> filter = (x) => x.Status == 1; 
var list = Parents.Where(parent => filter(parent) && filter(parent.Child)); 

उम्मीद है कि इससे मदद मिलती है!

+1

फ़नक linq-to-sql के साथ काम नहीं किया है, इसे अभिव्यक्ति होना चाहिए। और चूंकि माता-पिता और बच्चे डीबी योजना के आधार पर संभावित रूप से ऑटो-जेनरेटेड कक्षाएं हैं, उन्हें एक सामान्य आधार वर्ग देना इतना आसान नहीं है – HugoRune

+0

मानदंड मानते हैं कि वास्तव में साझा किया जाता है, यह वास्तव में एक अच्छा दृष्टिकोण है: ऑटो-जेनरेटेड क्लास घोषित किए जाते हैं 'आंशिक' के रूप में, ताकि आप किसी अन्य फ़ाइल में इंटरफ़ेस घोषणाओं/कार्यान्वयन जैसे चीजें जोड़ सकें। चूंकि आपको Func के बजाय अभिव्यक्ति का उपयोग करने की आवश्यकता होगी, इसलिए दिया गया कोड काम नहीं करेगा, लेकिन आप http://stackoverflow.com/questions/1922497/how-do-i- पर दिखाए गए तरीकों का उपयोग करके उन्हें जोड़ सकते हैं। गठबंधन-LINQ-भाव-में-एक। –

0

उपयोग करने के लिए आप बस के बजाय एक समारोह के रूप अभिव्यक्ति का उपयोग कर सकते हैं सक्षम हो जाएगा?

बजाय:

Expression<Func<Child, bool>> filter = child => child.Status == 1; 

उपयोग कि एक सामान्य समारोह के रूप में एक ही अभिव्यक्ति इस तरह से:

Func<Child, bool> filter = child => child.Status == 1; 

तो फिर तुम सिर्फ एक ही तरीका है कि आप करने के लिए कोशिश कर रहे थे में समारोह का उपयोग करने के लिए सक्षम हो जाएगा एक अभिव्यक्ति का उपयोग करें:

return db.Parents.Where(parent => parent.Status == 1 && 
            filter(parent.Child)); 
+1

आपका समाधान SQL में अनुवाद नहीं करता है। –

+0

linq से sql में, अभिव्यक्ति फ़ंक्शन की बजाय काम करता है। – Lali

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

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