.Net Core嵌套查询获取非被评审人员工列表方法错误修正
错误原因
原查询的核心问题是类型与逻辑不匹配:x.Id是单个Guid类型值,而_context.Reviwees.Select(x => x.EmployeeId)返回的是IQueryable<Guid>类型的ID集合,直接用!=比较单个值和集合没有合法的筛选逻辑,EF Core无法将其翻译为正确的SQL语句,因此无法返回预期结果。
正确嵌套查询实现
要查询不属于被评审人的员工列表,推荐使用!Any实现嵌套查询,EF Core会将其翻译为数据库端执行的NOT EXISTS嵌套SQL,查询性能最优,代码如下:
public async Task<List<EmployeeDto>> GetEmployeeListAsync() { var employeeList = await _context.Employees .Where(emp => !_context.Reviwees.Any(reviwee => reviwee.EmployeeId == emp.Id)) .Select(emp => new EmployeeDto { Id = emp.Id, FirstName = emp.FirstName }) .ToListAsync(); return employeeList; }
上述写法的执行逻辑:
- 外层查询遍历所有员工记录
- 内层嵌套查询针对当前遍历到的员工,检查
Reviwees表中是否存在EmployeeId对应当前员工ID的被评审人记录 - 取反后筛选出所有没有对应被评审人记录的员工,完全匹配需求
- 整个查询会在数据库端完成,不会把全量表数据加载到内存,执行效率高
可选NOT IN嵌套写法
如果习惯用集合包含判断的写法,也可以使用Contains实现NOT IN逻辑的嵌套查询,代码如下:
public async Task<List<EmployeeDto>> GetEmployeeListAsync() { var reviweeEmployeeIds = _context.Reviwees.Select(r => r.EmployeeId); var employeeList = await _context.Employees .Where(emp => !reviweeEmployeeIds.Contains(emp.Id)) .Select(emp => new EmployeeDto { Id = emp.Id, FirstName = emp.FirstName }) .ToListAsync(); return employeeList; }
注意:不要对
reviweeEmployeeIds提前调用ToList()、ToArray()等执行方法,否则会把所有被评审人ID先加载到应用内存中再做筛选,数据量较大时会出现明显的性能问题,保持上述写法即可让EF Core生成数据库端执行的嵌套子查询。
内容的提问来源于stack exchange,提问作者sami_neranjan
相关产品推荐
相关产品推荐

