在LINQ/SQL查询中合并部分表达式



我有一个表达式,它在查询中返回一个DateTime列。

Expression<Func<T, DateTime>> GetDateExpression;
GetDateExpression = td => td.DateShipped;

但是现在我想用这个表达式在SQL查询中形成一个过滤器。

query = query.Where(td => GetDateExpression(td) >= startDate);

但是不能编译。

错误CS1955:不可调用的成员'DateFilter。GetDateExpression'不能像方法一样使用。

谁能告诉我如何使用GetDateExpression构造上面的where子句?

你可以写一个方法从两个操作数构造一个新的GreaterThanOrEqual表达式

背后的思想是这样的。您需要构造一个新的表达式,如下所示:

td => td.DateShipped >= startDate.Value

使用你现有的表达式td => td.DateShipped的身体,但重要的是这里的td在结果表达式和td在你的GetDateExpression是不同的东西,所以如果你只是写greaterThanOrEqual表达式而不替换你会得到这样的东西:

td1 => td2.DateShipped >= startDate.Value

因此,您需要将td2替换为td1,以便表达式看起来像我在开始时写的那样。因此,替换器所做的就是用我们的filterParam替换它在表达式树中找到的每个ParameterExpression

你可以看看下面的答案来了解更多:

  • 为什么我们首先需要替代品
  • ParameterReplacer在我的回答中使用的实现
  • 针对不同情况提供不同解决方案的好答案
Expression<Func<T, bool>> GreaterThanOrEqual(Expression<Func<T, DateTime?>> operand1, Expression<Func<T, DateTime?>> operand2)
{
var filterParam = Expression.Parameter(typeof(T));
var greaterThanOrEqual = Expression.GreaterThanOrEqual(operand1.Body, operand2.Body);
greaterThanOrEqual = (BinaryExpression) new ParameterReplacer(filterParam).Visit(greaterThanOrEqual);

return Expression.Lambda<Func<T, bool>>(greaterThanOrEqual, filterParam);
}

internal class ParameterReplacer : ExpressionVisitor {
private readonly ParameterExpression _parameter;
protected override Expression VisitParameter(ParameterExpression node) {
return base.VisitParameter(_parameter);
}
internal ParameterReplacer(ParameterExpression parameter) {
_parameter = parameter;
}
}

然后像

一样使用
Expression<Func<T, DateTime?>> getDateExpression = m => m.Date;
Expression<Func<MyClass, bool>> combined = GreaterThanOrEqual(getDateExpression, td => startDate.Value);

query = query.Where(combined);

最新更新