EF Core中ToListAsync()带Where条件调用时抛出异常问题
解决EF Core异步查询中ToListAsync()抛出的IAsyncEnumerable类型不匹配异常
这个问题的核心原因是EF Core在异步查询上下文里,解析你Where子句中的表达式时,x.Child.Select(y => y.TypeId).Distinct()会被识别为返回IAsyncEnumerable<Guid>类型,而HashSet<Guid>的构造函数只接受IEnumerable<Guid>参数,两者类型不兼容,所以触发了这个异常。同步查询时EF用的是IEnumerable,所以不会有这个问题。
下面给你两种可行的解决方案:
方案一:用All+Count组合替代SetEquals实现集合完全匹配
既然你需要判断Parent的Child的TypeId去重后和传入的TypeIds完全相等,我们可以拆成两个逻辑条件:
- 传入的所有TypeId都能在当前Parent的Child集合中找到
- Parent的Child的TypeId去重后的数量和传入的TypeIds数量一致(避免Parent的Child有额外的TypeId)
修改后的代码如下:
public async Task<IEnumerable<Parent>> GetItems(List<Guid> TypeIds) { var typeIdHashSet = new HashSet<Guid>(TypeIds); var items = context.Parent .Include(x => x.Child) .Where(x => // 检查所有传入的TypeId都存在于当前Parent的Child中 typeIdHashSet.All(targetId => x.Child.Any(child => child.TypeId == targetId)) && // 检查Child的TypeId去重后数量和传入集合数量一致,确保没有额外的TypeId x.Child.Select(child => child.TypeId).Distinct().Count() == typeIdHashSet.Count); return await items.ToListAsync(); }
方案二:先加载Child数据到内存再过滤(不推荐大数据集)
如果你的数据集不大,也可以先把Parent和Child的数据异步加载到内存,再进行集合匹配判断,但这种方式会把符合Include条件的数据都拉到内存,性能不如方案一:
public async Task<IEnumerable<Parent>> GetItems(List<Guid> TypeIds) { var typeIdHashSet = new HashSet<Guid>(TypeIds); // 先异步加载所有带Child的Parent到内存 var allParents = await context.Parent.Include(x => x.Child).ToListAsync(); // 在内存中过滤符合条件的Parent return allParents.Where(x => new HashSet<Guid>(x.Child.Select(y => y.TypeId).Distinct()).SetEquals(typeIdHashSet)); }
优先推荐方案一,它能让EF Core将查询逻辑翻译成SQL在数据库端执行,性能更优。
内容的提问来源于stack exchange,提问作者Sethlans
相关产品推荐
相关产品推荐

