2014-06-25 6 views
6

जैसे: एक्स => x.Name = "जी"Expression.Like

मैं आकर्षण की तरह इस

public Expression<Func<TEntity, bool>> SearchExpression() 
{ 
    var c = new ConstantExpression[_paramList.Count]; 
    var b = new BinaryExpression[_paramList.Count]; 
    BinaryExpression comparisonExpression = null; 

    var entity = Expression.Parameter(typeof(TEntity)); 

    for (int i = 0; i < _paramList.Count; i++) 
    { 
     var value = Convert.ChangeType(_paramList[i].Item2 /*"g"*/, _paramList[i].Item3 /*System.String*/); 
     c[i] = Expression.Constant(value); //"g" 

     // PROBLEM IS HERE 
     b[i] = Expression.Equal(Expression.Property(entity, _paramList[i].Item1 /*Name*/, c[i]); 
     // PROBLEM IS HERE 



    } 
    _paramList.Clear(); 
    comparisonExpression = b.Aggregate(Expression.And); 
    return Expression.Lambda<Func<TEntity, bool>>(comparisonExpression, entity); 
} 

काम करता है की तरह कोड ब्लॉक है, लेकिन मैं जरूरत Expression.Like(जैसा "जी" बराबर नहीं "जी")

Expression.Like(Expression.Property(entity, _paramList[i].Item1), c[i]) 

लेकिन सी # अभिव्यक्ति पेड़ मीटर की तरह का समर्थन नहीं करता ethod

अद्यतन:

मैं कुछ इस तरह लिखा है:

Expression.Call(Expression.Property(entity, _paramList[i].Item1), 
       typeof(String).GetMethod("Contains"), new Expression[] { c[i] }); 

लेकिन मैं BinaryExpression नहीं MethodCallExpression

+0

मैं तुम्हें string.Contains के लिए एक विधि मंगलाचरण इंजेक्षन करने की जरूरत है लगता है। अभिव्यक्ति के रूप में उपलब्ध बॉक्स से बाहर 'अभिव्यक्ति। जैसा' नहीं है। – Maarten

+0

@ एड्रियन रैग, अभिव्यक्ति में ट्री स्ट्रिंग नहीं है !!!!!!!!!!!! –

+0

@ user3432343 * संभव *। यदि आप कह रहे हैं कि यह नहीं है, तो मैं करीबी वोट वापस ले जाऊंगा। –

उत्तर

4

आप एक विधि कॉल पर अभिव्यक्ति के बराबर होती है जोड़ने, तो तरह से अपने कोड काम कर सकते हैं:

b[i] = Expression.Equal(
     Expression.Call(Expression.Property(entity, _paramList[i].Item1), 
     typeof (String).GetMethod("Contains"), 
      new Expression[] {c[i]}), Expression.Constant(true)); 

छद्म कोड में यह पढ़ता है:

b[i] = entity => entity.someProperty.Contains(c[i]) == true; 

कौन सा एक द्विआधारी अभिव्यक्ति वापस आ जाएगी तुम्हारे लिए।

2

यह जवाब आपके सरणी और 'और' एकत्रीकरण पर विचार नहीं करता की जरूरत है, लेकिन इसे एक अलग मुद्दे के रूप में माना जाना चाहिए।

इस वर्ग पर विचार करें:

static Expression<Func<TEntity, bool>> Like<TEntity>(string propertyName, string queryText) 
{ 
    var parameter = Expression.Parameter(typeof (TEntity), "entity"); 
    var getter = Expression.Property(parameter, propertyName); 
    //ToString is not supported in Linq-To-Entities, throw an exception if the property is not a string. 
    if (getter.Type != typeof (string)) 
     throw new ArgumentException("Property must be a string"); 
    //string.Contains with string parameter. 
    var stringContainsMethod = typeof (string).GetMethod("Contains", new[] {typeof (string)}); 
    var containsCall = Expression.Call(getter, stringContainsMethod, 
     Expression.Constant(queryText, typeof (string))); 

    return Expression.Lambda<Func<TEntity, bool>>(containsCall, parameter); 
} 

अगर आप चाहते हैं:

select ... from MyEntity where Name like '%query%'; 

निम्न विधि से ऊपर क्वेरी पैटर्न की एक सामान्य दिया गया है:

class MyEntity { string Name { get; set; } } 

हम क्वेरी करना चाहते हैं query% या %query का पैटर्न रखने के लिए आपका उपयोग कर सकते हैं Contains के बजायऔर string.EndsWith

इसके अलावा, यदि आप हस्ताक्षर समायोजित करते हैं तो आप एकाधिक कॉल में पैरामीटर साझा कर सकते हैं।

वर्तमान कार्यान्वयन एक अपवाद फेंकता है यदि संपत्ति का डेटा प्रकार स्ट्रिंग नहीं है। संख्याओं को तारों में परिवर्तित करने के लिए इस उत्तर को https://stackoverflow.com/a/3292773/668272 पर देखें।

+1

वह अंतिम कथन अब ईएफ 6.1 के रूप में सत्य नहीं है। मैंने इसके लिए contrib लिखा :) .. तो आप स्ट्रिंग्स और प्राइमेटिव्स को समेट सकते हैं और कॉल भी कर सकते हैं। ToString() में गैर तार .. –

1

मैंने इसे लिखी एक स्क्रिप्टिंग भाषा में किया है, जो आपको name line 'bob%' जैसी चीजें कहने की अनुमति देता है। चाल यह है कि आपको इसे एक विधि कॉल में मैप करने की आवश्यकता है जो मूल्य और नियमित अभिव्यक्ति लेता है और इसे Expression के भीतर से कॉल करता है।

अगर आप मेरा तार पटकथा भाषा में LikeEvaluator वर्ग पर एक नज़र आप देखेंगे कि कैसे मैं यह किया ले:

static class LikeEvaluator 
{ 
    private static readonly MethodInfo ApplyLikeMethodInfo=typeof(LikeEvaluator).GetMethod("ApplyLike"); 
    private static readonly MethodInfo ApplyLikeNoCaseMethodInfo=typeof(LikeEvaluator).GetMethod("ApplyLikeNoCase"); 

    public static Expression Like(CaseMode caseMode, Expression lhs, Expression pattern) 
    { 
     Expression x=null; 

     if(caseMode==CaseMode.Sensitive) 
     { 
      x=Expression.Call(ApplyLikeMethodInfo,lhs,pattern); 
     } 
     else 
     { 
      x=Expression.Call(ApplyLikeNoCaseMethodInfo,lhs,pattern); 
     } 

     return x; 
    } 

    public static bool ApplyLike(string text, string likePattern) 
    { 
     string pattern=PatternToRegex(likePattern); 
     return Regex.IsMatch(text,pattern,RegexOptions.None); 
    } 

    public static bool ApplyLikeNoCase(string text, string likePattern) 
    { 
     string pattern=PatternToRegex(likePattern); 
     return Regex.IsMatch(text,pattern,RegexOptions.IgnoreCase); 
    } 

    public static string PatternToRegex(string pattern) 
    { 
     pattern=Regex.Escape(pattern); 
     pattern=pattern.Replace("%",@".*"); 
     pattern=string.Format("^{0}$",pattern); 

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