5

का उपयोग कर एक फिल्टर के रूप में कार्य करने के लिए एक कस्टम विधेय बिल्डिंग मैं उन्हें कि मैं गतिशीलनिर्माण के लिए संघर्ष कर रहा हूँ एक foreach पाश का उपयोग कर एक कस्टम फ़िल्टर को पास करके दस्तावेजों की एक सूची फिल्टर करने के लिए की जरूरत है:एक foreach पाश

var mainPredicate = PredicateBuilder.True<Document>(); 

// mainPredicate is combined to other filters successfully here ... 

var innerPredicate = PredicateBuilder.False<Document>(); 
foreach (var period in periods) 
{ 
    var p = period; 
    Expression<Func<Document, bool>> inPeriod = 
     d => d.Date >= p.DateFrom && d.Date <= p.DateTo; 

    innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d)); 
} 

mainPredicate = mainPredicate.And(innerPredicate); 

यह अंतिम पंक्ति:

:

documents = this.ObjectSet.AsExpandable().Where(mainPredicate).ToList(); 

इस अपवाद फेंकता

पैरामीटर 'डी' निर्दिष्ट LINQ से इकाइयों क्वेरी अभिव्यक्ति में बाध्य नहीं था।

कोई भी जानता है कि मुझे यह अपवाद क्यों मिल रहा है? मैं समझ नहीं पा रहा हूं कि 'डी' पैरामीटर जहां मैं इनपीरियोड विधि में जा रहा हूं, खो जाता है। मुझे नहीं पता कि काम करने के लिए क्या गुम है। मेरा कोड कई अन्य उदाहरणों जैसा ही है जो पूरी तरह से काम करते हैं। अभिव्यक्तियों का आह्वान करने और दृश्यों के पीछे यह कैसे काम करता है, इसके बारे में कोई भी अतिरिक्त थ्योरीय थ्योरिक जानकारी स्वागत है।

+0

क्या होता है यदि आप 'mainPredicate.Expand()। संकलित()। (कुछ दस्तावेज़) आमंत्रित करें? क्या आप सुनिश्चित हैं कि समस्या कहीं और नहीं है (आपका कोड मुझे ठीक लग रहा है)? – svick

+0

आपके सुझाव को देखते हुए, मैंने अंतिम पंक्ति को संशोधित किया है, इसलिए ऐसा लगता है: 'documentEntries = this.ObjectSet.AsExpandable()। जहां (de => mainPredicate.Expand()। संकलित()। Invoke (de))। ToList (); लेकिन यह फेंकता है: LINQ से संस्थाएं 'Boolean Invoke (Remabec.PM.Tarification.DocumentEntry)' विधि को पहचान नहीं पाती हैं, और इस विधि को स्टोर अभिव्यक्ति में अनुवादित नहीं किया जा सकता है। –

+0

हाँ, यह काम नहीं करेगा और मेरा मतलब यह नहीं था। क्या आप अपना कोड स्वयं ही निष्पादित करने का प्रयास कर सकते हैं? – svick

उत्तर

1

अंत में, मैं एक तरह से मुख्य अभिव्यक्ति करने के लिए कई विधेय के संयोजन से बचने के लिए मिल गया है पेड़।

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

इसके लिए काम करने के लिए, भविष्यवाणियों को AND के साथ जोड़ा जाना है। इन विधेय गठबंधन करने के लिए साथ AND अंतिम प्रश्न के Where क्वेरी ऑपरेटरों, इस तरह श्रृंखला है

predicate1 AND predicate2 AND predicate3 ...

एक बेहतर तरीका:

var documents = this.ObjectSet.AsExpandable() 
    .Where(mainPredicate) 
    .Where(otherPredicate) 
    .Where(yetAnotherPredicate) 
    .ToList(); 
तो, जिसके परिणामस्वरूप SQL क्वेरी इस तरह दिखना चाहिए

परिणामस्वरूप SQL क्वेरी AND के साथ इन भविष्यवाणियों में से प्रत्येक को जोड़ती है। यही वही है जो मैं करना चाहता था।

मेरे द्वारा अभिव्यक्ति वृक्ष को हैकिंग करना आसान है।

2

मुझे समझ नहीं आता क्यों आप ऐसा करते हैं: इस तरह,

innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d)); 

तुम सिर्फ पूरी तरह से Invoke से बच सकते हैं जब:

innerPredicate = innerPredicate.Or(inPeriod); 

यह बिल्कुल ठीक काम करना चाहिए।


Btw, मैं वहाँ LINQKit यहाँ के साथ एक बग है एक लग रहा है (जब तक वहाँ कुछ प्रलेखन पता चलता है कि यह है कि यह इस परिदृश्य का समर्थन नहीं करता है)।

मैं इस समान कोड की कोशिश की:

Expression<Func<int, bool>> first = p1 => p1 > 4; 
Expression<Func<int, bool>> second = p2 => p2 < 2; 

// Expand is similar to AsExpandable, except it works on 
// expressions, not queryables. 
var composite = first.Or(d => second.Invoke(d)) 
        .Expand(); 

... LINQKit निम्नलिखित समग्र अभिव्यक्ति उत्पन्न:

p1 => ((p1 > 4) OrElse (d < 2)) // what on earth is d? 

... जो वास्तव में अबाध पैरामीटर (है नोडटाइप = पैरामीटर, नाम = 'डी')।

चकमा दे रहा है first.Or(second).Expand() साथ Invoke उत्पन्न करता है पूरी तरह से समझदार:

p1 => ((p1 > 4) OrElse (p1 < 2)) // much better now... 
+0

'innerPredicate.Or (inPeriod.Invoke) 'संकलित नहीं होगा। मुझे लगता है कि आपका मतलब 'आंतरिक प्रीडिकेट.ओआर (इनपीरियोड)' था। – svick

+0

@svick: ओह, टाइपो! मैंने कहा 'Invoke' से बचें तो इसे कॉपी-पास्ता से खुद को हटा नहीं दिया। धन्यवाद। – Ani

+0

यदि मैं स्पष्ट रूप से अभिव्यक्ति का आह्वान नहीं करता (जैसे आपने सुझाव दिया: 'innerPredicate.Or (inPeriod))' मुझे मिलता है: __ पैरामीटर 'f' निर्दिष्ट LINQ में इकाई क्वेरी अभिव्यक्ति में बाध्य नहीं था .__ –

0

मैं इन विस्तार तरीकों का उपयोग:

public static class Extensions 
{ 
    public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate) 
    { 
     InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>>(Expression.OrElse(source.Body, invokedExpression), source.Parameters); 
    } 

    public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate) 
    { 
     InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(source.Body, invokedExpression), source.Parameters); 
    } 

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