如何解决如何有效重写无法在EFCore 3.1中转换的LINQ表达式'DbSet.Where... Any...'?
我一直在解决臭名昭著的Entity Framework Core3升级breaking changes所带来的问题。我曾经有一个工作正常的查询,如下所示:
// Assume someOtherList is a list populated here
var existingItemsList = myDbSet
.Where(s => someOtherList.Any(i => s.Name == i.Name && s.Id == i.RefId))
.Select(s => s.Id)
.ToList();
但是现在抛出:
System.InvalidOperationException: The LINQ expression 'DbSet<MyItem>
.Where(i => __someOtherList_0
.Any(i => i.Name == i.Name && i.Id == i.RefId))' could not be translated.
Either rewrite the query in a form that can be translated,or switch to
client evaluation explicitly by inserting a call to either
AsEnumerable(),AsAsyncEnumerable(),ToList(),or ToListAsync().
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
我该如何重新编写LINQ查询以确保其效率(即不要在过滤器之前将所有数据下载到客户端)?
PS:事实证明,我忽略了类似行的多次使用,OP中包含的以下语句是不正确的:为了尝试忽略性能问题,我尝试在 AsEnumerable()
之前和之后插入{ Where()
语句;但是完全相同的错误并没有消失。
解决方法
使用[https://github.com/scottksmith95/LINQKit],您可以创建扩展方法,以添加用于处理Where
(List
。Any
或{{1} }。List
)条件,假设您的All
足够短。这些将测试扩展为一系列List
或&&
在一起的测试。
这是我的||
变体形式:
WhereAny
(也有类似的// searchTerms - IEnumerable<TSearch> where one must match for a row
// 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,TSearch>(this IQueryable<T> dbq,IEnumerable<TSearch> searchTerms,Expression<Func<T,TSearch,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());
}
// could be return dbq.Where(searchTerms.AnyIs(testFne));
// testFne(row,searchTerm) - test one of searchTerms against a row
// searchTerms - IEnumerable<TKey> where one must match for a row
// dbq.Where(r => searchTerms.Any(s => testFne(r,bool>> testFne,IEnumerable<TSearch> searchTerms) =>
dbq.WhereAny(searchTerms,testFne);
// testFne(row,searchTerm) - test one of searchTerms against a row
// searchTerms - TSearch[] where one must match for a row
// dbq.Where(r => searchTerms.Any(s => testFne(r,params TSearch[] searchTerms) {
var pred = PredicateBuilder.New<T>();
foreach (var s in searchTerms)
pred = pred.Or(r => testFne.Invoke(r,bool>>)pred.Expand());
}
变体和WhereAll
变体,以及一组OrderBy
。)
有了这些,你可以写
IEnumerable
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。