有没有办法从 EF 中的字符串值数组动态生成多个喜欢?
Is there a way to have multiple likes generated dynamically from an array of string values in EF?
我设置了一个搜索文本框,搜索将单独抓取每个单词并使用包含搜索一个字段。
有没有办法通过 Contains 搜索字符串数组?
//Keep in mind that the array would be generated dynamically through textbox
string[] searchWords = { "hello", "world", "today" };
var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => a.Title.Contains(searchWords));
searchWords 显然不起作用,但试图展示我想要实现的目标。 searchWords[0] 有效,因为它只是一个词。
我也按照其他链接中的建议进行了尝试,但现在当我 运行 调试器或分析器时,WHERE 子句不会出现在查询中:
`var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => searchWords.Any(w => a.Title.Contains(w)));
`
似乎 Entity Framework Core 没有将上述查询中带有 .Contains
的 .Any
和 .All
转换为 SQL 语句。相反,它会加载所有其他匹配的数据并在内存中进行搜索。
如果你想在标题中找到包含 所有 搜索词的文章,你可以动态添加 .Where
条件(我有一个包含人物和评论的测试数据库场):
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();
但是,如果您想查找包含 任何 个搜索词的文章,那么您需要在 .Where
子句中添加 OR
。
手动编写它看起来像这样:
.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 and this SearchExtension https://whosebug.com/a/31682364/5550687。但我没有尝试过它们,我不知道它们是否适用于 EF Core。
我设置了一个搜索文本框,搜索将单独抓取每个单词并使用包含搜索一个字段。
有没有办法通过 Contains 搜索字符串数组?
//Keep in mind that the array would be generated dynamically through textbox
string[] searchWords = { "hello", "world", "today" };
var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => a.Title.Contains(searchWords));
searchWords 显然不起作用,但试图展示我想要实现的目标。 searchWords[0] 有效,因为它只是一个词。
我也按照其他链接中的建议进行了尝试,但现在当我 运行 调试器或分析器时,WHERE 子句不会出现在查询中:
`var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => searchWords.Any(w => a.Title.Contains(w)));
`
似乎 Entity Framework Core 没有将上述查询中带有 .Contains
的 .Any
和 .All
转换为 SQL 语句。相反,它会加载所有其他匹配的数据并在内存中进行搜索。
如果你想在标题中找到包含 所有 搜索词的文章,你可以动态添加 .Where
条件(我有一个包含人物和评论的测试数据库场):
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();
但是,如果您想查找包含 任何 个搜索词的文章,那么您需要在 .Where
子句中添加 OR
。
手动编写它看起来像这样:
.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 and this SearchExtension https://whosebug.com/a/31682364/5550687。但我没有尝试过它们,我不知道它们是否适用于 EF Core。