首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Evaluator.PartialEval减少提供的表达式

Evaluator.PartialEval减少提供的表达式
EN

Stack Overflow用户
提问于 2017-06-08 09:41:53
回答 1查看 762关注 0票数 3

在我的一个项目中,我有一个ExpressionVisitor来将提供的表达式转换为某个查询字符串。但在翻译之前,我需要评估表达式中的所有引用值。为此,我使用了来自Evaluator.PartialEval项目的EntityFramework方法。

假设我有这个查询:

代码语言:javascript
复制
 var page = 100;
 var query = myService.AsQueryable<Product>()
              //.Where(x=>x.ProductId.StartsWith(p.ProductId))
                .Skip(page)
                .Take(page);

var evaluatedQueryExpr = Evaluator.PartialEval(query.Expression);

正如您所看到的,我已经评论了Where方法。在这种情况下,evaluatedQueryExpr将不包含抓取和跳过的方法。

但是,如果在“取”或“跳”所有操作之前使用任何其他表达式方法,计算程序将正确评估表达式并将其完全返回。

我发现这个问题发生在计算器类的第80行中:

代码语言:javascript
复制
return Expression.Constant(fn.DynamicInvoke(null), e.Type);

你能解释一下为什么会发生这种情况并提出解决办法吗?

更新这里是一个关于github的项目

LinqToSolrQueriable遗传自IOrderedQueryable LinqToSolrProvider遗传自IQueryProvider包括引起问题的行范围

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-12 12:54:47

好消息是表达式并没有真正减少(SkipTake仍然存在:),而是简单地从包含原始表达式的MethodCallExpression转换为ConstantExpression

query.Expression

代码语言:javascript
复制
.Call System.Linq.Queryable.Take(
    .Call System.Linq.Queryable.Skip(
        .Constant<LinqToSolr.Query.LinqToSolrQueriable`1[LinqToSolrTest.Product]>(LinqToSolr.Query.LinqToSolrQueriable`1[LinqToSolrTest.Product]),
        100),
    100)

evaluatedQueryExpr:

代码语言:javascript
复制
.Constant<System.Linq.IQueryable`1[LinqToSolrTest.Product]>(LinqToSolr.Query.LinqToSolrQueriable`1[LinqToSolrTest.Product])

在这里,调试显示给您一个错误的印象。如果采用ConstaintExpression.Value,您将看到它是一个IQueryable<Product>Expression属性与原始query.Expression完全相同。

坏消息是,这不是您对PartialEval的期望--实际上,在这种情况下,它没有做任何有用的事情(除了可能破坏您的查询转换逻辑)。

那为什么会发生这种事?

您从EntityFramework.Extended库中使用的方法依次从MSDN示例演练:创建IQueryable LINQ中获取(如注释中所示)。可以注意到,PartialEval方法有两个重载-一个带有Func<Expression, bool> fnCanBeEvaluated参数,用于识别给定的表达式节点是否可以是本地函数的一部分(换句话说,要部分评估),另一个方法没有这样的参数(由您使用),后者只调用第一个传递以下谓词的谓词:

代码语言:javascript
复制
private static bool CanBeEvaluatedLocally(Expression expression)
{
    return expression.NodeType != ExpressionType.Parameter;
}

其效果是,它停止了对ParameterExpression类型表达式和任何直接或间接包含ParameterExpression的表达式的计算。最后一个应该解释你所观察到的行为。当查询在Where / Take调用之前包含参数化lambda表达式(因此是参数)的Skip (基本上是任何LINQ操作符)时,它将停止对包含方法的计算(从上面的query.Expression调试视图中可以看到-- Where调用将在Skip中)。

现在,MSDN示例使用此重载来计算具体的嵌套Where方法lambda表达式,并且通常不适用于任何类型的表达式(如IQueryable.Expression )。实际上,链接的项目是在QueryCache类中的单个位置使用QueryCache方法,并调用传递不同谓词的另一个重载,该重载除了ParameterExpressions之外,还将停止对任何具有IQueryable结果类型的表达式的计算。

我认为这也是解决你的问题的方法:

代码语言:javascript
复制
var evaluatedQueryExpr = Evaluator.PartialEval(query.Expression,
    // can't evaluate parameters or queries
    e => e.NodeType != ExpressionType.Parameter &&
        !typeof(IQueryable).IsAssignableFrom(e.Type)
);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44432144

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档