2012-05-07 12 views
6

मैं अपने एंटिटी फ्रेमवर्क एप्लिकेशन के लिए एक साधारण खोज क्वेरी लिख रहा हूं। मुझे यह जांचने की ज़रूरत है कि फ़ील्ड का एक गुच्छा शून्य है, और यदि नहीं, तो उन पर ToLower() को कॉल करें और खोज क्वेरी से तुलना करें। LINQ क्वेरी इस तरह दिखता है:क्या LINQ से Entities में कस्टम फ़ंक्शन लिखने का कोई आसान तरीका है?

public IQueryable<Store> SearchStores(string q, IQueryable<Store> source) 
{ 
    q = q.ToLower(); 

    return (
     from s in source 
     where (
      (s.Name != null && s.Name.ToLower().Contains(q)) || 
      (s.Description != null && s.Description.ToLower().Contains(q)) || 
      ... 
} 

वहाँ इस तरह लाइनों के एक बहुत हैं, तो मैं यह थोड़ा साफ करने के लिए एक सहायक विधि लिखने के लिए परीक्षा की गई थी:

public static bool SafeSearch(this string s, string q) 
{ 
    return s == null ? false : s.ToLower().Contains(q); 
} 

इस कोर्स की काम नहीं करता है, हालांकि, LINQ के बाद से संस्थाओं को नहीं समझती क्या सुरक्षित खोज समारोह है:

संस्थाओं को LINQ विधि 'बूलियन सुरक्षित खोज (System.String, System.String)' विधि को नहीं पहचानता है, और यह विधि अनुवाद नहीं हो सकती है एक स्टोर अभिव्यक्ति में ted।

क्या इस तरह एक साधारण कस्टम फ़ंक्शन लिखने का कोई आसान तरीका है?

धन्यवाद!

+0

आपके डेटाबेस पर संयोजन प्रकार क्या है? – Brannon

उत्तर

2

चूंकि linq अभिव्यक्ति का उपयोग करता है जो निष्पादित नहीं होता है जब तक आप वास्तव में डेटाबेस को कॉल नहीं करते हैं, आपको अपने कार्य को भविष्यवाणी के अंदर लपेटना होगा।

private static Func<Country, bool> Predicate(string q) 
{ 
    return x => (
     q.SafeSearch(x.Name) || 
     q.SafeSearch(x.Description) 
     ); 
} 

भी प्रश्न पर यह फोन करके सुरक्षित खोज विस्तार विधि पीछे, ऐसे मामलों में जहां x.Name रिक्त है की देखभाल करेंगे।

public static class SearchExt 
{ 
    public static bool SafeSearch(this string q, string param) 
    { 
     return param == null ? false : param.ToLower().Contains(q); 
    } 
} 

और फिर आप extesion तरीकों

return source.Where(Predicate(q)); 

साथ या LINQ अभिव्यक्ति

return from p in source 
     where Predicate(q).Invoke(p) 
     select p; 
+0

यह विस्तार विधि के साथ काम कर रहा है, लेकिन जब मैं linq में Invoke विधि का उपयोग करके इसे आज़माता हूं, तो मुझे मिलता है: LINQ से Entities 'Boolean Invoke (Localsip.Models.Wine)' विधि को पहचान नहीं पाती है, और यह विधि नहीं हो सकती एक स्टोर अभिव्यक्ति में अनुवाद किया गया। इसके बारे में कोई विचार? – ManicBlowfish

+0

ओह ठीक है, काफी अच्छा है। अभी भी जानना चाहेंगे कि एक LINQ क्वेरी में "पूर्वानुमान" Func को कैसे शामिल किया जाए। यद्यपि कि आपकी इस सहायता के लिए धन्यवाद। – ManicBlowfish

+0

@ManicBlowfish आप स्रोत में पी से वापस लौट सकते हैं। जहां (पूर्वानुमान (क्यू)) पी –

1

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

आगे बढ़ने के लिए आपको 3 सरल कार्यों की लाइब्रेरी की आवश्यकता है। गतिशील रूप से अभिव्यक्तियों को संशोधित करने के लिए वे System.Linq.Expressions.ExpressionVisitor का उपयोग करते हैं। मुख्य विशेषता अभिव्यक्ति के अंदर पैरामीटर को एकीकृत कर रही है, ताकि एक ही नाम वाले 2 पैरामीटर समान (UnifyParametersByName) समान किए गए हों। शेष भाग दिए गए अभिव्यक्ति (ReplacePar) और एक सहायक विधि (NewExpr) के साथ नामित पैरामीटर को प्रतिस्थापित कर रहा है। पुस्तकालय जीआईटीबी पर एमआईटी लाइसेंस के साथ उपलब्ध है: LinqExprHelper, लेकिन आप जल्दी से कुछ लिख सकते हैं।

सबसे पहले आप कुछ विधियों को परिभाषित करते हैं, जिन्हें बाद में गतिशील प्रश्न बनाने में उपयोग किया जा सकता है।

public class Store 
{ 
    ... 

    public static Expression<Func<Store, bool>> 
     SafeSearchName(string sWhat) 
    { 
     return LinqExprHelper.NewExpr(
      (Store s) => s.Name != null && s.Name.ToLower().Contains(sWhat) 
     ); 
    } 

    public static Expression<Func<Store, bool>> 
     SafeSearchDesc(string sWhat) 
    { 
     return LinqExprHelper.NewExpr(
      (Store s) => s.Description != null && s.Description.ToLower().Contains(sWhat) 
     ); 
    } 
} 

तो फिर तुम इस तरह से क्वेरी:

// Define a master condition, using named parameters. 
    var masterExpr = LinqExprHelper.NewExpr(
     (Store s, bool bSearchName, bool bSearchDesc) 
     => (bSearchName && bSearchDesc)); 

    // Replace stub parameters with some real conditions. 
    var combExpr = masterExpr 
     .ReplacePar("bSearchName", Store.SafeSearchName("b").Body) 
     .ReplacePar("bSearchDesc", Store.SafeSearchDesc("p").Body); 
     // Sometimes you may skip a condition using this syntax: 
     //.ReplacePar("bSearchDesc", Expression.Constant(true)); 

    // It's interesting to see how the final expression looks like. 
    Console.WriteLine("expr: " + combExpr); 

    // Execute the query using combined expression. 
    db.Stores 
     .Where((Expression<Func<Store, bool>>)combExpr) 
     .ToList().ForEach(i => { Console.WriteLine(i.Name + ", " + i.Description); }); 

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

क्या यह सब के बाद "सरल" है? यदि आप लिंक के विधि वाक्यविन्यास पर सरल मानते हैं, तो यह लगभग इतना आसान है। यह आपको कस्टम लिंक फ़ंक्शन बनाने की अनुमति नहीं देता है, लेकिन आपको तुलनीय क्षमताओं देता है।

+0

का चयन करें अभिव्यक्ति ने मेरे लिए चाल बनाई –

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