了解表达式树和参数评估 [英] Understanding Expression Tree and Parameter Evaluation

查看:129
本文介绍了了解表达式树和参数评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图修改表达式树动态地构建一个包含表达式最终导致SQL像



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



,而不是检查执行范围检查,最终导致SQL像



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



我基础上的这个帖子

 静态公共表达式来; Func键< TElement,布尔>> 
BuildContainsExpression< TElement,TValue>(
表达式来; Func键< TElement,TValue>> valueSelector,IEnumerable的< TValue>的值)
{
//删除了帖子:输入检查和边缘情况

无功等于=
values.Select(价值=>
(表情)Expression.Equal(valueSelector.Body,
Expression.Constant(价值的typeof(TValue))));

变种体= equals.Aggregate<表达>((积累,等于)=>
Expression.Or(积累,等于));

返回Expression.Lambda<&Func键LT; TElement,布尔>>(身体,P);
}



我能够得到检查工作,如果我提供的价值范围比较:

 长testValue = 5; 
名单,LT; KeyValuePair< INT,INT>>范围=新的List< KeyValuePair< INT,INT>>()
{
新KeyValuePair<长,长>(3,6),
新KeyValuePair<长,长>(10 ,12),
新KeyValuePair&下;长,长>(20,20),
};

名单,LT; BinaryExpression> rangeExpressions =新的List< BinaryExpression>();

的foreach(在范围VAR对)
{
变种greaterThanOrEqual =
Expression.GreaterThanOrEqual(Expression.Constant(testValue),
Expression.Constant( pair.Key));

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

VAR INRANGE = Expression.AndAlso(greaterThanOrEqual,lessThanOrEqual);
rangeExpressions.Add(INRANGE);
}

变种最后=
rangeExpressions.Aggregate&所述;表达>((A,B)=> Expression.Or(A,B));

VAR的结果= Expression.Lambda<&Func键LT;布尔>>(最终).Compile()();



不过,我无法理清如何获取值从传入的表达时比较,我丢弃代码到与LINQ的使用的方法。该方法的签名是:



 表达式来; Func键< TElement,布尔>> 
BuildRangeExpression< TElement>(
表达式来; Func键< TElement,长>> valueSelector,
的IEnumerable<长>的值)

和它的使用方式:

 表达式来; MyType的,布尔>比赛= 
BuildRangeExpression< MyType的,长>(我=> my.ProductCode,productCodes);

VAR的结果= db.MyTypes.Where(比赛);





如何评估

 表达式来; Func键< TElement,长>> valueSelector 



这样我可以用传递到 BuildRangeExpression ,而不是我目前硬编码值

 长testValue = 5; 


解决方案

我觉得从博客文章的代码有什么您需要:所有你所要做的就是用 valueSelector.Body ,而不是你的 Expression.Constant(),也原来的参数添加到生成的表达式:

 公共静态表达式来; Func键< TElement,布尔>> 
BuildRangeExpression< TElement,TValue>(
表达式来; Func键< TElement,TValue>> valueSelector,
的IEnumerable<元组LT; TValue,TValue>>的值)
{
变种p值= valueSelector.Parameters.Single();

无功等于= values.Select(
元组=>
Expression.AndAlso(
Expression.GreaterThanOrEqual(
valueSelector.Body,Expression.Constant (tuple.Item1)),
Expression.LessThanOrEqual(
valueSelector.Body,Expression.Constant(tuple.Item2))));

变种体= equals.Aggregate(Expression.OrElse);

返回Expression.Lambda<&Func键LT; TElement,布尔>>(身体,P);
}


I'm attempting to modify an expression tree that dynamically builds a Contains expression that ultimately results in SQL like

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

to instead check perform range checks, which ultimately results in SQL like

(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. 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

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:

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);
}

这篇关于了解表达式树和参数评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆