2012-01-23 9 views
13

मैं एक लैम्ब्डा अभिव्यक्ति बनाने की कोशिश कर रहा हूं जिसे फ़िल्टरिंग के लिए दूसरों के साथ एक बड़े अभिव्यक्ति वृक्ष में जोड़ा जाएगा। यह तब तक ठीक काम करता है जब तक मुझे उप संग्रह संपत्ति द्वारा फ़िल्टर करने की आवश्यकता न हो।संग्रह संपत्ति पर फ़िल्टर करने के लिए एक गतिशील अभिव्यक्ति वृक्ष का निर्माण

आप एक लैम्ब्डा अभिव्यक्ति कैसे बनाते हैं जो किसी संग्रह की संपत्ति पर किसी भी() का उपयोग करके फ़िल्टर करेगा जो रूट ऑब्जेक्ट की संपत्ति है?

उदाहरण:

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

यह कैसे मैं अभिव्यक्ति स्थिर का निर्माण होगा, लेकिन मैं यह गतिशील रूप का निर्माण करने की जरूरत है। गलतफहमी के लिए खेद है।

संपादित करें:

IQueryable<Office> officeQuery = CurrentDataSource.Offices.AsQueryable<Office>(); 
ParameterExpression pe = Expression.Parameter(typeof(Office), "Office"); 
ParameterExpression tpe = Expression.Parameter(typeof(Trades), "Trades"); 

Expression SimpleWhere = null; 
Expression ComplexWhere = null; 
foreach (ServerSideFilterObject fo in ssfo) 
{ 
    SimpleWhere = null; 
    foreach (String value in fo.FilterValues) 
    { 
     if (!CollectionProperties.Contains(fo.PropertyName)) 
     { 
      //Handle singleton lambda logic here. 
      Expression left = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); 
      Expression right = Expression.Constant(value); 
      if (SimpleWhere == null) 
      { 
       SimpleWhere = Expression.Equal(left, right); 
      } 
      else 
      { 
       Expression e1 = Expression.Equal(left, right); 
       SimpleWhere = Expression.Or(SimpleWhere, e1); 
      } 
     } 
     else 
     { 
      //handle inner Collection lambda logic here. 
      Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); 
      Expression right = Expression.Constant(value); 
      Expression InnerLambda = Expression.Equal(left, right); 

      //Problem area. 
      Expression OfficeAndProperty = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); 
      Expression OuterLambda = Expression.Call(OfficeAndProperty, typeof(Trades).GetMethod("Any", new Type[] { typeof(Expression) }),InnerLambda); 

      if (SimpleWhere == null) 
       SimpleWhere = OuterLambda; 
      else 
       SimpleWhere = Expression.Or(SimpleWhere, OuterLambda); 
     } 
    } 
    if (ComplexWhere == null) 
     ComplexWhere = SimpleWhere; 
    else 
     ComplexWhere = Expression.And(ComplexWhere, SimpleWhere); 
} 
MethodCallExpression whereCallExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { officeQuery.ElementType }, officeQuery.Expression, Expression.Lambda<Func<Office, bool>>(ComplexWhere, new ParameterExpression[] { pe })); 
results = officeQuery.Provider.CreateQuery<Office>(whereCallExpression); 
+0

क्या आप एक अभिव्यक्ति वृक्ष बनाने के लिए पूछ रहे हैं? – SLaks

+0

मुझे यकीन नहीं है कि पदानुक्रम आपके उदाहरण में कैसे काम करता है। क्या आप उस पर थोड़ा और विस्तार कर सकते हैं? क्या कार्यालय रूट है और फिर प्रत्येक कार्यालय में ट्रेडों का संग्रह होता है? और आप व्यापार के नाम पर फ़िल्टर करना चाहते हैं ?? फ़िल्टर वह जगह है जहां मैं थोड़ा खो गया हूं। माफ़ कीजिये। –

+0

नहीं, मैं सिर्फ एक आंतरिक विधि कॉल और पैरामीटर के लिए अभिव्यक्ति के साथ अभिव्यक्ति बनाने के लिए प्रयुक्त वाक्यविन्यास से अनिश्चित हूं। इस मामले में, मुझे यह बताते हुए एक त्रुटि मिल रही है कि कोई भी() नहीं मिला क्योंकि मेरे पैरामीटर परिभाषा से मेल नहीं खाते हैं। इस मामले में मुझे यकीन नहीं है कि ऐसा इसलिए है क्योंकि मैं वाक्यविन्यास पर हूं या यदि कोई भी() इसका उपयोग करने के तरीके में समर्थित नहीं है। – George

उत्तर

9

मिले समाधान। मैं पहले सही जगह पर किसी भी विधि की तलाश नहीं कर रहा था।

Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); 
Expression right = Expression.Constant(value); 
Expression InnerLambda = Expression.Equal(left, right); 
Expression<Func<Trades, bool>> innerFunction = Expression.Lambda<Func<Trades, bool>>(InnerLambda, tpe); 

method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(Trades)); 
OuterLambda = Expression.Call(method, Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)),innerFunction); 
0

आप सूचीबद्ध क्या के रूप में अपने उदाहरण अपनी टिप्पणी के आधार पर काम करेगा: यहाँ कैसे मैं कम जटिल भाव संभाल का एक टुकड़ा है।

Templates.Where(t => t.TemplateFields.Any(f => f.Required == 'Y')) 

हम टेम्पलेट्स है कि क्षेत्रों के विशिष्ट संग्रह है, और उन क्षेत्रों के लिए आवश्यक हो सकता है: यहाँ मैं क्या के साथ काम का एक उदाहरण है। तो मैं उन टेम्पलेट्स को प्राप्त कर सकता हूं जहां उपरोक्त उस कथन द्वारा किसी भी फ़ील्ड की आवश्यकता होती है।

उम्मीद है कि इससे मदद मिलती है ... या कम से कम पुष्टि करता है कि आप क्या करने की कोशिश कर रहे हैं। अगर आपको इसके बारे में और सवाल हैं तो मुझे बताएं और मैं विस्तृत करूंगा।

शुभकामनाएं!

+0

यह वही है जो मैं काम कर रहा हूं लेकिन मुझे प्रतिबिंब के साथ गतिशील रूप से लैम्डा अभिव्यक्ति बनाना है ताकि मैं सुनिश्चित कर सकूं कि फ़िल्टर सेट में अन्य फ़िल्टर शामिल करता है। – George

0

प्रदान की कोड

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

काम करना चाहिए, जब तक o.base_Trades लागू करता IEnumerable<Trade> के रूप में। यदि o.base_Trades केवल IEnumerable लागू करता है, तो आपको Cast<Trade>() का उपयोग करने की आवश्यकता है यदि आप सुनिश्चित कर सकते हैं कि o.base_Trades में सभी तत्व आपके Trade प्रकार या OfType<Trade>() हैं यदि अन्य (असंगत) प्रकारों के तत्व हो सकते हैं।

यही तो इस प्रकार दिखाई देगा:

CurrentDataSource.Offices 
    .Where(o => o.base_Trades.Cast<Trade>.Any(t => t.Name == "test")) 
1

कृपया ऐसा न करें, आप वास्तव में गतिशील लिनक नामक लाइब्रेरी का उपयोग करना चाहते हैं। http://nuget.org/packages/DynamicLINQ

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

+0

यह एक उत्कृष्ट पुस्तकालय है, मैं इसका भी उपयोग करता हूं, लेकिन यह उदाहरण के लिए समर्थन नहीं करता है जैसे कि संग्रह की संपत्ति की संपत्ति पर छंटनी 'myIQueryable.OrderBy (x => x.MyCollection.Select (y => y.Myproperty) ', कम से कम मैं इसे काम नहीं कर सकता –

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