递归地(?)将LINQ谓词组合成单个谓词

递归地(?)将LINQ谓词组合成单个谓词,linq,linq-to-sql,recursion,functional-programming,composition,Linq,Linq To Sql,Recursion,Functional Programming,Composition,(编辑:我问错了问题。我真正的问题已经结束了-但这一个得到了一些好的答案,所以我把它忘了!) 给定以下搜索文本: "keyword1 keyword2 keyword3 ... keywordN" 我希望以以下SQL结束: SELECT [columns] FROM Customer WHERE (Customer.Forenames LIKE '%keyword1%' OR Customer.Surname LIKE '%keyword1%') AND (C

(编辑:我问错了问题。我真正的问题已经结束了-但这一个得到了一些好的答案,所以我把它忘了!)

给定以下搜索文本:

"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%')
实际上,我们在空格上拆分搜索文本,修剪每个标记,基于每个标记构造一个多部分或子句,然后将这些子句合并在一起

我是在LINQtoSQL中这样做的,我不知道如何基于任意长的子谓词列表动态组合谓词。对于已知数量的子句,手动组合谓词很容易:

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));
}
Func谓词=/*谓词*/;
foreach(令牌中的var令牌){
谓词=(客户)
=>谓词(客户)
&& 
(customer.Forenames.Contains(token)| customer.姓氏.Contains(token));
}
这会产生一个StackOverflowException——可能是因为赋值的RHS上的谓词()直到运行时才被实际计算,在运行时它会调用自己……或者其他什么


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

我建议使用另一种技术

你可以做:

var query = dataContext.Customers;
然后,在一个周期内

foreach(string keyword in keywordlist)
{
    query = query.Where(Customer.Forenames.Contains(keyword) || Customer.Surname.Contains(keyword));
}

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

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

这将
dataContext.Customers
作为初始状态,然后使用给定的聚合函数(正如Gnomo所建议的,它只调用
Where
)为列表中的每个关键字更新此状态(查询)。

@KennyTM-我不确定我是否理解你的意思……你能详细说明一下(请)?当然……当你这样说的时候,它看起来很简单:)太棒了。谢谢。哦。我问错了问题。看看我真正想要达到的目标。哦。