我正在尝试修改动态构建包含表达式的表达式树,该表达式最终会产生类似 SQL
P IN (123, 124, 125, 200, 201)
改为检查执行范围检查,最终导致像 SQL
(P >= 123 AND P <= 125) OR (P >= 200 AND P <= 201)
我的解决方案基于这篇文章。
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()();
但是,当我将该代码放入要与 Linq 一起使用的方法中时,我无法弄清楚如何从传入的表达式中获取比较值。该方法的签名是:
Expression<Func<TElement, bool>> BuildRangeExpression<TElement>( Expression<Func<TElement, long>> valueSelector, IEnumerable<long> values)
它的用法如下:
Expression<MyType, bool> match = BuildRangeExpression<MyType, long>(my => my.ProductCode, productCodes); var result = db.MyTypes.Where(match);
问题
我该如何评价
Expression<Func<TElement, long>> valueSelector
这样我就可以使用传入的值BuildRangeExpression而不是我当前的硬编码值
BuildRangeExpression
long testValue = 5;
我认为博客文章中的代码正是您所需要的:您所要做的就是使用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); }