8

在 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 查询以生成等效的 SQL 语句,progressively这样生成的查询具有一个 WHERE 子句,其中谓词由OR逻辑运算符组合在一起,如下所示?

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

4 回答 4

19

您需要先构建过滤器,然后将过滤器组合成一个 lambda,您可以将其用作组合查询:

var filters = new List<Expression<Func<YourType, bool>>>();
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<Func<T,bool>> AnyOf<T>(
          params Expression<Func<T,bool>>[] 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<Func<T, bool>>(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);
    }
}
于 2013-03-28T08:54:08.723 回答
1

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


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));

于 2013-03-28T08:56:20.467 回答
0

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

Expression<Func<Customer, bool>> isIndividualCustomer = c => c.CustomerType == "Individual";

Expression<Func<Customer, bool>> territoryIdIs3 = c => c.TerritoryID == 3;

Expression<Func<Car, bool>> customerIsIndividualOrOfTerritoryId3 = Expression.Lambda<Func<Customer, bool>>(
    Expression.Or(isIndividualCustomer.Body, territoryIdIs3.Body), isIndividualCustomer.Parameters.Single());

用法:

var query = context.Customers.Where(customerIsIndividualOrOfTerritoryId3);
于 2013-03-28T09:06:01.283 回答
0

虽然您可以直接执行此类操作,但我使用了 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 的开发人员 - 只是一个粉丝。)

于 2013-03-28T09:12:27.910 回答