Linq-to-SQL如何使用and/or结合两个Expression<Func<T, bool>>(“where子句”)?

6
首先,我必须说我在StackOverflow上读了几篇有关此问题的文章,但我无法得到所需的结果。
让我简单解释一下背景:我正在使用Linq-to-SQL查询最近拜访商店的客户,并(可选)仅获取特定支付金额的客户。假设我拥有一个包含客户、拜访和付款类的模型。
因此,关注Where表达式,我正在尝试这样做:
Expression<Func<Entityes.Clients, bool>> filter = null;

filter = c => 
          c.Visits.Any(v => v.VisitDate > DateTime.Now.Date.AddMonths(-(int)visitsSince));


if (minPayment.HasValue && minPayment.Value > 0)
{
     filter.And(
               c => c.Payments.Sum(p => p.Quantity) > minPayment.Value);
}
filter.And 方法是一个扩展方法,在这个论坛中被推荐使用,下面是定义:
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,
                                            Expression<Func<T, bool>> expression2)
{
  InvocationExpression invokedExpression =
      Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());

  return Expression.Lambda<Func<T, bool>>
      (Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
}

然而,这并没有按照我的期望工作,结果没有按支付金额进行过滤。由于以下代码可以正常工作,因此数据或linq-to-sql模型没有错误:

filter = c => 
           c.Visits.Any(v => v.VisitDate > DateTime.Now.Date.AddMonths(-(int)visitsSince)))
             && c => c.Payments.Sum(p => p.Quantity) > minPayment.Value;

然而,我不想使用最后的代码,因为我有一些更复杂的场景需要逐步构建筛选表达式,并使用每个部分的“and/or”组合。

附注:我是一个“ADO.Net数据集”人,正在尝试学习Linq-to-SQL和即将推出的Entity Framework,希望很快能对StackOverflow社区有所帮助。


3
附言:您应该使用Expression.AndAlso()方法生成逻辑AND表达式(&&)。Expression.And()生成位AND表达式(&)。 - Jeff Mercado
3个回答

4

您没有把 And 运算的结果赋值给任何变量。

我猜您代码中应该这样写:

if (minPayment.HasValue && minPayment.Value > 0)
{
   filter = filter.And(
            c => c.Payments.Sum(p => p.Quantity) > minPayment.Value);
}

事实是,您(或您提到的SO)的And函数返回包含两个表达式连接的表达式。它不会改变调用它的对象。

@FranCD 不用谢。顺便说一下,我自作主张将你的问题回滚到原始版本,这样更多的访问者可以看到实际的原始代码。否则,下面的答案就毫无意义了。 - Krizz

1
问题出在这一行:
filter.And(c => c.Payments.Sum(p => p.Quantity) > minPayment.Value); 

And 方法返回了另一个委托,你还没有分配给任何东西。尝试这样做:

filter = filter.And(c => c.Payments.Sum(p => p.Quantity) > minPayment.Value); 

仅作澄清,And是一个方法,它接受两个表达式并将它们的逻辑组合成一个新的表达式。它不会改变执行的表达式,而是将新的表达式作为返回值返回。因此,在您的代码中,您调用了filter.And(...),但没有对返回值做任何处理,所以filter仍然引用原始的lambda表达式。


0

我使用的 And 实现来自 PredicateBuilder 类,但它不起作用... 错在哪里? - Fran CD
@FranCD,您的用法有误,请参考我的答案。 - Krizz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接