2013-02-18 15 views
2

我試圖修改表達式樹用於動態創建一個包含表達式最終導致SQL像理解表達式樹和參數評估

P IN (123, 124, 125, 200, 201)

,而不是檢查執行範圍檢查,最終導致SQL像

(P >= 123 AND P <= 125) OR (P >= 200 AND P <= 201)

我立足於this post我的解決方案。

static public Expression<Func<TElement, bool>> 
BuildContainsExpression<TElement, TValue>(
    Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values) 
{ 
    // Removed for post: Input checks and edge cases 

    var equals = 
     values.Select(value => 
     (Expression)Expression.Equal(valueSelector.Body, 
            Expression.Constant(value, typeof(TValue)))); 

    var body = equals.Aggregate<Expression>((accumulate, equal) => 
              Expression.Or(accumulate, equal)); 

    return Expression.Lambda<Func<TElement, bool>>(body, p); 
} 

我能夠得到檢查工作,如果我提供比較值範圍:

long testValue = 5; 
List<KeyValuePair<int, int>> ranges = new List<KeyValuePair<int, int>>() 
{ 
    new KeyValuePair<long, long>(3, 6), 
    new KeyValuePair<long, long>(10, 12), 
    new KeyValuePair<long, long>(20, 20), 
}; 

List<BinaryExpression> rangeExpressions = new List<BinaryExpression>(); 

foreach (var pair in ranges) 
{ 
    var greaterThanOrEqual = 
     Expression.GreaterThanOrEqual(Expression.Constant(testValue), 
             Expression.Constant(pair.Key)); 

    var lessThanOrEqual = 
     Expression.LessThanOrEqual(Expression.Constant(testValue), 
            Expression.Constant(pair.Value)); 

    var inRange = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual); 
    rangeExpressions.Add(inRange); 
} 

var final = 
    rangeExpressions.Aggregate<Expression>((a, b) => Expression.Or(a, b)); 

var result = Expression.Lambda<Func<bool>>(final).Compile()(); 

但是,我不能理清如何獲取值從passed-比較在表達式中,當我將該代碼放入與Linq一起使用的方法中時。該方法的簽名是:

Expression<Func<TElement, bool>> 
BuildRangeExpression<TElement>(
    Expression<Func<TElement, long>> valueSelector, 
    IEnumerable<long> values) 

,它是用來像:

問題

如何評估

Expression<Func<TElement, long>> valueSelector 

,這樣我可以使用價值傳遞到BuildRangeExpression而不是我目前LY硬編碼值

long testValue = 5; 

回答

3

我想從博客文章的代碼有您需要的東西:你所要做的就是用valueSelector.Body,而不是你Expression.Constant()並添加原參數生成的表達式:

public static Expression<Func<TElement, bool>> 
    BuildRangeExpression<TElement, TValue>(
    Expression<Func<TElement, TValue>> valueSelector, 
    IEnumerable<Tuple<TValue, TValue>> values) 
{ 
    var p = valueSelector.Parameters.Single(); 

    var equals = values.Select(
     tuple => 
     Expression.AndAlso(
      Expression.GreaterThanOrEqual(
       valueSelector.Body, Expression.Constant(tuple.Item1)), 
      Expression.LessThanOrEqual(
       valueSelector.Body, Expression.Constant(tuple.Item2)))); 

    var body = equals.Aggregate(Expression.OrElse); 

    return Expression.Lambda<Func<TElement, bool>>(body, p); 
} 
1

使用Expression.Parameter

創建參數:

var param = Expression.Parameter(typeof(TElement), "arg") 

相反的Expression.Constant(testvalue),你將需要把param

然後,你需要做的:

var result = Expression.Lambda<Func<TElement, bool>>(final, param).Compile() 
+0

這還不夠,表達式還應該從'valueSelector'訪問屬性。 – svick 2013-02-18 22:29:24