Похоже, что Entity Framework Core не переводит .Any
и .All
с .Contains
в приведенном выше запросе в операторы SQL.Вместо этого он загружает все остальные совпадающие данные и выполняет поиск в памяти.
Если вы хотите найти Статьи, которые содержат все поисковых слов в заголовке, вы можете динамически добавить .Where
условия (Iимел тестовую базу данных с персонами и полем «Комментарий»):
var query = (IQueryable<Person>)dbContext.Persons
.Include(p => p.TaxIdentificationNumber);
foreach (var searchWord in searchWords)
{
query = query.Where(p => p.Comment.Contains(searchWord));
}
var persons = query.ToList();
Но если вы хотите найти статьи, содержащие любой поисковых слов, тогда вам понадобится OR
в.Where
предложение.
Если написать это вручную, это будет выглядеть так:
.Where(p => p.Comment.Contains(searchWords[0]) || p.Comment.Contains(searchWords[1]))
Но вы можете динамически построить выражение:
Expression<Func<Person, bool>> e1 = p => p.Comment.Contains(searchWords[0]);
Expression<Func<Person, bool>> e2 = p => p.Comment.Contains(searchWords[1]);
Expression<Func<Person, bool>> e3 = p => p.Comment.Contains(searchWords[2]);
var orExpression1 = Expression.OrElse(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
var orExpression2 = Expression.OrElse(orExpression1, Expression.Invoke(e3, e1.Parameters[0]));
var finalExpression = Expression.Lambda<Func<Person, bool>>(orExpression2, e1.Parameters);
и использовать его следующим образом:это:
var persons = dbContext.Persons.Where(finalExpression).ToList();
как функция:
Expression<Func<Person, bool>> BuildOrSearchExpression(string[] searchWords)
{
// searchWords must not be null or empty
var expressions = searchWords.Select(s => (Expression<Func<Person, bool>>)(p => p.Comment.Contains(s))).ToList();
if (expressions.Count == 1) return expressions[0];
var orExpression = expressions.Skip(2).Aggregate(
Expression.OrElse(expressions[0].Body, Expression.Invoke(expressions[1], expressions[0].Parameters[0])),
(x, y) => Expression.OrElse(x, Expression.Invoke(y, expressions[0].Parameters[0])));
return Expression.Lambda<Func<Person, bool>>(orExpression, expressions[0].Parameters);
}
и использовать его
var persons = dbContext.Persons
.Include(p => p.TaxIdentificationNumber)
.Where(BuildOrSearchExpression(searchWords))
.ToList();
Если вы поменяете .OrElse
на .AndAlso
все поисковые словадолжен быть найден как с несколькими пунктами .where
.
Когда я провел какое-то исследование, я также наткнулся на PredicatedBuilder http://www.albahari.com/nutshell/predicatebuilder.aspx и это SearchExtension https://stackoverflow.com/a/31682364/5550687. Но я не пробовал их и не знаю, работают ли они с EF Core.