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