我有以下方法来构建一些自定义的EF查询,以支持一个非常接近工作的文本过滤器,但是我在组装表达式的左侧遇到了问题。当我使用"Expression.Invoke"(方法体的第一行)时,我会得到一个异常,其中
但是当我使用第二行(
LINQ表达式节点类型'Invoke'在LINQ to Entities中不受支持。
这对我来说是有意义的(我概念上理解了在LINQ => SQL翻译中发生了什么)。所以我想左边的表达式必须需要像右边那样需要更多的东西(即使用Expression.Constant
),在所有的“预处理”完成后,LINQ to Entities知道如何构造表达式的左边。但是当我使用第二行(
Expression.Property
)时,我会得到一个异常:Instance property 'PropertyName' is not defined for type System.Func2[Proj.EntityFramework.DomainObject,System.Decimal]'
我理解的远没有那么深。
调用该方法的示例:
return context.DomainObjects.Where(BuildExpression(l => l.PropertyName, "<200"));
所以,我大致了解到我正在构建表达式时出了问题,它试图从提供的表达式中获取属性名称,而不是EF需要编译SQL语句的内容,但此时我有点迷失了。
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());
}
propertyexpression
是一个Func<>
:类型Func
没有名为Member.Name
(=PropertyName
)的属性。只需输入var property = propertyexpression.Body;
。 - NetMageExpression.Invoke
转换为 EF 支持的内容,用于我的左外连接IQueryable
实现,通过使用扩展方法Apply
来实现,该方法通过使用ExpressionVisitor
将参数替换为参数来扩展 lambda 体,如 此答案 所示(您可能不需要在Apply
上使用PropagateNull
)。您只需在使用Expression.Invoke
的位置替换为Apply
即可。 - NetMage