我有一个表达式,它在查询中返回一个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);