EF Core中GroupBy后使用First()/FirstOrDefault()查询报错求助
解决EF Core 5中LINQ GroupBy后排序子查询无法翻译的问题
你的报错原因是EF Core 5无法将GroupBy后对分组集合执行OrderByDescending再取首元素的操作翻译成SQL——LINQPad能运行是因为它默认做了客户端评估,但EF Core 5对这类复杂分组后的子查询翻译支持有限。
下面是两种可行的修正方案:
方案1:用窗口函数筛选每个用户的最新交易(推荐,效率更高)
利用SQL的ROW_NUMBER窗口函数,直接在数据库层面筛选出每个用户的最新交易记录,EF Core 5完全支持这种写法:
// 先筛选每个用户的最新交易 var latestTransactions = _db.Transactions .Select(t => new { t.CustomerId, t.Balance, t.CreatedOn, // 按用户分组,按创建时间倒序排,取每条记录的序号 RowNum = EF.Functions.RowNumber().Over( partitionBy: t.CustomerId, orderBy: t.CreatedOn descending) }) .Where(r => r.RowNum == 1); // 只保留每个用户的第一条(最新)交易 // 关联用户表并过滤余额大于0的记录 var q = from lt in latestTransactions join u in _db.Users on lt.CustomerId equals u.Id where lt.Balance > 0 select new { CustomerId = lt.CustomerId, CustomerFullName = u.FullName, Balance = lt.Balance }; var balances = q.ToList();
方案2:先获取每个用户的最新交易时间,再关联查询
如果不想用窗口函数,也可以先查询每个用户的最新交易时间,再通过时间关联找到对应的交易记录:
// 先获取每个用户的最新交易创建时间 var latestTransactionTimes = _db.Transactions .GroupBy(t => t.CustomerId) .Select(g => new { CustomerId = g.Key, LatestCreatedOn = g.Max(t => t.CreatedOn) }); // 关联交易表、用户表,找到对应最新时间的交易 var q = from t in _db.Transactions join ltt in latestTransactionTimes on new { t.CustomerId, t.CreatedOn } equals new { ltt.CustomerId, ltt.LatestCreatedOn } join u in _db.Users on t.CustomerId equals u.Id where t.Balance > 0 select new { CustomerId = t.CustomerId, CustomerFullName = u.FullName, Balance = t.Balance }; var balances = q.ToList();
原写法问题说明
原查询中,你在GroupBy后的分组集合上直接调用OrderByDescending再取首元素,EF Core 5无法将这种操作翻译成对应的SQL分组后排序逻辑。上面两种方案都是先在数据库层面完成“获取每个用户最新交易”的逻辑,避免了在分组集合上执行复杂操作,因此可以被EF Core正确翻译。
内容的提问来源于stack exchange,提问作者Moradof
相关产品推荐
相关产品推荐

