使用 搜索查询.包含 () 用于组合两列的参数
本文关键字:两列 参数 用于 搜索 查询 包含 使用 组合 | 更新日期: 2023-09-27 18:36:52
我有一个包含名字和姓氏的表,以及一个看起来像这样的查询:
var TheQuery = (from c in MyDC.Contacts
where (c.FirstName.Contains(TheSearchParameter) ||
c.LastName.Contains(TheSearchParameter))
select c.ColumnID).Distinct().ToList();
如果用户搜索 John 或 Smith,则会返回记录,但如果用户搜索 John Smith,则不会返回任何记录。Contains()
如何工作,我需要在查询中更改哪些内容才能使其按预期工作?
与其开始玩and
、or
、StartsWith
、EndsWith
等的组合,不如让我们分析一下主要问题:
使用
.Contains()
搜索合并两列的参数的查询
所以一般的答案是:
where Combine(table.Column1, table.Column2).Contains(TheSearchParameter)
问题是Combine
函数是什么,对此没有通用的答案。
在您的特定情况下,看起来您想搜索一个Name
,该是FirstName
列和LastName
列的组合。
即使这种组合通常也没有定义(不同的语言有不同的名称规则),但假设您想到了最常见的名称组合器:
Name = "{FirstName} {LastName}"
那么查询很简单
var TheQuery = (from c in MyDC.Contacts
where (c.FirstName + " " + c.LastName).Contains(TheSearchParameter)
select c.ColumnID).Distinct().ToList();
例如,如果存在与名字的联系人:"约翰",姓氏:"史密斯",则上述查询将匹配"约翰","史密斯","约翰史密斯",但不匹配"史密斯约翰"。
可以考虑在 LINQ 表达式中添加StartsWith
方法。StartsWith 的工作方式类似于 SQL where Column LIKE 'Something%'
。您也可以添加EndsWith
以使您的搜索范围更广
var TheQuery = (from c in MyDC.Contacts
where (c.FirstName.Contains(TheSearchParameter) ||
c.FirstName.StartsWith(TheSearchParameter) ||
c.FirstName.EndsWith(TheSearchParameter) ||
c.LastName.StartsWith(TheSearchParameter) ||
c.LastName.EndsWith(TheSearchParameter) ||
c.LastName.Contains(TheSearchParameter))
select c.ColumnID).Distinct().ToList();
var TheQuery = (from c in MyDC.Contacts
where ((c.FirstName.Contains(TheSearchParameter) &&
c.LastName.Contains(TheSearchParameter)) ||
(c.FirstName.Contains(TheSearchParameter) ||
c.LastName.Contains(TheSearchParameter)))
select c.ColumnID).Distinct().ToList();
使用 ( condition && condition ) ||
将强制括号的内部为单个表达式,同时保留现有条件。
如果没有,请告诉我。希望这有帮助。
我目前的理解是您想跨列搜索单词。虽然我确定我还没有完全理解要求,但我想贡献以下想法。希望您能够将其变成一个完整的解决方案:
var words = searchQuery.Split(' ');
var query = (from c in MyDC.Contacts
select c);
//Force each word to occur.
foreach (var w in words)
query = query.Where(c => c.FN.Contains(w) || c.LN.Contains(w));
var TheQuery = (from c in query
select c.ColumnID).Distinct().ToList();
这引入了搜索所有单词的概念,而不是只搜索一个字符串。
如果要为名字和姓氏提供单独的逻辑,则可以有两个单词列表:一个用于 FN,一个用于 LN。
你去吧(我更喜欢使用 lambdas,但你不必这样做):
var results = MyDC.Contacts
.Where(c => string.Join(" ",c.FirstName,c.LastName).Contains(TheSearchParameter))
.Select(c => c.ColumnId)
.Distinct()
.ToList();
通过将 FirstName 和 LastName 组合成一个字符串,您可以节省一些比较。
编辑:更新了格式,因为很难在一行上遵循。
Contains
如何工作
假设您的FirstName
和LastName
是string
类型,Contains
将检查字符串的任何子字符串是否与您的TheSearchParameter
匹配
因此,如果c.FirstName
为以下任何一项,c.FirstName.Contains("John")
将匹配:
John
vbJohn
John123
vbJohn123
不过,它区分大小写,因此以下内容不匹配:
john
vbjohn
john123
vbjohn123
我需要在查询中更改什么才能使其按预期工作
假设您是否有以下名称列表:
John Bryant
John Bard
Smith Bard
John Smith
Ralla Smith
Smith John
Metajohn Rasmith
我假设您可能想要的最自然的"搜索",即
- 添加为关键字的项目越多,获得的项目就越少("John"
TheSearchParameter
应该比"John Smith"返回更多的结果)。 - 顺序无关紧要。
- 需要完全匹配(因为您处理名称)
因此,通过输入"约翰",您想要返回:
John Bryant
John Bard
John Smith
Smith John
并通过放置"史密斯"
Smith Bard
John Smith
Ralla Smith
Smith John
在放"约翰·史密斯"的同时
John Smith
Smith John
我建议您做的是使其不区分大小写并像这样检查它:
string TheSearchParameter = "John Smith";
TheSearchParameter = TheSearchParameter.ToLower(); //case insensitive
string[] pars = TheSearchParameter.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries); //to get all the pars
var TheQuery = (from c in MyDC.Contacts
let l = new List<string>() {c.FirstName.ToLower(), c.LastName.ToLower()}
where l.Except(pars).Count() <= l.Count - pars.Length
select c.ColumnID).Distinct().ToList();
这里的关键是
where l.Except(pars).Count() <= l.Count - pars.Length
通过它,您可以控制要视为真正匹配的匹配项数。您在SearchParameter
中使用的单词越多,您期望的l.Except
量就越少(因为名称中的单词必须在搜索参数中匹配)。
我认为每个人都在把简单的事情变得复杂。主要意图是获得与给定名称匹配的结果联系人。有两种情况,1.您需要找到完全匹配的。使用以下查询,
var TheQuery = (from c in MyDC.Contacts
where (TheSearchParameter.Split(' ').Any(s => c.FirstName.Contains(s)) ||
TheSearchParameter.Split(' ').Any(s => c.LastName.Contains(s)))
select c.ColumnID).Distinct().ToList();
您需要找到所有相关的匹配项
var TheQuery = (from c in MyDC.Contacts where (c.FirstName + " " + c.LastName == TheSearchParameter) select c.ColumnID).Distinct().ToList();
正如您所说,假设集合包含一条 FirstName 为 John
,LastName 为 Smith
的记录,还有另一条记录 FirstName='Sam',LastName 为 'SmithX'。而TheSearchParameter
将包含要搜索的单词。
现在,让我们检查一下查询将如何处理不同的输入。
情况 1:TheSearchParameter= 'John' - 会给你预期的结果,因为c.FirstName.Contains(TheSearchParameter)
的计算结果是true
情况 2:TheSearchParameter= 'Smith' - 会给你预期的结果,因为c.LastName.Contains(TheSearchParameter)
的计算结果是true
情况 3 : *搜索参数= 'Jo'*会给你预期的结果,因为c.FirstName.Contains(TheSearchParameter)
的计算结果是true
到目前为止,一切都很好;现在
情况 4 :
TheSearchParameter= 'John Smith' - 会给你 空结果集 由于没有包含John Smith
的名字或姓氏 但它是两者的组合。
在所有这些情况下,您可以做些什么来获得正确的结果:
由于TheSearchParameter
可能包括名字和/或姓氏,因此请在 TheSearchParameter
中执行搜索操作。因此,您的查询可能如下所示:
var TheQuery = (from c in MyDC.Contacts
where (TheSearchParameter.Contains(c.FirstName) ||
TheSearchParameter.Contains(c.LastName))
select c.ColumnID).Distinct().ToList();
现在,它为案例 1-3 给出相同的结果,并将给出两条记录("约翰·史密斯"和"山姆·史密斯" 即使姓氏不同。 因为TheSearchParameter.Contains(c.LastName)
是 评估为 true;现在我们必须解决这个问题;
所以事实是
如果输入是名字和姓氏的组合,我们必须确认该组合应以 FirstName
开头并以 LastName
结尾。所以我建议你使用这样的搜索机制。以下代码片段将帮助您做到这一点;
var TheQuery = (from c in MyDC.Contacts
where ((TheSearchParameter.Contains(c.FirstName) && TheSearchParameter.StartsWith(c.FirstName)) ||
(TheSearchParameter.Contains(c.LastName) && TheSearchParameter.EndsWith(c.FirstName)))
select c.ColumnID).Distinct().ToList();
-
如果我们假设名字是由名字和姓氏组成的只是,并且您的数据中没有中间名。用户全名 =名字+姓氏。也许您可以尝试以下代码:
var TheQuery = (from c in MyDC.Contacts where (c.FirstName + " " + c.LastName).Contains(TheSearchParameter) select c.ColumnID).Distinct().ToList();
-
我们在
TheSearchParameter
中检查FirstName
和LastName
:var TheQuery = (from c in MyDC.Contacts where (c.FirstName.Contains(TheSearchParameter) || c.LastName.Contains(TheSearchParameter) || TheSearchParameter.StartsWith(c.FirstName) || TheSearchParameter.EndsWith(c.LastName) ) select c.ColumnID).Distinct().ToList();
例如:
"Jhon Smith".EndsWith("Smith")
"Jhon Smith".StartsWith("Jhon")
当约翰或史密斯在Contacts
.
string[] parametersArray = null;
int parametersCount = 0;
if(!string.IsNullOrEmpty(TheSearchParameter))
{
parametersArray = TheSearchParameter.Split(new char[0],StringSplitOptions.RemoveEmptyEntries);
parametersCount = parametersArray.Length;
}
var TheQuery = (from c in MyDC.Contacts
where (parametersCount == 0 || (parametersCount > 0 && (parametersArray.Contains(c.FirstName) ||
parametersArray.Contains(c.LastName))))
select c.ColumnID).Distinct().ToList();
你试过这个吗?
var TheQuery = (from c in MyDC.Contacts
where (System.Threading.Thread.CurrentThread.CurrentCulture.CompareInfo.IndexOf(c.FirstName, TheSearchParameter, System.Globalization.CompareOptions.IgnoreCase) >= 0 ||
System.Threading.Thread.CurrentThread.CurrentCulture.CompareInfo.IndexOf(c.Lastname, TheSearchParameter, System.Globalization.CompareOptions.IgnoreCase) >= 0)
select c.ColumnID).Distinct().ToList();
美好的一天,请考虑我的方法
如果搜索全名,上述两个答案都不会返回,因为它们只使用名字和姓氏进行搜索
(例如:
John.Contains(John Smith) = false
Smith.Contains(John Smith) = false
John.StartsWith(John Smith) = false
Smith.StartsWith(John Smith) = false
John.EndsWith(John Smith) = false
Smith.EndsWith(John Smith) = false
)
var TheQuery = (from c in x where ((TheSearchParameter.Contains(c.FirstName)
&& TheSearchParameter.Contains(c.LastName)) ||
((c.FirstName.Contains(TheSearchParameter) ||
c.LastName.Contains(TheSearchParameter))))
select c.ColumnId).Distinct().ToList();
第一部分,TheSearchParameter.Contains(c.First/LastName)
将考虑搜索具有名字和姓氏部分的TheSearchParameter
第二部分将考虑搜索带有TheSearchParameter
的名字或姓氏
如果您搜索"约翰·史密斯"
并有约翰·史密斯、约翰·保罗和保罗·史密斯的记录
第一部分将返回 1 个结果:约翰·史密斯第二部分将返回 0
如果您搜索"约翰"
第一部分将返回 0 结果第二部分将回归:约翰·史密斯和约翰·保罗
如果您搜索"史密斯"
第一部分将返回 0第二部分将返回:John Smith 和 Paul Smith
我不太明白你为什么期望你的陈述有效。
string x = "abc" ;
string y = "abc def";
y.Contains(x); // returns true
x.Contains(y); // returns false