[英]Understanding Expression Tree and Parameter Evaluation
I'm attempting to modify an expression tree that dynamically builds a Contains expression that ultimately results in SQL like 我试图修改一个表达式树,该树动态构建一个Contains表达式,最终导致SQL
P IN (123, 124, 125, 200, 201)
to instead check perform range checks, which ultimately results in SQL like 而是进行范围检查,最终导致SQL
(P >= 123 AND P <= 125) OR (P >= 200 AND P <= 201)
I'm basing my solution on 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);
}
I'm able to get the range checking to work if I provide the value for comparison: 如果我提供比较值,我就能使范围检查工作:
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()();
However, I cannot sort out how to get the value for comparison from the passed-in expression when I drop that code into the method to be used with Linq. 但是,当我将该代码放到与Linq一起使用的方法中时,我无法从传入的表达式中找出如何获取用于比较的值。 The signature of that method is:
该方法的签名是:
Expression<Func<TElement, bool>>
BuildRangeExpression<TElement>(
Expression<Func<TElement, long>> valueSelector,
IEnumerable<long> values)
and it is used like: 它的用法如下:
Expression<MyType, bool> match =
BuildRangeExpression<MyType, long>(my => my.ProductCode, productCodes);
var result = db.MyTypes.Where(match);
QUESTION 题
How can I evaluate 我该如何评估
Expression<Func<TElement, long>> valueSelector
so that I can use the value passed into BuildRangeExpression
instead of my currently hard-coded value 这样我就可以使用传递给
BuildRangeExpression
的值代替我当前的硬编码值
long testValue = 5;
I think the code from the blog post has exactly what you need: all you have to do is to use valueSelector.Body
instead of your Expression.Constant()
and also add the original parameter to the generated expression: 我认为博客文章中的代码完全满足您的需求:您要做的就是使用
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);
}
Use Expression.Parameter
. 使用
Expression.Parameter
。
Create a parameter: 创建一个参数:
var param = Expression.Parameter(typeof(TElement), "arg")
Instead of Expression.Constant(testvalue)
, you will need to put param
. 您需要放置
param
而不是Expression.Constant(testvalue)
。
Then, you need to do: 然后,您需要执行以下操作:
var result = Expression.Lambda<Func<TElement, bool>>(final, param).Compile()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.