gpt4 book ai didi

c# - 在 IQueryable 中按小时分组

转载 作者:行者123 更新时间:2023-11-30 21:27:52 25 4
gpt4 key购买 nike

在我的项目中,我一直在 x 秒内从 SPS 接收一些数据。每隔 y 分钟,我都会将当前数据存档到数据库中,以便能够显示统计信息。

我收到的数据被放入模型中。像这样但要复杂得多:

public class Data
{
public DateTime ArchiveTime { get; set; }
public float TempC { get; set; }
public float CO2Percent { get; set; }
}

我有一个数据库存储库,它返回特定时间跨度内的所有条目。看这段代码:

// Context is my DbContext for a SQLite db and Data is the DbSet<Data> on that
IQueryable<Data> GetDataBetween(DateTime from, DateTime to) => Context.Data.Where(d => (d.ArchiveTime >= from && d.ArchiveTime <= to));

如您所见,这将返回一个 IQueryable,因此我想使用 linq to entities 功能。
我相信它被称为 linq to entities 但如果它不是,我的意思是将表达式树转换为 sql 或其他而不是仅仅在 C# 中执行它的功能。

由于数据库中每小时的条目数量无法确定,我想每小时只获取一个条目(第一个),这样我就可以在图表中显示它。

下面是一些日期时间的示例,可能会更好地显示我的意图:
注意:这些只是对象中包含的日期时间,我想要整个对象 - 而不仅仅是时间。

// say this is all the data I get between two times
2019-07-06 10:30:01 // I want
2019-07-06 10:40:09
2019-07-06 10:50:10
2019-07-06 11:00:13 // I want
2019-07-06 11:10:20
2019-07-06 11:20:22
2019-07-06 11:30:24
2019-07-06 11:40:32
2019-07-06 11:50:33
2019-07-06 12:00:35 // I want
2019-07-06 12:10:43
2019-07-06 12:20:45
2019-07-06 12:40:54
2019-07-06 12:50:56
2019-07-06 13:00:58 // I want
2019-07-06 13:11:06
2019-07-06 13:21:08
2019-07-06 13:31:09

我目前的做法是通过 IEnumerableGroupBy。看这段代码:

var now = DateTime.Now;
IQueryable<Data> dataLastWeek = repos.GetDataBetween(now.AddDays(-7), now);

IEnumerable<Data> onePerHour = dataLastWeek.AsEnumerable()
.GroupBy(d => new DateTime(d.ArchiveTime.Year, d.ArchiveTime.Month, d.ArchiveTime.Day, d.ArchiveTime.Hour, 0, 0))
.Select(g => g.First());

这很好用,但是因为它使用 IEnumerable 并创建对象,所以我没有得到 linq to entities 的优势,我认为这种方式肯定慢很多。

有什么方法可以重写此查询以在 SQLite 数据库上使用 IQueryable 吗?

编辑:我正在使用 .net core 3 preview6(最新预览)版本的 EF Core。也许有一个新功能可以实现我想要的:)

最佳答案

GroupBy 的关键部分可以通过避免 new DateTime(...) 并使用任何一种匿名类型来轻松翻译

.GroupBy(d => new { d.ArchiveTime.Date, d.ArchiveTime.Hour })

日期属性+AddHours:

.GroupBy(d => d.ArchiveTime.Date.AddHours(d.ArchiveTime.Hour))

不幸的是,目前 (EF Core 2.2) 不会将嵌套的 First/FirstOrDefault/Take(1) 转换为 SQL 并使用客户端评估。对于 First(),它被强制模拟 LINQ to Objects 抛出行为,但对于其他两种模式,它是由于缺乏适当的转换造成的。

对于您的具体查询,我看到的唯一服务器端解决方案是根本不使用 GroupBy,而是使用相关的自反连接,如下所示:

var onePerHour = dataLastWeek.Where(d => !dataLastWeek.Any(d2 =>
d2.ArchiveTime.Date == d.ArchiveTime.Date &&
d2.ArchiveTime.Hour == d.ArchiveTime.Hour &&
d2.ArchiveTime < d.ArchiveTime));

关于c# - 在 IQueryable 中按小时分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57038298/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com