c# - 将 LINQ-to-SQL 谓词组合成单个谓词

标签 c# linq linq-to-sql functional-programming composition

(之前的一个问题 Recursively (?) compose LINQ predicates into a single predicate 与此类似,但实际上我问错了问题......那里的解决方案满足了所提出的问题,但实际上并不是我需要的。不过它们是不同的。诚实。)

给定以下搜索文本:

"keyword1 keyword2 ... keywordN"

我想以以下 SQL 结束:

SELECT [columns] FROM Customer 
  WHERE (
        Customer.Forenames LIKE '%keyword1%' 
        OR 
        Customer.Forenames LIKE '%keyword2%'
        OR
        ...
        OR
        Customer.Forenames LIKE '%keywordN%'
    ) AND (
        Customer.Surname LIKE '%keyword1%' 
        OR 
        Customer.Surname LIKE '%keyword2%'
        OR
        ....
        OR
        Customer.Surname LIKE '%keywordN%'
    )

实际上,我们在空格上拆分搜索文本,修剪每个标记,基于每个构建一个多部分 OR 子句,然后将这些子句连接在一起。

我在 Linq-to-SQL 中执行此操作,但我不知道如何根据任意长的子谓词列表动态组合谓词。对于已知数量的子句,很容易手动组合谓词:

dataContext.Customers.Where(
    ( 
      Customer.Forenames.Contains("keyword1") 
      ||
      Customer.Forenames.Contains("keyword2")
    ) && (
      Customer.Surname.Contains("keyword1") 
      ||
      Customer.Surname.Contains("keyword2")
    )
);

简而言之,我需要一种技术,在给定两个谓词的情况下,该技术将返回一个由两个源谓词与提供的运算符组成的单个谓词,但仅限于 Linq-to-SQL 明确支持的运算符。有什么想法吗?

最佳答案

您可以使用 PredicateBuilder

IQueryable<Customer> SearchCustomers (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Customer>();

  foreach (string keyword in keywords)
  {
    // Note that you *must* declare a variable inside the loop
    // otherwise all your lambdas end up referencing whatever
    // the value of "keyword" is when they're finally executed.
    string temp = keyword;
    predicate = predicate.Or (p => p.Forenames.Contains (temp));
  }
  return dataContext.Customers.Where (predicate);
}

(这实际上是 PredicateBuilder 页面中的示例,我只是根据您的情况对其进行了调整...)


编辑:

实际上我误解了你的问题,我上面的例子只涵盖了解决方案的一部分......下面的方法应该做你想要的:

IQueryable<Customer> SearchCustomers (string[] forenameKeyWords, string[] surnameKeywords)
{
    var predicate = PredicateBuilder.True<Customer>();

    var forenamePredicate = PredicateBuilder.False<Customer>();
    foreach (string keyword in forenameKeyWords)
    {
      string temp = keyword;
      forenamePredicate = forenamePredicate.Or (p => p.Forenames.Contains (temp));
    }
    predicate = PredicateBuilder.And(forenamePredicate);

    var surnamePredicate = PredicateBuilder.False<Customer>();
    foreach (string keyword in surnameKeyWords)
    {
      string temp = keyword;
      surnamePredicate = surnamePredicate.Or (p => p.Surnames.Contains (temp));
    }
    predicate = PredicateBuilder.And(surnamePredicate);

    return dataContext.Customers.Where(predicate);
}

你可以这样使用它:

var query = SearchCustomers(
    new[] { "keyword1", "keyword2" },
    new[] { "keyword3", "keyword4" });

foreach (var Customer in query)
{
    ...
}

关于c# - 将 LINQ-to-SQL 谓词组合成单个谓词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3782940/

相关文章:

c# - XNA 4.0 中 2d 光照着色器中的 alpha 问题

c# - 使用 LINQ 使用复合主键更新表

c# - LINQ:如何将元素列表追加到另一个列表中

c# - 如何在没有 lambda 的情况下使用 linq 扩展?

c# - 有没有更好的方法来编写这个 Frankenstein LINQ 查询,在子表中搜索值并按相关性对它们进行排序?

c# - 有没有办法在使用 .net Framework 4.8 在 Visual Studio 2022 中处理 Razor View 时实时预览我的 Web 项目

c# - 如何从网络服务返回响应

c# - 泛型内存管理

c# - Linq 中的 DataLayer 具有不同版本的数据模型

ASP.Net MVC 要求 vs ASP.Net? (托管问题,加上 LINQ-to-SQL 问题)