I have the following method to build some custom EF queries to support a text filter which is very close to working, but I'm having a problem with the LEFT side of the assembled expression. When I use "Expression.Invoke" (first line of method body), I get an exception that The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
which makes sense to me (I conceptually understand what's going on in the LINQ => SQL translation). So I figured the left side of the expression must need something more like the right side (i.e. using Expression.Constant
) where all the 'preprocessing' is done so LINQ to Entities knows how to construct the left side of the expression.
But when I use the 2nd line (Expression.Property
), I get an exception:
Instance property 'PropertyName' is not defined for type System.Func2[Proj.EntityFramework.DomainObject,System.Decimal]'
Which I understand.... much less.
Example call to the method in question:
return context.DomainObjects.Where(BuildExpression(l => l.PropertyName, "<200"));
So, I roughly get that I'm building the expression wrong and it's trying to pull the property name off the supplied expression rather than whatever EF needs to compile the SQL statement, but I'm a bit lost at this point.
private static Expression<Func<DomainObject, bool>> BuildExpression<TDest>(
Expression<Func<DomainObject, TDest>> propertyexpression,
string term
) where TDest : struct {
//var property = Expression.Invoke(propertyexpression, propertyexpression.Parameters.ToArray());
var property = Expression.Property(propertyexpression, ((MemberExpression)propertyexpression.Body).Member.Name);
var parser = new ParsedSearchTerm<TDest>(term); // e.g. "<200" => { LowerBound = null, Operator = "<", UpperBound = 200 }
Expression final = null;
if (parser.HasLowerBound) {
final = Expression.AndAlso(
Expression.GreaterThanOrEqual(property, Expression.Constant(parser.LowerBound)),
Expression.LessThanOrEqual(property, Expression.Constant(parser.UpperBound)));
}
else {
switch (parser.Operator) {
case "<":
final = Expression.LessThanOrEqual(property, Expression.Constant(parser.UpperBound));
break;
case ">":
final = Expression.GreaterThanOrEqual(property, Expression.Constant(parser.UpperBound));
break;
case "=":
final = Expression.Equal(property, Expression.Constant(parser.UpperBound));
break;
case "!":
final = Expression.Negate(Expression.Equal(property, Expression.Constant(parser.UpperBound)));
break;
}
}
return Expression.Lambda<Func<DomainObject, bool>>(final, propertyexpression.Parameters.ToArray());
}