EF 核心 "Group By could not be translated and will be evaluated locally."

EF Core "Group By could not be translated and will be evaluated locally."

我是 运行 使用 Entity Framework Core 2.2.6 针对 Sql 服务器数据库的简单查询,但是 GroupBy 没有在服务器上执行,而是正在执行本地。

有没有我遗漏的东西会迫使群组进入服务器?

我尝试过的 2 种 EF 查询变体:

public class Holiday
{
    public int Id {get;set;}
    public DateTime Date {get;set;}
    public string Username {get;set;}
    public string Approver {get;set;}
}

//version 1
await _dbContext.Holidays
    .GroupBy(h => new { h.Date})
    .ToDictionaryAsync(x => x.Key.Date, x => x.Select(x1 => x1.Username).ToList());

//version 2
await _dbContext.Holidays
    .GroupBy(h => h.Date)
    .ToDictionaryAsync(x => x.Key, x => x.Select(x1 => x1.Username).ToList());

两种变体都会产生以下 SQL:

SELECT [h].[Id], [h].[Approver], [h].[Date], [h].[HolidayTypeId], [h].[OwningRequestId], [h].[HolidayStatusId], [h].[Username]
FROM [Holidays] AS [h]
ORDER BY [h].[Date]

产生警告:

警告警告:Microsoft.EntityFrameworkCore.Query[20500] LINQ 表达式 'GroupBy([h].Date, [h])' 无法翻译,将在本地求值。

来自评论的建议:

//group by string
await _dbContext.Holidays
     .GroupBy(h => h.Username)
     .ToDictionaryAsync(x => x.Key, x => x.Select(x1 => x1.Username).ToList());

//group by part of date
await _dbContext.Holidays
     .GroupBy(h => h.Date.Year)
     .ToDictionaryAsync(x => x.Key, x => x.Select(x1 => x1.Username).ToList());
--group by string
SELECT [h].[Id], [h].[Approver], [h].[Date], [h].[HolidayTypeId], [h].[OwningRequestId], [h].[HolidayStatusId], [h].[Username]
FROM [Holidays] AS [h]
ORDER BY [h].[Username]

--group by part of date
SELECT [h].[Id], [h].[Approver], [h].[Date], [h].[HolidayTypeId], [h].[OwningRequestId], [h].[HolidayStatusId], [h].[Username]
FROM [Holidays] AS [h]
ORDER BY DATEPART(year, [h].[Date])

因为没有SQL这样的查询。

像SQL一样思考。如果你想按日期组获取用户名,你需要这两个。

基本上:

await _dbContext.Holidays
    .GroupBy(h => new { h.Date, h.Username})
    .Select(g => new
        {
          g.Key.Date,
          g.Key.Username
        });

这将生成这样的 SQL 查询。

SELECT [h].[Date],[h].[Username]
FROM [Holidays] AS [h]
GROUP BY [h].[Date],[h].[Username]

之后,您可以根据需要使用数据来创建字典的结构。

问题是,当您尝试在数据库中分组时,您实际上没有办法在组内具体化值。您只能获得 SELECT 分组列或非分组列的聚合值(通过 SUM 等)。

例如:

SELECT [h].[Date], [h].[Username]
FROM [Holidays] AS [h]

此查询将生成结果集,其中每一行都有两列,日期和名称。

让我们尝试分组:

SELECT [h].[Date], [h].[Username]
FROM [Holidays] AS [h]
GROUP BY [h.Date]

这个 SQL 查询根本不会被评估,因为从 SQL 服务器的角度来看它是无效的。错误消息将是

Column 'Holidays.Username' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

综上所述,您可以按照@Ercan Tirman 的建议进行操作,或者加载所有用户名和日期并在内存中对它们进行分组:

var dateAndUsername = await _dbContext.Holidays
    .Select(x => new {x.Date, x.Username})
    .ToArrayAsync();

Dictionary<DateTime, List<string>> grouped = dateAndUsername
    .GroupBy(x => x.Date)
    .ToDictionary(x => x.Key, x => x.Select(y => y.Username).ToList());