在 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 的主体,但重要的是结果表达式中的 tdGetDateExpression 中的 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);