我正在尝试构建一个通用查询构建器来接受用户输入的搜索词。为了获得我需要的 where 子句,我必须解析术语并独立确定需要包含在子句中的字段。
请注意,此示例已大大简化以说明这一点。我知道在这种特殊情况下,整个结果可以表示为单个 Where() 语句。这段代码将在我的问题空间中工作(单个 Where() 语句不起作用),所以答案必须解决这里实际发生的事情,而不是如何使它更简单。
我从一个术语列表开始(这里表示为一个字符串 [],但最终将是一个更复杂类型的 IList,有助于指导查询构建器):
string[] terms = new string[] {
"hope",
"bob",
};
第一个示例(如下)给出了正确的结果集(在三个搜索字段中的任何一个中具有“bob”的员工并且在三个匹配字段中的任何一个中都具有“hope”的任何记录)。这确实表明在链接 Where() 子句时从代码构建了正确的查询:
var query0 = Sites.Where(s => s.SiteId < 200);
query0 = query0.Where(s =>
s.Employee.FirstName.Contains(terms[0]) ||
s.Employee.LastName.Contains(terms[0]) ||
s.Employee.Username.Contains(terms[0]));
query0 = query0.Where(s =>
s.Employee.FirstName.Contains(terms[1]) ||
s.Employee.LastName.Contains(terms[1]) ||
s.Employee.Username.Contains(terms[1]));
query0.Dump();
(请注意,我不能使用这种直接方法,因为我不知道会有多少术语,其中一些将在 Employee 上,而另一些将在“站点”的其他字段上,所以在编译时我必须能够迭代并独特地对待每个术语。)
下一个示例(如下)是我想要做的,但它不尊重第一个术语,并且只匹配最后一个;无论“hope”是否出现在任何字段中,任何字段中包含“bob”的任何记录都包括在内:
var query1 = Sites.Where(s => s.SiteId < 200);
foreach (string term in terms)
{
query1 = query1.Where(s =>
s.Employee.FirstName.Contains(term) ||
s.Employee.LastName.Contains(term) ||
s.Employee.Username.Contains(term));
}
query1.Dump();
最后一个示例(如下)在到达 Dump() 指令时给出了“索引越界”错误:
var query2 = Sites.Where(s => s.SiteId < 200);
for (int i = 0; i < terms.Length; ++i)
{
query2 = query2.Where(s =>
s.Employee.FirstName.Contains(terms[i]) ||
s.Employee.LastName.Contains(terms[i]) ||
s.Employee.Username.Contains(terms[i]));
}
query2.Dump();
我认为 query2 是最有说服力的例子。就好像 LINQ 在构建整个查询之后尝试将变量绑定到 SQL 参数,并且它尝试对所有绑定使用 i==2 (这将是循环退出时 i 的值)。这也与我在 query1 中看到的结果一致。
有谁知道绑定是如何工作的以及我如何构建我的查询?