在我的一个项目中,我有一个ExpressionVisitor来将提供的表达式转换为某个查询字符串。但在翻译之前,我需要评估表达式中的所有引用值。为此,我使用了来自Evaluator.PartialEval项目的EntityFramework方法。
假设我有这个查询:
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行中:
return Expression.Constant(fn.DynamicInvoke(null), e.Type);你能解释一下为什么会发生这种情况并提出解决办法吗?
更新这里是一个关于github的项目
LinqToSolrQueriable遗传自IOrderedQueryable LinqToSolrProvider遗传自IQueryProvider包括引起问题的行范围
发布于 2017-06-12 12:54:47
好消息是表达式并没有真正减少(Skip和Take仍然存在:),而是简单地从包含原始表达式的MethodCallExpression转换为ConstantExpression:
query.Expression
.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:
.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参数,用于识别给定的表达式节点是否可以是本地函数的一部分(换句话说,要部分评估),另一个方法没有这样的参数(由您使用),后者只调用第一个传递以下谓词的谓词:
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结果类型的表达式的计算。
我认为这也是解决你的问题的方法:
var evaluatedQueryExpr = Evaluator.PartialEval(query.Expression,
// can't evaluate parameters or queries
e => e.NodeType != ExpressionType.Parameter &&
!typeof(IQueryable).IsAssignableFrom(e.Type)
);https://stackoverflow.com/questions/44432144
复制相似问题