You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LINQ中GroupBy后执行操作无法被EF Core转换为SQL的问题

问题:EF Core无法转换LINQ查询,获取用户最高评分及全名失败

数据表结构

Schoolattempts表

AttemptIdUserIDRating
1115
2120

Aspnetusers表

UserIdFirstNameLastName
1......
2......

原LINQ代码

from attempts in (from q in Schoolattempts
            group q by q.UserId into g
            select g.OrderByDescending(c => c.Rating).First())
join users in Aspnetusers on attempts.UserId equals users.Id
select new
{
    FullName = users.LastName + " " + users.FirstName + " " + users.MiddleName,
    Rating = attempts.Rating
}

错误信息

InvalidOperationException: The LINQ expression 'DbSet<Schoolattempts>()
    .GroupBy(s => s.UserId)
    .Select(g => g
        .AsQueryable()
        .OrderByDescending(e => e.Rating)
        .First())
    .Join(
        inner: DbSet<Aspnetusers>(), 
        outerKeySelector: e0 => e0.UserId, 
        innerKeySelector: a => a.Id, 
        resultSelector: (e0, a) => new TransparentIdentifier<Schoolattempts, Aspnetusers>(
            Outer = e0, 
            Inner = a
        ))' 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'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

解决方案

EF Core对GroupBy后直接调用OrderByDescending().First()的转换支持有限,可通过以下方式改写查询:

方法一:先分组取最高评分再关联

先通过分组得到每个用户的最高评分,再关联用户表和对应的记录,避免直接在分组后取实体:

from user in Aspnetusers
join attempt in Schoolattempts on user.Id equals attempt.UserId
join maxRating in (
    from q in Schoolattempts
    group q by q.UserId into g
    select new { UserId = g.Key, MaxRating = g.Max(r => r.Rating) }
) on new { attempt.UserId, attempt.Rating } equals new { maxRating.UserId, maxRating.MaxRating }
select new
{
    FullName = user.LastName + " " + user.FirstName + " " + user.MiddleName,
    Rating = maxRating.MaxRating
}

方法二:使用窗口函数(EF Core 3.0+支持)

利用ROW_NUMBER()窗口函数为每个用户的评分排序,取排名第一的记录后关联用户表:

from attempt in (
    from q in Schoolattempts
    select new
    {
        q.UserId,
        q.Rating,
        RowNum = EF.Functions.RowNumber().Over(
            partitionBy: q.UserId,
            orderBy: q.Rating descending
        )
    }
)
where attempt.RowNum == 1
join user in Aspnetusers on attempt.UserId equals user.Id
select new
{
    FullName = user.LastName + " " + user.FirstName + " " + user.MiddleName,
    Rating = attempt.Rating
}

方法三:拆分分组与关联逻辑

先单独获取用户最高评分集合,再依次关联评分表和用户表:

var maxRatings = from q in Schoolattempts
                 group q by q.UserId into g
                 select new { UserId = g.Key, MaxRating = g.Max(r => r.Rating) };

var result = from mr in maxRatings
             join a in Schoolattempts on new { mr.UserId, mr.MaxRating } equals new { a.UserId, a.Rating }
             join u in Aspnetusers on mr.UserId equals u.Id
             select new
             {
                 FullName = u.LastName + " " + u.FirstName + " " + u.MiddleName,
                 Rating = mr.MaxRating
             };

内容的提问来源于stack exchange,提问作者Saidnazar Saidnazarov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:30:42