简体   繁体   English

如何使用LINQ与分组的OR查询生成AND?

[英]How to generate an AND with a grouped OR query, with LINQ?

I'm struggling to understand how to come up with a query like the following, using LINQ ... 我正在努力了解如何使用LINQ提出如下查询:

SELECT *
FROM foo
WHERE a = false AND (b = true OR c = true)

I'm using Entity Framework and LINQ to query my database. 我正在使用Entity Framework和LINQ查询数据库。 I've got a table and entity class that has some boolean columns, and looks like so ... 我有一个具有一些布尔列的表和实体类,看起来像这样……

public class Foo
{
  public bool A { get; set; }
  public bool B { get; set; }
  public bool C { get; set; }
}

var foos = DbSet<Foo>();

I'm trying to write a query that will select these records in such a way that if I want to include columns that are true, they need to be OR'd together, not AND'd. 我正在尝试编写一个查询,该查询将选择这些记录,以便如果我要包括正确的列,则需要将它们进行“或”运算,而不是“与”运算。 For the properties that are not true, though, they need to exist as ANDs. 但是,对于不正确的属性,它们需要以AND的形式存在。

I'm sure this is something very basic but I'm just failing to see the simple solution. 我敢肯定这是非常基本的东西,但是我只是看不到简单的解决方案。 Specifically, I cannot figure out how to progressively add the OR clauses. 具体来说,我无法弄清楚如何逐步添加OR子句。

Edit: 编辑:

To clarify my logic, I'll explain what I'm trying to make happen. 为了阐明我的逻辑,我将解释我试图实现的目标。 I'm trying to write a filter query that would allow me to ask the database, "show me all Foos where either A is true, or B is true and C is not true". 我正在尝试编写一个过滤器查询,该查询将允许我询问数据库,“向我展示所有Foos,其中A为true或B为true且C为非true”。 Or maybe the query would need to ask, "show me all Foos where C is true and A and B are not true". 或者,查询可能需要询问“向我展示所有Foos,其中C是真实的,而A和B不是真实的”。

This is a query to be used as part of an ASP.NET action method, filtering based on some check boxes. 这是一个查询,将用作ASP.NET操作方法的一部分,并基于某些复选框进行过滤。 So, the action method knows whether A, B or C need to be filtered as true or false, I just need to write a LINQ expression that builds this query. 因此,该操作方法知道A,B或C是否需要过滤为true或false,我只需要编写一个构建此查询的LINQ表达式即可。

LINQ与SQL几乎相同:

foos.Where(n => n.A == false && (n.B == true || n.C == true))
var result = foos.Where(x => !x.A && (x.B || a.C)).ToList();

If A is true, it needs to become part of that OR expression, otherwise it needs to be part of the AND expression 如果A为true,则它必须成为该OR表达式的一部分,否则它必须成为AND表达式的一部分。

You can use an ? 您可以使用 operator. 操作员。

var result = foos.Where (x => x.A ? x.B && x.C : x.B || x.C);

So if xA == true statement will be xB && xC , or xB || xC 因此,如果xA == true语句将为xB && xCxB || xC xB || xC otherwise xB || xC否则

I disagree with buffjape. 我不同意buffjape。 In your case I would progressively add Where clauses. 在您的情况下,我将逐步添加Where子句。 I would do something like the following: 我将执行以下操作:

//start with the full set
var results = DbSet<Foo>();

//then build the where clause using conditional logic based on which checkboxes are checked

if(aCheckBoxIsChecked)
{
    results = results.Where(foo => foo.A == true); //each where you add is effectively an and
}

if(bCheckBoxIsChecked)
{
    results = results.Where(foo => foo.B == true);
}

... //and keep on with as many checkboxes as you have


if(aCheckBoxIsChecked && cCheckBoxIsChecked)
{
    results = results.Where(foo => foo.B != true);
}
else if(!aCheckBoxIsChecked)
{
    results = results.Where(foo => foo.B == true || foo.C == true);
}
else if(...) //any other clauses
{
    ... //any other logic
}

... //any other tests

/* The key insight, is that Linq will not execute your query until 
you try to access the results. Therefore, you can continue to build
an arbitrarily complex query until you've finished it, and then you
can execute it, as in the below line. */

return results.ToList(); //Execute. Or whatever method you want to use to execute the query.

So by incrementally building our your clauses you have complete flexibility to build arbitrary Linq Where clauses. 因此,通过逐步构建您的子句,您可以完全灵活地构建任意的Linq Where子句。

Like I said, I disagree with the assertion that progressively building your where clause is bad. 就像我说过的那样,我不同意逐步构建where子句不好的说法。 Yes, you have to be careful, but it is a technique that gives you great flexibility when your where clause is driven by many different parameters. 是的,您必须要小心,但是当您的where子句由许多不同的参数来驱动时,这项技术可以为您提供极大的灵活性。

Trying to progressively add WHERE clauses is a classic Linq mistake: 尝试逐步添加WHERE子句是一个典型的Linq错误:

  var results = foos.Where(n => n.A == false)
                    .Where(n => n.B == true);

  // Bug: testing C == true, but this ignores A
  results = results.Union(foos.Where(n => n.C == true));

Instead, always use one where clause: 相反,请始终使用一个where子句:

  results = foos.Where(n => n.A == false && (n.B == true || n.C == true));

If the expression gets too large for one line, switch to query syntax: 如果表达式对于一行来说太大,请切换到查询语法:

  results = (from n in foos
             where (n.A == false)
                && (n.B == true || n.C == true)
             select n
            );

As a last resort, if the Where clause gets unreasonably long, use a sql stored procedure instead. 作为最后的选择,如果Where子句过长,请改用sql存储过程。

SELECT *
FROM foo
WHERE a = false AND (b = true OR c = true)

would be 将会

foos.Where(x=>!x.a && (x.b || x.c));

alternatively you could do this as well: 或者,您也可以这样做:

foos
  .Where(x=>!x.a)
  .Where(x=>x.b || x.c);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM