英文:
C# Expression Tree AndAlso for Entity Framework query
问题
在尝试使用AndAlso
组合两个表达式时,我遇到了错误。
步骤1:使用表达式树构建EF对象的表达式:
public override Expression<Func<T, bool>> ToExpression()
{
var expressionParameter = Expression.Parameter(typeof(T), "p");
var expressionField = Expression.PropertyOrField(expressionParameter, field);
var expressionConstraint = Expression.Constant(value);
BinaryExpression expression = Expression.Equal(expressionField, expressionConstraint);
return Expression.Lambda<Func<T, bool>>(expression, expressionParameter);
}
如果我调用.ToExpression()
并针对一个表达式运行此代码,这段代码在EF中可以正常工作,它生成了表达式:
{ p => (p.MyField1 == "X") }
但是,当我尝试进行以下操作时:
步骤2:使用AndAlso
组合两个表达式:
public override Expression<Func<T, bool>> ToExpression()
{
Expression<Func<T, bool>> leftExpression = left.ToExpression();
Expression<Func<T, bool>> rightExpression = right.ToExpression();
BinaryExpression andExpression = Expression.AndAlso(leftExpression.Body, rightExpression.Body);
return Expression.Lambda<Func<T, bool>>(andExpression, leftExpression.Parameters.Single());
}
这会生成一个表达式:
{ p => ((p.MyField1 == "X") AndAlso (p.MyField2 == "Y")) }
在尝试使用.Where(expression)
调用它时,我得到了以下错误:
System.InvalidOperationException: LINQ表达式'p'无法被转换。要么以可翻译的形式重写查询,要么通过插入对'AsEnumerable'、'AsAsyncEnumerable'、'ToList'或'ToToListAsync'的调用显式切换到客户端评估。
为什么单独的表达式可以工作,但与AndAlso
组合的表达式不能工作呢?
英文:
I get an error when trying to combine two expressions with AndAlso
.
Step 1: building expression for EF object with expression tree:
public override Expression<Func<T, bool>> ToExpression()
{
var expressionParameter = Expression.Parameter(typeof(T), "p");
var expressionField = Expression.PropertyOrField(expressionParameter, field);
var expressionConstraint = Expression.Constant(value);
BinaryExpression expression = Expression.Equal(expressionField, expressionConstraint);
return Expression.Lambda<Func<T, bool>>(expression, expressionParameter);
}
If I'm calling .ToExpression();
and running this for one expression, this code works fine with EF, it produces expression:
{ p => (p.MyField1 == "X") }
But when I'm trying to do
Step 2: combine two expressions with AndAlso
:
public override Expression<Func<T, bool>> ToExpression()
{
Expression<Func<T, bool>> leftExpression = left.ToExpression();
Expression<Func<T, bool>> rightExpression = right.ToExpression();
BinaryExpression andExpression = Expression.AndAlso(leftExpression.Body, rightExpression.Body);
return Expression.Lambda<Func<T, bool>>(andExpression, leftExpression.Parameters.Single());
}
This produces an expression:
{ p => ((p.MyField1 == "X") AndAlso (p.MyField2 == "Y")) }
It seems fine to me, but when trying to call it with .Where(expression)
I get this error:
> System.InvalidOperationException: The LINQ expression 'p' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
Any idea why separate expressions work but combined with AndAlso
don't?
答案1
得分: 1
你的 Expression.Lambda
调用可能需要从一个像这样的 Expression.Invoke
调用开始:
var expr = Expression.Invoke(expression, expressionParameter);
return Expression.Lambda<Func<T, bool>>(expr, expressionParameter);
英文:
Your Expression.Lambda
calls probably need to start with a call to Expression.Invoke
like this:
var expr = Expression.Invoke(expression, expressionParameter);
return Expression.Lambda<Func<T, bool>>(expr, expressionParameter);
答案2
得分: 0
实现ParameterReplacer
起到了作用,我找到并使用的实现如下:
internal class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node) => node == _oldValue ? _newValue : base.Visit(node);
}
感谢您的建议。
英文:
Implementing ParameterReplacer
did the trick, implementation that I have found and used:
internal class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node) => node == _oldValue ? _newValue : base.Visit(node);
}
Thank's for your suggestions.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论