Linq to Entities中的动态where子句

10
我正在使用linq to entities(EF)。 我有一个构造函数,它接受4个字符串参数。根据哪个参数不是空的,我必须构建linq查询。我可以用if else语句来实现,但我还有另一个构造函数有10个参数,在这种情况下需要检查很多组合。
例子:
Constructor(p1,p2,p3,p4)
{
  var prod= from p in ctxt.products.expand("items\details")
            where p.x==p1 && p.xx==p2 && p.xxx==p3 && p.xxxx==p4
            select p;
}
在上面的where子句中,只有在参数不为null时才应进行条件检查。 也就是说, 如果p2为null,则where子句应该如下所示:
where p.x==p1 && p.xxx==p3 && p.xxxx==p4

如果p2和p3都是空,则

where p.x==p1 && p.xxxx==p4

有人可以告诉我如何处理这个问题吗?如果可能的话,你能给出样例代码吗?


可能是 https://dev59.com/xUfRa4cB1Zd3GeqP5wyA?rq=1 的重复问题。 - Michael Freidgeim
3个回答

11

Linq的DeferredExecution来拯救。只有在请求数据时,Linq查询才会被执行。

var prod = from p in ctxt.products.expand("items\details")
        select p;

if (p1 != null)
{
    prod = prod.Where(p => p.x == p1);
}

if (p2 != null)
{
    prod = prod.Where(p => p.xx == p2);
}

// Execute the query

var prodResult = prod.ToList();

如果我们这样做,将会在生产环境中加载大量数据,然后再取其子集。我们能否直接获取子集呢? - Deepak
3
在构建where子句之后才会执行查询。在上述代码中,查询一直构建到最后一行,然后才执行。您可以通过运行SQL分析器来检查这一点。 - amit_g
是的,你说得对。我可以使用你的代码,而且它完美地运行。 - Deepak
我们可以在这里使用异步吗? - HamedH
这里在AND条件中添加了p1和p2。有没有一种方法可以强制执行OR连接? - Afshar Mohebi

3
您可以根据需要链接方法:
 YourType(string p1, string p2, string p3, string p4)
 {
      var prod = ctxt.Products.Expand("items\details");

      if (!p1.IsNullOrWhiteSpace())
          prod = prod.Where(p => p.x == p1);
      if (!p2.IsNullOrWhiteSpace())
          prod = prod.Where(p => p.xx == p2);

      // ....

      // use "prod"
 }

生成的SQL语句应该与将它们全部放在单个语句中时相同。

1
如果我们这样做,我们将在生产环境中加载大量数据,然后再取其子集。我们能否直接获取子集?否则,我们将加载不必要的数据。 - Deepak
1
@Deepak 不会的。IQueryable 的好处在于它不会“加载数据” - LINQ 使用延迟执行,而且使用 EF 时,它将最终的“查询”转换为单个 SQL 语句。这将得到相同的结果。 - Reed Copsey
1
@Deepak 详细信息请参见:https://dev59.com/_XI-5IYBdhLWcg3w-92b#1578977 - Reed Copsey
这里在AND条件中添加了p1和p2。有没有一种方法可以强制执行OR连接? - Afshar Mohebi

3

你可以将查询拆分成多个部分,并利用延迟查询执行的优势:

public Constructor(int? p1, int? p2, int? p3, int? p4)
{
    var prod = ctxt.products.expand("items\details");

    if(p1 != null)
        prod = prod.Where(p.x == p1);

    if(p2 != null)
        prod = prod.Where(p.xx == p2);

    if(p3 != null)
        prod = prod.Where(p.xxx == p3);

    if(p4 != null)
        prod = prod.Where(p.xxxx == p4);
}

如果我们这样做,我们将在生产环境中加载大量数据,然后再对其进行子集处理。我们能否直接获取子集,否则我们将加载不必要的数据。 - Deepak
2
@Deepak - 你根本不需要加载任何数据。LINQ只有在实际使用数据时才执行查询。当查询执行时,你已经设置好了正确的where子句,只会加载你需要的数据。 - Justin Niessner
这里在AND条件中添加了p1和p2。有没有一种方法可以强制执行OR连接? - Afshar Mohebi

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