在 LINQ/SQL 查询中合并部分表达式
Incorporate partial expression in LINQ/SQL query
我有一个表达式 returns 查询中的 DateTime 列。
Expression<Func<T, DateTime>> GetDateExpression;
GetDateExpression = td => td.DateShipped;
但现在我想使用该表达式在 SQL 查询中形成过滤器。
query = query.Where(td => GetDateExpression(td) >= startDate);
但是无法编译。
error CS1955: Non-invocable member 'DateFilter.GetDateExpression' cannot be used like a method.
谁能告诉我如何使用 GetDateExpression
构造上面的 where 子句?
你可以写一个方法从两个操作数
构造一个新的GreaterThanOrEqual
表达式
这背后的想法如下。您想要构造一个如下所示的新表达式:
td => td.DateShipped >= startDate.Value
使用现有表达式 td => td.DateShipped
的主体,但重要的是结果表达式中的 td
和 GetDateExpression
中的 td
是不同的东西,所以如果你只写 greaterThanOrEqual 表达式而不替换你会得到这样的东西:
td1 => td2.DateShipped >= startDate.Value
因此您需要将 td2
替换为 td1
以便表达式看起来像我在开头写的那样。因此,替换器所做的就是用我们的 filterParam
.
替换它在表达式树中找到的每个 ParameterExpression
您可以查看以下答案以进一步了解此内容:
- Why we need replacer in the first place
- Implementation of
ParameterReplacer
used in my answer
- Great answer with different solutions for different cases
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);
我有一个表达式 returns 查询中的 DateTime 列。
Expression<Func<T, DateTime>> GetDateExpression;
GetDateExpression = td => td.DateShipped;
但现在我想使用该表达式在 SQL 查询中形成过滤器。
query = query.Where(td => GetDateExpression(td) >= startDate);
但是无法编译。
error CS1955: Non-invocable member 'DateFilter.GetDateExpression' cannot be used like a method.
谁能告诉我如何使用 GetDateExpression
构造上面的 where 子句?
你可以写一个方法从两个操作数
构造一个新的GreaterThanOrEqual
表达式
这背后的想法如下。您想要构造一个如下所示的新表达式:
td => td.DateShipped >= startDate.Value
使用现有表达式 td => td.DateShipped
的主体,但重要的是结果表达式中的 td
和 GetDateExpression
中的 td
是不同的东西,所以如果你只写 greaterThanOrEqual 表达式而不替换你会得到这样的东西:
td1 => td2.DateShipped >= startDate.Value
因此您需要将 td2
替换为 td1
以便表达式看起来像我在开头写的那样。因此,替换器所做的就是用我们的 filterParam
.
ParameterExpression
您可以查看以下答案以进一步了解此内容:
- Why we need replacer in the first place
- Implementation of
ParameterReplacer
used in my answer - Great answer with different solutions for different cases
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);