Использование contains() в LINQ to SQL
Я пытаюсь реализовать очень простой поиск по ключевым словам в приложении, используя 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;
}
Как я могу переписать этот запрос так, чтобы он сделал то, что мне нужно?
Ответы
Ответ 1
Глядя на другие попытки, опечаляет меня: (
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" }
Ответ 2
Более простое и правильное решение (тогда 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>%';
Также обратите внимание на StartsWith
и EndsWith
, которые похожи на Contains
, но найдите строку в определенном месте.
query.Contains(partName)
совпадает с командой SQL in
. Полученный SQL будет эквивалентен (где < query0 > - значение query[0]
, < query1 > - это значение query[1]
, а <queryN> - последнее значение в массиве запросов):
select * from Parts where partName in ( <query0>, <query1>, ..., <queryN> );
Update:
Также важно отметить, что ответ leppie не избегает символов подстановочных знаков, прежде чем добавлять их в как выражение. Это не проблема с решением 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 убежит в этом, вам.
Ответ 3
Вы можете попробовать:
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.
Ответ 4
Вы можете записать это как
var result = db.Parts.Where(p => query.All(q => p.partName.Contains(q)));
Ответ 5
С помощью 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);
Или выполните 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);
Надеюсь, это поможет будущим посетителям.
Ответ 6
Я чувствую, что это несколько просто и работает для меня:
string[] product = products.Split(',');
using (var context = new ProjectTrackerEntities())
{ var result = from part in context.DBAudits where product.Contains(part.TableName) select part; }
Ответ 7
попробуйте следующее:
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;
}