Использование contains () в LINQ to SQL - PullRequest
38 голосов
/ 03 марта 2010

Я пытаюсь реализовать очень простой поиск по ключевым словам в приложении, используя 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;
}

Как мне переписать этот запрос, чтобы он делал то, что мне нужно?

Ответы [ 7 ]

42 голосов
/ 03 марта 2010

Глядя на другие попытки меня огорчает: (

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"}

19 голосов
/ 29 февраля 2012

Более простое и правильное решение (чем у Леппи):

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):

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

Также следует отметить StartsWith и EndsWith, которые похожи на Contains, но ищут строку в определенном месте. 1031 *

query.Contains(partName) аналогичен команде SQL in. Результирующий SQL будет эквивалентен (где - значение query[0], - значение query[1], а - последнее значение в массиве запросов):

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

Обновление:
Также важно отметить, что ответ Леппи не экранирует символы подстановки перед добавлением их в оператор like . Это не проблема с решением Contains, так как Linq будет избегать запроса перед его отправкой. Экранированная версия решения SqlMethods.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 избежит этого за вас.

2 голосов
/ 03 марта 2010

Вы можете попробовать:

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 s в предложении where.

1 голос
/ 13 февраля 2014

Использование пакета nuget NinjaNye.SearchExtension позволяет легко выполнять поиск:

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

Или выполните RankedSearch, которое возвращает 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

Надеюсь, что это поможет будущим посетителям

1 голос
/ 03 марта 2010

Вы можете написать это как

var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));
0 голосов
/ 17 декабря 2012

Я чувствую, что это несколько просто и работает для меня:

string[] product = products.Split(','); 
using (var context = new ProjectTrackerEntities()) 
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }
0 голосов
/ 03 марта 2010

пожалуйста, попробуйте это:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...