访问第一个组元素时无法翻译 First() (Linq GroupBy)

Posted

技术标签:

【中文标题】访问第一个组元素时无法翻译 First() (Linq GroupBy)【英文标题】:First() could not be translated when accessing first group element (Linq GroupBy) 【发布时间】:2021-06-13 03:41:02 【问题描述】:

我正在使用带有 SQLite 的 EF Core 来存储一堆天气报告:

public class WeatherReport

    [Key]
    public string ReportId  get; set; 
    public float Temperature  get; set; 
    public DateTime ReportDate  get; set; 

在我的 API 控制器中,我像这样返回它们:

IEnumerable<Models.TemperatureGetDTO> weatherReports = await _db.WeatherReports
    .Select(g => new Models.TemperatureGetDTO 
        ReportDate = g.ReportDate,
        Temperature = g.Temperature
    )
    .ToListAsync();

return Ok(weatherReports);

返回以下 JSON 化数据:

"reportDate":"2021-03-13T23:56:14.0135403","temperature":22,
"reportDate":"2021-03-13T23:57:14.1441771","temperature":22,
"reportDate":"2021-03-13T23:58:14.2924322","temperature":22,
"reportDate":"2021-03-13T23:59:14.4499289","temperature":21.9,
"reportDate":"2021-03-14T00:00:14.651818","temperature":22,
"reportDate":"2021-03-14T00:01:14.7563863","temperature":22,
"reportDate":"2021-03-14T00:02:14.886777","temperature":22,
"reportDate":"2021-03-14T00:03:15.0797178","temperature":22,
"reportDate":"2021-03-14T00:04:15.2898459","temperature":22
...

但是,现在,我想按小时对温度进行分组,并获得每小时的第一份天气报告(分组)。我试过这样写查询:

var weatherReports = await _db.WeatherReports
    .GroupBy(w => w.ReportDate.Hour)
    .Select(g => new 
        Hour = g.Key,
        Temperature = g.OrderBy(w => w.ReportDate).First().Temperature
    )
    .ToListAsync();

然而,这会产生以下错误:

LINQ 表达式 'GroupByShaperExpression: KeySelector: CAST(strftime('%H', w.ReportDate)) AS INTEGER), ElementSelector:EntityShaperExpression:EntityType:WeatherReport ValueBufferExpression:ProjectionBindingExpression: EmptyProjectionMember IsNullable: False

.Select(s => s.Temperature) .First()' 无法翻译。任何一个 以可以翻译的形式重写查询,或切换到 通过插入对“AsEnumerable”的调用来显式评估客户端, “AsAsyncEnumerable”、“ToList”或“ToListAsync”。看 https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。

我在这里做错了什么?要从组中获取第一项,我不应该使用 First() 吗?

【问题讨论】:

【参考方案1】:

这意味着 EF 无法将表达式转换为 SQL 以便它可以在服务器端执行。在过去,EF 只会将所有数据下载到客户端并在那里进行数据操作,但现在的表达式不能被翻译会抛出异常。

在不可翻译的表达式之前强制下载数据,例如:

(await _db.WeatherReports.GroupBy(w => w.ReportDate.Hour).ToListAsnc())
  .Select(g => new 
    Hour = g.Key,
    Temperature = g.OrderBy(w => w.ReportDate).First().Temperature
  );

或者

(await _db.WeatherReports.ToListAsync())
  .GroupBy(w => w.ReportDate.Hour)
  .Select(g => new 
    Hour = g.Key,
    Temperature = g.OrderBy(w => w.ReportDate).First().Temperature
);

或者可能为此使用原始 SQL,因为它是一种相当高级的用法:

SELECT * FROM
(
  SELECT *, ROW_NUMBER() OVER(PARTITION BY strftime('%Y%m%d%H', ReportDate) ORDER BY ReportDate) rn
  FROM WeatherReports
) WHERE rn = 1

顺便说一句,如果表中的数据跨越一天以上,请注意仅按小时分组,就像您在 LINQ 中所做的那样;昨天1300小时的数据今天会污染1300..

【讨论】:

优秀的答案凯厄斯,谢谢!我重写了如下详述的查询,这与您的建议差不多(它无法在服务器端翻译)。 谢谢!见关于 groupby 的脚注;我突然想到它可能会导致奇怪的结果

以上是关于访问第一个组元素时无法翻译 First() (Linq GroupBy)的主要内容,如果未能解决你的问题,请参考以下文章

jquery如何获取ul中第一个li和最后一个li

过滤性选择器

jQuery选择器和遍历的总结

jquery怎么找到元素下面的第一个子元素

jQuery筛选选择器

jQuery选择器选择元素的方法完整篇