微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

我使用 EF Core 和 sqlite 来存储一堆天气报告:

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",{"reportDate":"2021-03-13T23:58:14.2924322",{"reportDate":"2021-03-13T23:59:14.4499289","temperature":21.9},{"reportDate":"2021-03-14T00:00:14.651818",{"reportDate":"2021-03-14T00:01:14.7563863",{"reportDate":"2021-03-14T00:02:14.886777",{"reportDate":"2021-03-14T00:03:15.0797178",{"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)) 作为整数),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() 吗?

解决方法

这意味着 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..

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。