使用 搜索查询.包含 () 用于组合两列的参数

本文关键字:两列 参数 用于 搜索 查询 包含 使用 组合 | 更新日期: 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()如何工作,我需要在查询中更改哪些内容才能使其按预期工作?

使用 搜索查询.包含 () 用于组合两列的参数

与其开始玩andorStartsWithEndsWith等的组合,不如让我们分析一下主要问题:

使用.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如何工作

假设您的FirstNameLastNamestring类型,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

我假设您可能想要的最自然的"搜索",即

  1. 添加为关键字的项目越多,获得的项目就越少("John"TheSearchParameter应该比"John Smith"返回更多的结果)。
  2. 顺序无关紧要。
  3. 需要完全匹配(因为您处理名称)

因此,通过输入"约翰",您想要返回:

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();
  1. 您需要找到所有相关的匹配项

    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将包含要搜索的单词。

现在,让我们检查一下查询将如何处理不同的输入。

情况 1TheSearchParameter= 'John' - 会给你预期的结果,因为c.FirstName.Contains(TheSearchParameter)的计算结果是true

情况 2TheSearchParameter= '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();
  1. 如果我们假设名字是由名字和姓氏组成的只是,并且您的数据中没有中间名。用户全名 =名字+姓氏。也许您可以尝试以下代码:

    var TheQuery = (from c in MyDC.Contacts
                where (c.FirstName + " " + c.LastName).Contains(TheSearchParameter)
                select c.ColumnID).Distinct().ToList();
    
  2. 我们在TheSearchParameter中检查FirstNameLastName

    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