如何制作化合物“;或“;Linq中的子句

本文关键字:子句 Linq 何制作 化合物 | 更新日期: 2023-09-27 17:59:39

如果要将"and"条件添加到Linq查询中,很容易这样做:

var q = MyTable;
if (condition1)
  q = q.Where(t => t.Field1 == value1);
if (condition2)
  q = q.Where(t => t.Field2 > t.Field3);
// etc.

当你想添加"或"条件时,有什么聪明的方法可以做同样的事情吗?

如何制作化合物“;或“;Linq中的子句

您可以使用PredicateBuilder并使用它来构建基于Or的表达式:

 var predicate = PredicateBuilder.False<Product>();
 predicate = predicate.Or (t => t.Field1 == value1);
 predicate = predicate.Or (t => t.Field2 > t.Field3);
 q = q.Where (predicate);

您可以在此处阅读更多信息:http://www.albahari.com/nutshell/predicatebuilder.aspx

PredicateBuilder.False<Product>()中的Product替换为查询的对象。

请注意,您从False谓词开始,因为您希望使用Or。如果您想要And谓词,Yuo应该从True 开始

使用以下内容:

var q = MyTable;
q = q.Where(
     t => (condition1 && t.Field1 == value1) || (condition2 && t.Field2 > t.Field3));
var q = MyTable;
var conditions = new List<Func<T, bool>>();
 if (condition1)
     conditions.Add(t => ...);
 if (condition2)
     conditions.Add(t => ...);
 q.Where(x => conditions.Any(y => y(x)));

有一种方法可以做到这一点,那就是使用表达式树。通过这种方式,您可以自己构建布尔表达式。这是非常直接的,但棘手的部分是,您需要重新设置参数的基础,否则它将引用原始lambda表达式。参见以下示例:

static void Main(string[] args)
{
    var source = new List<int> { 1, 2, 3 };
    var any = new List<Expression<Func<int, bool>>>();
    any.Add(x => x == 1);
    any.Add(x => x == 3);
    foreach (var item in source.AsQueryable().WhereDisjunction(any))
    {
        Console.WriteLine(item);
    }
}
class RewriteSingleParameterUsage : ExpressionVisitor
{
    public ParameterExpression Parameter { get; set; }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return Parameter;
    }
}
public static IQueryable<T> WhereDisjunction<T>(this IQueryable<T> source, IList<Expression<Func<T, bool>>> any)
{
    switch (any.Count)
    {
        case 0: return source;
        case 1: return source.Where(any[0]);
        default:
            var p = Expression.Parameter(any[0].Parameters[0].Type, any[0].Parameters[0].Name);
            var rw = new RewriteSingleParameterUsage { Parameter = p };
            var expr = rw.Visit(any[0].Body);
            for (int i = 1; i < any.Count; i++)
            {
                expr = Expression.Or(expr, rw.Visit(any[i].Body));
            }
            return source.Where(Expression.Lambda<Func<T, bool>>(expr, p));
    }
}

在上面的例子中,我非常苛刻,我有效地将任何参数替换为用于创建新表达式的单个新参数。然而,考虑到这个扩展方法的签名,应该不可能用参数来调用这个方法,这样会导致错误。然而,如果涉及多个参数,这将是一个问题。

这与我在这里给出的答案相同

正如Marc Gravell所说,它涉及到表达式树的组合。

这篇文章向您展示了如何做到这一点。最初设置它需要一些工作。但这是值得的。

另一种解决方案是使用谓词生成器。这篇文章并没有很好地解释幕后到底发生了什么。但是上面的文章很好地解释了