含分组排序子查询的LINQ查询报错:DbSet<TabEmployee>()无法翻译的解决方法咨询
问题背景
我在实现业务逻辑时遇到了EF Core的LINQ翻译问题:需要先从TabEmployee按AspUserID分组,取每组Id最大的记录,再关联TabCompany获取对应公司信息。但原始代码抛出了翻译失败的错误,移除分组逻辑后就正常运行,必须保留分组取最新记录的逻辑。
原始代码:
var query1 = from m in _appContext.TabEmployee group m by m.AspUserID into g select g.OrderByDescending(p => p.Id).First(); var query2 = from q in query1 join c in _appContext.TabCompany on q.AspUserID equals c.AspUserID select c; var result = query2.ToList().AsQueryable();
错误信息:
'The LINQ expression 'DbSet
() 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 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.'
解决方案
方案1:用窗口函数(ROW_NUMBER)实现分组取最新记录
EF Core 3.0+支持窗口函数的翻译,这是最推荐的方式,整个查询会被翻译成SQL在数据库端执行,性能更好:
// 用ROW_NUMBER标记每组内的记录顺序,取序号为1的(即Id最大的) var query = from emp in _appContext.TabEmployee select new { Employee = emp, RowNumber = EF.Functions.RowNumber() .Over(PartitionBy: emp.AspUserID, OrderBy: emp.Id descending) } // 筛选出每组的第一条记录 into numberedEmp where numberedEmp.RowNumber == 1 // 关联公司表 join comp in _appContext.TabCompany on numberedEmp.Employee.AspUserID equals comp.AspUserID select comp; var result = query.ToList().AsQueryable();
方案2:子查询获取最大Id后关联
如果你的EF Core版本较低不支持窗口函数,可以用子查询先获取每个AspUserID对应的最大Id,再关联回员工表拿到完整记录,最后关联公司表:
// 先获取每个AspUserID对应的最大员工Id var maxEmployeeIds = from emp in _appContext.TabEmployee group emp by emp.AspUserID into g select new { AspUserID = g.Key, MaxEmployeeId = g.Max(e => e.Id) }; // 关联员工表拿到对应记录,再关联公司表 var query = from emp in _appContext.TabEmployee join maxId in maxEmployeeIds on new { emp.AspUserID, emp.Id } equals new { maxId.AspUserID, maxId.MaxEmployeeId } join comp in _appContext.TabCompany on emp.AspUserID equals comp.AspUserID select comp; var result = query.ToList().AsQueryable();
为什么原始代码报错?
原始代码中GroupBy之后直接调用OrderByDescending().First()的写法,EF Core无法将其翻译成合法的SQL——因为SQL的GROUP BY只能返回分组键和聚合函数结果,不能直接返回分组内的某一行完整记录。当你后续再用这个结果去关联数据库中的TabCompany表时,EF Core无法处理内存集合和数据库集合的混合关联,所以抛出了翻译错误。
内容的提问来源于stack exchange,提问作者ASP Developer

