43

我正在尝试使用 linq-to-sql 在应用程序中实现一个非常基本的关键字搜索。我的搜索词在一个字符串数组中,每个数组项都是一个单词,我想找到包含搜索词的行。我不介意它们是否包含不仅仅是搜索词(很可能,它们会),但所有搜索词都必须存在。

理想情况下,我想要类似于下面的代码片段,但我知道这行不通。另外,我在这里查看了这个问题,但该问题的作者似乎满足于以相反的方式做事(query.Contains(part.partName)),这对我不起作用。

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where part.partName.Contains(query)
           select part;
}

我怎样才能重写这个查询,以便它可以满足我的需要?

4

7 回答 7

45

看着其他的尝试让我很难过:(

public IQueryable<Part> SearchForParts(string[] query)
{
  var q = db.Parts.AsQueryable(); 

  foreach (var qs in query)
  { 
    var likestr = string.Format("%{0}%", qs);
    q = q.Where(x => SqlMethods.Like(x.partName, likestr));
  }

  return q;
}

假设:

  • partName 看起来像:“ABC 123 XYZ”

  • 查询是 { "ABC", "123", "XY" }

于 2010-03-03T06:21:30.097 回答
22

一个更简单、更正确的解决方案(然后是 leppie's):

public IQueryable<Part> SearchForParts(string[] query)
{
    var q = db.Parts.AsQueryable(); 

    foreach (string qs in query)
    {
        q = q.Where(x => x.partName.Contains(qs));
    }

    return q;
}

只要partName是字符串(或字符串的 SQL 等效项),这将起作用。

需要注意的重要一点partName.Contains(qs)是不同于query.Contains(partName).
使用partName.Contains(qs),partName搜索任何出现的qs. 生成的 SQL 将是等效的(其中 <qs> 是 的值qs):

select * from Parts where partName like '%<qs>%';

还要注意的是StartsWithEndsWith类似于Contains但在特定位置查找字符串。

query.Contains(partName)与 SQLin命令相同。生成的 SQL 将等效于(其中 <query0> 是 的值query[0],<query1> 是 的值query[1],<queryN> 是查询数组中的最后一个值):

select * from Parts where partName in ( <query0>, <query1>, ..., <queryN> );

更新:同样重要的是要注意,leppie 的答案在将通配符添加到like语句
之前不会转义它们。这不是解决方案的问题,因为 Linq 将在发送查询之前对其进行转义。解决方案的转义版本是:ContainsSqlMethods.Like

public IQueryable<Part> SearchForParts(string[] query)
{
    var q = db.Parts.AsQueryable(); 

    foreach (var qs in query)
    {
        string escaped_bs = qs.Replace("/", "//"),
            escaped_us = escaped_bs.Replace("_", "/_"),
            escaped_p = escaped_us.Replace("%", "/%"),
            escaped_br = escaped_p.Replace("[", "/["),
            likestr = string.Format("%{0}%", escaped_br);

        q = q.Where(x => SqlMethods.Like(x.partName, likestr, '/'));
    }

    return q;
}

您不必担心 ' 因为 Linq 会为您避免这种情况。

于 2012-02-29T03:56:03.547 回答
1

你可以试试:

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where query.All(term => part.partName.Contains(term))
           select part;
}

但是,我不确定 LINQ to SQL 是否能够将其转换为 T-SQL。另一种选择是:

public IQueryable<Part> SearchForParts(string[] query)
{
    var result = from part in db.Parts
                 select part;

    foreach(var term in query)
    {
        result = from part in result
                 where part.partName.Contains(term)
                 select part;
    }

    return result;
}

它不是那么漂亮,但它应该可以工作。AND你会在 where 子句中得到一个包含很多 s 的查询。

于 2010-03-03T05:50:32.873 回答
1

你可以这样写

var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));
于 2010-03-03T06:05:51.050 回答
1

使用NinjaNye.SearchExtension nuget 包可以让您轻松执行此搜索:

string[] terms = new[]{"search", "term", "collection"};
var result = db.Parts.Search(terms, p => p.PartName);

您还可以搜索多个字符串属性

var result = db.Parts.Search(terms, p => p.PartName, p.PartDescription);

或者执行一个RankedSearchwhich 返回IQueryable<IRanked<T>>,它只包含一个显示搜索词出现次数的属性:

//Perform search and rank results by the most hits
var result = db.Parts.RankedSearch(terms, p => p.PartName, p.PartDescription)
                     .OrderByDescending(r = r.Hits);

项目 GitHub 页面上有更广泛的指南:https ://github.com/ninjanye/SearchExtensions

希望这对未来的访客有所帮助

于 2014-02-13T09:01:34.427 回答
0

我觉得这有点简单,对我有用:

string[] product = products.Split(','); 
using (var context = new ProjectTrackerEntities()) 
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }
于 2012-12-17T17:34:28.870 回答
-3

请试试这个:

public IQueryable<Part> SearchForParts(string[] query)
{
    return from part in db.Parts
           where Search(part.Name,query)
           select part;
}

public bool Search(string partName,string[] query)
{
    for (int i = 0; i < query.Length; i++)
    {
        if(partName.Contains(query[i]))
           return true;
    }

    return false;
}
于 2010-03-03T06:10:49.900 回答