2012-08-27 15 views
7

में चेनिंग या शर्तें मैं इस समस्या का समाधान करने के लिए सक्रिय रूप से खोज कर रहा हूं, लेकिन मुझे लगता है कि अगर मैं स्टैक पर किसी ने इसे पहले ही समझ लिया है तो मैं कुछ शोध और विकास का समय कम कर सकता हूं। (मुझे ऑनलाइन कुछ भी नहीं मिला है इसलिएईएफ 5.0

हमारे पास एक ऐसे अनुप्रयोग ढांचे में एक मामला है जहां हम निर्माण कर रहे हैं जहां हमें भविष्यवाणियों (List<Expression<Func<T,bool>>>) के सेट में लेने की क्षमता की आवश्यकता है और इसे एक खोज ढांचे में पार्स करें।

अभी हम इस तरह से किया जा रहा है कि में फिल्टर करने के लिए क्षमता है:

//Assume predicates is passed as a method argument. 
//  of List<Expression<Func<T,bool>>> 
//Assume user is passed in as a method argument. 
//Assume FilterToUserAccess is a custom extension method that restricts the dataset 
// to access restrictions. 
var query = _dbContext.Set<EntityType>() 
    .FilterToUserAccess(user); 
foreach(var p in predicates){ 
    query = query.Where(p); 
} 

return p.ToList(); 

कारण है कि हम इस फ़िल्टर वस्तुओं के पैमाने-क्षमता के लिए है की ज़रूरत है। हालांकि त्वरित खोज के लिए ईएफ की अंतर्निहित क्षमताओं को देखते हुए यह संभव नहीं है। मुझे क्या करने में सक्षम होना चाहिए:

ऑब्जेक्ट ए (आइए रेस कार दिखाएं) और हम त्वरित खोज बॉक्स में मेक, मॉडल, टीम और ड्राइवर खोजना चाहते हैं। इसलिए यदि मैं "एर्नहार्ट" दर्ज करता हूं, तो यह सभी रेस कार इकाई गुणों को बनाने, मॉडल, टीम और ड्राइवर की खोज करेगा। मैं सभी डीईआई कारों के साथ-साथ डेल जूनियर के साथ समाप्त हो जाऊंगा। मैं एक ही दृष्टिकोण का उपयोग करना चाहता हूं ताकि हम एक खोज योग्य इकाई को कॉन्फ़िगर कर सकें और एप्लिकेशन प्रारंभ पर खोज कॉन्फ़िगरेशन को प्रतिबिंबित कर सकें।

//Assume predicates is passed as a method argument. 
//  of List<Expression<Func<T,bool>>> 
//Assume user is passed in as a method argument. 
//Assume FilterToUserAccess is a custom extension method that restricts the dataset 
// to access restrictions. 
var query = _dbContext.Set<EntityType>() 
    .FilterToUserAccess(user); 
foreach(var p in predicates){ 
    query = query.Or(p); 
} 

return p.ToList(); 

मुझे पता है मैं क्या कर सकते हैं:

_dbContext.Set<EntityType>().Where(predicate1 || predicate2 || predicate3) 

हालांकि इस दृष्टिकोण हम करने के लिए ले जाना चाहते हैं के लिए काम नहीं करेगा मैं आदर्श बनाने के लिए क्वेरी होने के किसी तरह से कुछ ऐसा दिखाई चाहते हैं इस समस्या का समाधान निकले। आदर्श रूप से हमारी क्लाइंट साइट्स में से एक के लिए एक व्यवस्थापक एक अतिरिक्त खोज शब्द में जा सकता है और उस इकाई प्रकार के लिए सभी त्वरित खोजों में शामिल होने के लिए एक क्लिक के साथ कॉन्फ़िगर कर सकता है जैसे कि हम वर्तमान में फ़िल्टर के साथ खींच सकते हैं जो मानक का उपयोग करते हैं .Where(...) "और" चेनिंग तर्क।

+0

आपको गतिशील रूप से एक अभिव्यक्ति वृक्ष बनाने की आवश्यकता होगी। –

+0

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

+2

आप लिंककिट/अभिव्यक्ति बिल्डर को देख सकते हैं। ईबी ईएफ के लिए काम करता है और श्रृंखला 'या' शर्तों के लिए यह बहुत आसान बनाता है। –

उत्तर

6

पहला समाधान एक बस्ट था, हालांकि कुछ और खुदाई के साथ एक अविश्वसनीय सरल समाधान, सत्यापित और काम करता है।

चरण 1: लिंककिट के लिए NuGet पैकेज स्थापित करें।

चरण 2: नीचे

using (ISampleRepository repo = new SampleRepository()) 
{ 
    var predicates = new List<Expression<Func<Customer,bool>>>(){ 
     (x => x.FirstName.Contains(searchValue)), 
     (x => x.LastName.Contains(searchValue)) 
    }; 

    var lambda = PredicateBuilder.False<Customer>(); 
    lambda = predicates.Aggregate(lambda, (current, p) => current.Or(p).Expand()); 

    var query = repo.QueryCustomers().AsExpandable().Include(x => x.Phones).Where(lambda); 
    return query.Take(500) 
     .ToList() 
     .Select(x => x.ToDTO()) 
     .ToList(); 
} 

कोड का लाभ उठाएं यह सिर्फ कील नमूना लेकिन एक विधि में लेने के साथ ही बात कर रहे है ->

List<T> QuickSearch<T>(string input) ... 

उपयोग करने में सक्षम हो जाएगा एक ही दृष्टिकोण। आपके पास अभी भी अभिव्यक्ति फॉर्म में भविष्यवाणी का संग्रह है, फिर आप क्वेरी को खींचने के लिए अनुमानित बिल्डर चाल का उपयोग करते हैं। फिर AsExpandable() का उपयोग करके आप अनुमानित निर्माता का उपयोग करके बनाई गई संयुक्त भविष्यवाणी निष्पादित करने की अनुमति देता है।

उम्मीद है कि यह सिर्फ मेरे लिए अधिक उपयोगी है, लेकिन यह वह समाधान है जिसके साथ मैं जा रहा हूं क्योंकि यह काफी कम कोड है। आपको अपनी भविष्यवाणियों को कहीं और बनाने की अनुमति देता है ... और फिर भी उन्हें तथ्य के बाद "OR" कथन में संयोजित करें।

+0

क्या आपने अभी तक एक मेमोरी क्वेरीबल के खिलाफ यह कोशिश की है? मुझे चिंतित होगा कि पैरामीटर अभिव्यक्ति प्रत्येक अभिव्यक्ति के बीच गुंजाइश में नहीं रहेगी। – mclark1129

+0

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

+0

यह शायद एक टाइपो है, लेकिन आपकी निष्पादन योग्य अभिव्यक्ति में 'Func <ग्राहक, bool>' है जबकि शेष उदाहरण सामान्य 'टी' है। पोस्ट करने से पहले – mclark1129

2

जैसा कि Ladislav कहते हैं, आपको गतिशील रूप से अपने LINQ अभिव्यक्तियों को उत्पन्न करने की आवश्यकता होगी।यहाँ जो गतिशील पूर्णांकों का एक संग्रह के लिए एक विधेय बनाता है एक कार्यक्रम का एक सरल उदाहरण है: (एक्स> = 50) और (x < = 20)

class Program { 
    static void Main(string[] args) { 

     // Retreive your data source 
     List<int> numbers = new List<int>() { 0, 10, 20, 30, 40, 50, 60 }; 

     // Create a collection of predicates that you would like to chain together. 
     ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "x"); 
     List<Expression> predicates = new List<Expression>(); 

     // x >= 50 
     predicates.Add(Expression.GreaterThanOrEqual(parameterExpression, Expression.Constant(50))); 

     // x <= 20 
     predicates.Add(Expression.LessThanOrEqual(parameterExpression, Expression.Constant(20))); 

     // Build a single predicate by chaining individual predicates together in an OR fashion 
     Expression whereFilter = Expression.Constant(false); // Use false a base expression in OR statements 

     foreach (var predicate in predicates) { 
      whereFilter = Expression.OrElse(whereFilter, predicate); 
     } 

     // Once the expressions have been chained, create a lambda to represent the whole predicate 
     // x => (x >= 50) || (x <= 20) 
     Expression<Func<int, bool>> whereLambda = 
      (Expression<Func<int, bool>>)Expression.Lambda(whereFilter, 
              new List<ParameterExpression>() { parameterExpression }); 

     // To use an expression directly, the datasource must be an IQueryable 
     // Since I am using List<T> I must call AsQueryable. This is not necessary 
     // if your collection is already IQueryable, like in Entity Framework. 
     var results = numbers.AsQueryable().Where(whereLambda); 

    } 
} 

मूलतः सभी मैं यहाँ कर कई बूलियन statments बनाने और उन्हें एक संग्रह में रखें। फिर उस संग्रह के माध्यम से लूप करके, मैं प्रत्येक कथन लेता हूं और यह आखिरी में ले जाता है। नतीजा बूलियन स्टेटमेंट्स की एक श्रृंखला है जो सभी को एक साथ लिंक किया गया है। मैं फिर उस कथन को लैम्ब्डा अभिव्यक्ति में लपेटता हूं ताकि इसे IQueryable.Where से उपभोग किया जा सके और इसे मेरे क्वेरी करने योग्य संग्रह में पास किया जा सके। परिणाम मेरे पूर्ण सेट से पूर्णांक के फ़िल्टर किए गए सेट हैं।

LINQ अभिव्यक्ति कम से कम कहने में भ्रमित हो सकती है, लेकिन वे जानना अविश्वसनीय रूप से शक्तिशाली और सार्थक हैं। अगर मुझे कुछ उदाहरण है तो मैं इस उदाहरण की अधिक समझ में मदद करने के लिए कर सकता हूं।

+0

"सरल उदाहरण" .. –

+0

एक बहुत ही अच्छी तरह से तैयार किए गए उत्तर के लिए टक्कर और मेरे साथ आने के कुछ ही क्षण बाद। अभी भी बहुत अच्छी तरह से एक साथ रखा और बहुत विस्तृत। धन्यवाद! – VulgarBinary

+0

मैं मानता हूं, LINQ अभिव्यक्तियों में काफी वर्बोज़ और भ्रमित वाक्यविन्यास है। मैं कहूंगा कि LINQ अभिव्यक्तियों तक यह बहुत आसान है, बस कुछ सरल बूलियन अभिव्यक्तियों को एक साथ जोड़ रहा है। – mclark1129

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