该LINQ表达式无法被翻译。请将查询重写成可以翻译的形式。

5

从SQL表中,我正在尝试获取每个项目的最后一行。 我传递了一个用户列表(对象ID列表),想要获取他们每个人的最后一份工作。 以下是该函数。

   public async Task<List<Job>> GetLastJobs(List<int> objectIds)
    {
        using ManagerContext context = new ManagerContext(_callContext);
        List<Job> jobs = context.Jobs.Where(j => j.ObjectId.HasValue && objectIds.Contains(j.ObjectId.Value)).GroupBy(j => j.ObjectId).Select(j => j.OrderByDescending(p => p.Id).FirstOrDefault()).ToList();
        return null;
    }

在执行时,它返回:
the LINQ expression '(GroupByShaperExpression:
KeySelector: (j.ObjectId),
ElementSelector:(EntityShaperExpression: 
    EntityType: Job
    ValueBufferExpression: 
        (ProjectionBindingExpression: EmptyProjectionMember)
    IsNullable: False
)
)
    .OrderByDescending(p => p.Id)' could not be translated. 

要么改写查询语句使其可翻译,要么明确切换到客户端评估,插入以下任意一个调用:AsEnumerable()、AsAsyncEnumerable()、ToList()或ToListAsync()。有关更多信息,请参见https://go.microsoft.com/fwlink/?linkid=2101038

我不知道从哪里开始解决这个问题


我假设这是EF Core 3.x。不幸的是,在GroupBy处理方面它非常受限 - 他们计划在未来版本中进行改进。你可以在GroupBy之前加上AsEnumerable,理解这样做会拉取所有行。(PS:你可以使用First代替FirstOrDefault - 不可能存在空组。) - NetMage
1个回答

7
基本问题在于,SQL没有像LINQ的GroupBy那样强大的分组操作符。 SQL GROUP BY必须聚合所有非分组列,并且大多数RDBMS中没有FIRST()聚合函数。因此,您必须使用窗口函数编写此查询,而EF Core还没有解决这个问题。
也可以用替代方法编写此查询。
  var jobs = db.Jobs.Where(j => j.ObjectId.HasValue && objectIds.Contains(j.ObjectId.Value))
                    .Where(j => j.Id == db.Jobs.Where(j2 => j2.ObjectId == j.ObjectId).Max(j => j.Id))
                    .ToList();

这个短语的意思是

SELECT [j].[Id], [j].[ObjectId]
FROM [Jobs] AS [j]
WHERE ([j].[ObjectId] IS NOT NULL AND [j].[ObjectId] IN (1, 2, 3)) AND ([j].[Id] = (
    SELECT MAX([j0].[Id])
    FROM [Jobs] AS [j0]
    WHERE [j0].[ObjectId] = [j].[ObjectId]))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接