逐步构建OR查询表达式

在LINQ中,可以逐步构建LINQ查询,如下所示:

var context = new AdventureWorksDataContext(); // Step 1 var query = context.Customers.Where(d => d.CustomerType == "Individual"); // Step 2 query = query.Where(d => d.TerritoryID == 3); 

上面的查询将产生一个等效的SQL语句,其WHERE子句包含由AND逻辑运算符组合在一起的两个谓词,如下所示:

 SELECT * FROM Customers WHERE CustomerType = 'Individual' AND TerritoryID = 3 

是否可以构建LINQ查询以progressively生成等效的SQL语句,以便生成的查询具有WHERE子句,其中谓词由OR逻辑运算符组合在一起,如下所示?

 SELECT * FROM Customers WHERE CustomerType = 'Individual' OR TerritoryID = 3 

您需要首先构造filter,然后将filter组合成一个可用作组合查询的lambda:

 var filters = new List>>(); filters.Add(d => d.TerritoryID == 3); filters.Add(d => d.CustomerType == "Individual"); ... var lambda = AnyOf(filters.ToArray()); // this is: d => d.TerrotoryID == 3 || d.CustomerType == "Individual"; var data = src.Where(lambda); 

使用:

 static Expression> AnyOf( params Expression>[] expressions) { if (expressions == null || expressions.Length == 0) return x => false; if (expressions.Length == 1) return expressions[0]; var body = expressions[0].Body; var param = expressions[0].Parameters.Single(); for (int i = 1; i < expressions.Length; i++) { var expr = expressions[i]; var swappedParam = new SwapVisitor(expr.Parameters.Single(), param) .Visit(expr.Body); body = Expression.OrElse(body, swappedParam); } return Expression.Lambda>(body, param); } class SwapVisitor : ExpressionVisitor { private readonly Expression from, to; public SwapVisitor(Expression from, Expression to){ this.from = from; this.to = to; } public override Expression Visit(Expression node) { return node == from ? to : base.Visit(node); } } 

如果你想分两步,你可以使用union:

 var context = new AdventureWorksDataContext(); // Step 1 var query = context.Customers.Where(d => d.CustomerType == "Individual"); // step2 query = query.Union(context.Customers.Where(d => d.TerritoryID == 3)); 

要在不使用动态linq lib的情况下完成您的要求,您可以在where子句中为每个测试定义表达式,然后使用它们来构建lambda表达式:

 Expression> isIndividualCustomer = c => c.CustomerType == "Individual"; Expression> territoryIdIs3 = c => c.TerritoryID == 3; Expression> customerIsIndividualOrOfTerritoryId3 = Expression.Lambda>( Expression.Or(isIndividualCustomer.Body, territoryIdIs3.Body), isIndividualCustomer.Parameters.Single()); 

用法:

 var query = context.Customers.Where(customerIsIndividualOrOfTerritoryId3); 

虽然您可以直接执行此类操作,但我使用LinqKit库,这使得这种渐进式查询构建非常简单:

你会最终得到:

 var context = new AdventureWorksDataContext(); // Step 1 var query = context.Customers.Where(d => d.CustomerType == "Individual"); // Step 2 query = query.Or(d => d.TerritoryID == 3); 

我正在研究的系统需要很多,LinqKit是一个重要的救生员。 你可以在这里找到它。

(注意:无论如何,我与LinqKit的开发者没有关系 – 只是一个粉丝。)