使用.Contains()搜索查询,以查找组合两列

时间:2016-03-01 00:35:01

标签: c# linq linq-to-sql

我有一个包含FirstName和LastName的表以及一个看起来像这样的查询:

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()如何工作以及我在查询中需要更改哪些内容才能按预期工作?

13 个答案:

答案 0 :(得分:4)

不要开始使用andorStartsWithEndsWith等组合,而是分析主要问题:

  

使用.Contains()搜索查询合并两列

的参数

所以一般的答案是:

where Combine(table.Column1, table.Column2).Contains(TheSearchParameter)

问题在于Combine函数是什么,并且没有一般答案。

在您的特定情况下,您希望搜索NameFirstNameLastName列的Name = "{FirstName} {LastName}"

即使这种组合通常没有定义(不同的语言有不同的名称规则),但假设您考虑到最常见的名称组合:

var TheQuery = (from c in MyDC.Contacts
                where (c.FirstName + " " + c.LastName).Contains(TheSearchParameter)
                select c.ColumnID).Distinct().ToList();

然后查询只是

NoReverseMatch at /

Reverse for 'thing_detail' with arguments '()' and keyword arguments '{u'slug': ''}' not found. 1 pattern(s) tried: ['things/(?P<slug>[-\\w]+)/$']

Request Method:     GET
Request URL:    http://localhost:8000/
Django Version:     1.8.4
Exception Type:     NoReverseMatch
Exception Value:    

Reverse for 'thing_detail' with arguments '()' and keyword arguments '{u'slug': ''}' not found. 1 pattern(s) tried: ['things/(?P<slug>[-\\w]+)/$']

Exception Location:     /usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py in _reverse_with_prefix, line 496
Python Executable:  /usr/bin/python
Python Version:     2.7.6
Python Path:    

['/home/shashank/development/hellowebapp/hellowebapp',
 '/usr/lib/python2.7',
 '/usr/lib/python2.7/plat-x86_64-linux-gnu',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages/PILcompat',
 '/usr/lib/python2.7/dist-packages/gtk-2.0',
 '/usr/lib/pymodules/python2.7',
 '/usr/lib/python2.7/dist-packages/ubuntu-sso-client']

Server time:    Sun, 13 Mar 2016 18:54:31 +0000

例如,如果联系 FirstName “John” LastName “Smith”,上述查询将匹配“John”“Smith”“John Smith”但< em>“史密斯约翰”。

答案 1 :(得分:1)

您可以考虑在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();

答案 2 :(得分:1)

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 ) ||将强制括号内部为单个表达式,同时保留现有条件。

如果没有,请告诉我。希望这会有所帮助。

答案 3 :(得分:1)

我目前的理解是,您希望跨列搜索单词。虽然我确信我还没有完全理解我想要提出以下想法的要求。希望你能够将它变成一个完整的解决方案:

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。

答案 4 :(得分: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();
    

答案 5 :(得分:1)

你去(我更喜欢使用lambdas,但你不必):

var results = MyDC.Contacts
  .Where(c => string.Join(" ",c.FirstName,c.LastName).Contains(TheSearchParameter))
  .Select(c => c.ColumnId)
  .Distinct()
  .ToList();

通过将FirstName和LastName组合成一个字符串,您可以节省几个比较。

修改:更新了格式,因为单行难以理解。

答案 6 :(得分:1)

  

Contains如何运作

假设您的FirstNameLastName属于string类型,Contains将检查字符串的任何子字符串是否与您的TheSearchParameter匹配

因此,如果c.FirstName.Contains("John")是以下任何一项,c.FirstName将匹配:

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. 需要完全匹配(因为您处理名称)
  4. 因此,通过输入“John”你想要返回:

    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(因为名称中的字词必须与搜索参数匹配)。

答案 7 :(得分:0)

美好的一天,请考虑我的方法

如果搜索全名,则上述两个答案都不会返回,因为他们只使用FirstName和LastName搜索

(例如: 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)将考虑使用第一个AND姓的部分搜索TheSearchParameter的第一部分

第二部分将考虑使用TheSearchParameter

搜索第一个或最后一个名字

如果你搜索约翰史密斯&#34;

并有约翰史密斯,约翰保罗和保罗史密斯的记录

第一部分将返回1个结果:John Smith 第二部分将返回0

如果您搜索&#34; John&#34;

第一部分将返回0结果 第二部分将回归:John Smith和John Paul

如果您搜索&#34; Smith&#34;

第一部分将返回0 第二部分将回归:约翰史密斯和保罗史密斯

谢谢!

答案 8 :(得分:0)

正如您所说,我们假设Collection包含FirstName为John且LastName为Smith的记录,还有另一条记录,其中FirstName =&#39; Sam&#39 ;和LastName为&#39; SmithX&#39;。 TheSearchParameter将包含要搜索的字词。

现在让我们来看看您的查询将如何处理不同的输入。

案例1: TheSearchParameter =&#39; John&#39; - 将为您提供自c.FirstName.Contains(TheSearchParameter)评估为true以来的预期结果

案例2: TheSearchParameter =&#39; Smith&#39; - 将为您提供自c.LastName.Contains(TheSearchParameter)评估为true以来的预期结果

案例3: * TheSearchParameter =&#39; Jo&#39; *会为您提供自c.FirstName.Contains(TheSearchParameter)评估为true后的预期结果

到目前为止一切都很好;现在

案例4: TheSearchParameter =&#39; John Smith&#39; - 将为您提供空结果集由于没有包含{{1的FirstName或LastName但它是两者的结合。

在所有这些情况下,您可以采取哪些措施来获得正确的结果:

由于John Smith可能包含firstName或LastName或Both,因此请在TheSearchParameter中执行搜索操作。所以您的查询可能看起来像:

TheSearchParameter

现在,它为案例1-3 提供相同的结果并且将给出两个记录(&#34; John Smith&#34;和#34; Sam Smith&#34;即使姓氏是不同的。因为var TheQuery = (from c in MyDC.Contacts where (TheSearchParameter.Contains(c.FirstName) || TheSearchParameter.Contains(c.LastName)) select c.ColumnID).Distinct().ToList(); 评估为真;现在我们必须对此进行排序;

所以事实是

如果输入是FirstName和LastName的组合,我们必须确认组合应该从TheSearchParameter.Contains(c.LastName)和EndsWith FirstName开始。所以我建议你使用这样的搜索机制。以下代码段将帮助您完成此操作;

LastName

答案 9 :(得分:0)

  1. 如果我们假设名称由名字和姓氏组成 只是,你的数据中没有中间名。用户全名= 名字+姓氏。也许您可以尝试以下代码:

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

    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进入时,Jhon Smith "Jhon Smith".StartsWith("Jhon")"Jhon Smith".EndsWith("Smith")是真的 Contacts

答案 10 :(得分:0)

        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();

答案 11 :(得分:0)

你试过这个吗?

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();

答案 12 :(得分:-1)

我不太明白为什么你期望你的陈述有效。

string x =  "abc" ;
string y = "abc def";

y.Contains(x); // returns true
x.Contains(y); // returns false