如何解决EF Core-无法查询list<string>
使用 Entity Framework Core 3.1.7
我在数据库中有一个包含产品的表。
public class Product
{
public int Id {get; set;}
public string Name {get; set;}
}
然后,我希望用户能够使用搜索字段在UI表中查找某些产品。 当查询出现时,我尝试执行以下操作:
var searchParameters = query.SearchParameters.ToLower().Split(' ',','+').Distinct();
var result = _context.Products
.Where(p => searchParameters.Any()
&& (searchParameters.Any(x => p.Name.ToLower().Contains(x)) //Version 1
).ToList();
或替代
searchParameters.Any(x => EF.Functions.Like(p.Name,"%" + x + "%")) //Version 2
但是我调整了一下看似简单的东西:
LINQ表达式'DbSet 哪里(p => __searchParameters_0 .Any(x => p.Name.ToLower()。Contains(x)))'无法翻译。以可以翻译的形式重写查询, 或通过插入来明确切换到客户评估 AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync()
我意识到.ToLower()
将会成为一个问题,因此我想为LIKE语句(不区分大小写)和SQL查询运行一个LIKE语句。但是即使如此,List<string>
仍未翻译。
解决方法
如果您愿意使用LINQKit(或模拟谓词构建器部分),则可以使用扩展方法将Any(
... Contains)
表达式扩展为“或”表达式:
public static class LinqKitExt { // using LINQKit
// keyFne - extract string key from row
// searchTerms - IEnumerable<string> where one must be contained by a row's key
// dbq.Where(r => searchTerms.Any(s => keyFne(r).Contains(s)))
public static IQueryable<T> WhereContainsAny<T>(this IQueryable<T> dbq,Expression<Func<T,string>> keyFne,IEnumerable<string> searchTerms) {
var pred = PredicateBuilder.New<T>();
foreach (var s in searchTerms)
pred = pred.Or(r => keyFne.Invoke(r).Contains(s));
return dbq.Where((Expression<Func<T,bool>>)pred.Expand());
}
}
(以及Where / OrderBy [Descending] Any / All Contains / StartsWith的51个其他变体。)
然后您可以像这样使用它
var result = _context.Products
.WhereContainsAny(r => r.Name,searchParameters)
.ToList();
PS寻求另一个答案,我意识到将测试传递给呼叫者可以消除大多数变化:
// searchTerms - IEnumerable<TKey> where all must be in a row's key
// testFne(row,searchTerm) - test one of searchTerms against a row
// dbq.Where(r => searchTerms.Any(s => testFne(r,s)))
public static IQueryable<T> WhereAny<T,TKey>(this IQueryable<T> dbq,IEnumerable<TKey> searchTerms,TKey,bool>> testFne) {
var pred = PredicateBuilder.New<T>();
foreach (var s in searchTerms)
pred = pred.Or(r => testFne.Invoke(r,s));
return dbq.Where((Expression<Func<T,bool>>)pred.Expand());
}
然后您只需致电:
var result = _context.Products
.WhereAny(searchParameters,(r,s) => r.Name.Contains(s))
.ToList();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。