2

(编辑:我问错了问题。我遇到的真正问题是Compose LINQ-to-SQL predicates into a single predicates - 但是这个得到了一些很好的答案,所以我把它留下了!)

给定以下搜索文本:

"keyword1 keyword2 keyword3   ... keywordN"

我想以以下 SQL 结束:

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

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

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

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

但我想处理任意搜索词列表。我做到了

Func<Customer, bool> predicate = /* predicate */;
foreach(var token in tokens) {
    predicate = (customer 
        => predicate(customer) 
        && 
         (customer.Forenames.Contains(token) || customer.Surname.Contains(token));
}

这会产生一个 StackOverflowException - 大概是因为分配的 RHS 上的 predicate() 直到运行时才真正被评估,此时它最终会调用自己......或其他东西。

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

4

2 回答 2

3

我会建议另一种技术

你可以做:

var query = dataContext.Customers;

然后,在一个循环内做

foreach(string keyword in keywordlist)
{
    query = query.Where(Customer.Forenames.Contains(keyword) || Customer.Surname.Contains(keyword));
}
于 2010-09-23T21:58:52.803 回答
1

如果您想要一种更简洁和声明式的编写方式,您还可以使用Aggregate扩展方法而不是foreach循环和可变变量:

var query = keywordlist.Aggregate(dataContext.Customers, (q, keyword) => 
    q.Where(Customer.Forenames.Contains(keyword) || 
            Customer.Surname.Contains(keyword)); 

This takes dataContext.Customers as the initial state and then updates this state (query) for every keyword in the list using the given aggregation function (which just calls Where as Gnomo suggests.

于 2010-09-23T22:12:24.170 回答