(编辑:我问了一个错误的问题。我遇到的真正的问题已经结束了Compose LINQ-to-SQL predicates into a single predicate - 但这个问题得到了一些很好的答案,所以我把它留了下来!)
给出以下搜索文本:
"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子句,然后将这些子句一起进行AND运算。
我在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上的谓词()实际上直到运行时才被评估,此时它最终会调用自身......或者其他东西。
简而言之,我需要一种技术,给定两个谓词,将返回使用提供的运算符组成两个源谓词的单个谓词,但仅限于Linq-to-SQL明确支持的运算符。有什么想法吗?
答案 0 :(得分:3)
我会建议另一种技术
你可以这样做:
var query = dataContext.Customers;
然后,在一个循环内做
foreach(string keyword in keywordlist)
{
query = query.Where(Customer.Forenames.Contains(keyword) || Customer.Surname.Contains(keyword));
}
答案 1 :(得分:1)
如果你想要一种更简洁和声明的方式来编写它,你也可以使用Aggregate
扩展方法而不是foreach
循环和可变变量:
var query = keywordlist.Aggregate(dataContext.Customers, (q, keyword) =>
q.Where(Customer.Forenames.Contains(keyword) ||
Customer.Surname.Contains(keyword));
这将dataContext.Customers
作为初始状态,然后使用给定的聚合函数(如Gnomo建议的那样调用Where
)为列表中的每个关键字更新此状态(查询)。