You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用LINQ按半小时周期返回最大ReadingReplacementVersion记录

如何用LINQ获取每个半小时周期内ReadingReplacementVersion最大的记录?

我有一个数据集,包含这些字段:

IntervalPeriodTimestamp RegisterTypeCode ReadingReplacementVersion IntervalValue

每30分钟接收一次读数,但读数有时会被替换,ReadingReplacementVersion会随之递增。我需要用LINQ只返回每个半小时周期内ReadingReplacementVersion最大的记录列表。

我试过这段代码:

db.IntervalInformations
    .Where(ii => ii.ChannelInformation.RegisterTypeCode == "62")
    .OrderBy(ii => ii.IntervalPeriodTimestamp)
    .ThenBy(ii => ii.ChannelInformation.Meter.messageType342.ReadingReplacementVersionNumber)
    .ToList();

它返回了按时间戳和版本排序的列表,但我只想要每个周期里版本最大的那条记录。我已经用SQL实现了这个需求,代码如下:

WITH CTE AS (
    select 
        SerialNumber, RegisterTypeCode, IntervalStatusCode, UOM_Code,
        IntervalPeriodTimestamp, ReadingReplacementVersionNumber, IntervalValue,
        RN = ROW_NUMBER() OVER (PARTITION BY IntervalPeriodTimestamp ORDER BY ReadingReplacementVersionNumber desc)
    from MarketMessage as a
    inner join messageType342 as b on a.MarketMessageID = b.MarketMessageID
    inner join Meter as c on b.messageType342ID = c.MessageType342ID
    inner join ChannelInformation as d on c.MeterID = d.MeterID
    inner join IntervalInformation as e on d.ChannelInformationID = e.ChannelInformationID
    where MPRN = 101010101010
        and CAST(IntervalPeriodTimestamp as date) between '1 feb 2018' and '28 feb 2018'
        and RegisterTypeCode = 62
)
select * from CTE WHERE RN = 1

不知道怎么把这段SQL转换成LINQ语句,求帮助!


我来帮你把这段SQL逻辑转换成对应的LINQ写法,有两种常用的思路可以实现你的需求:

方法1:分组后筛选每组最大版本记录

这种方式更直观,和你SQL的分组思路一致,先按IntervalPeriodTimestamp(半小时周期)分组,然后在每个分组里挑出ReadingReplacementVersionNumber最大的那条记录:

var result = db.IntervalInformations
    // 先加上SQL里的所有过滤条件
    .Where(ii => ii.ChannelInformation.RegisterTypeCode == "62"
             && ii.ChannelInformation.Meter.messageType342.MarketMessage.MPRN == 101010101010
             && ii.IntervalPeriodTimestamp.Date >= new DateTime(2018, 2, 1)
             && ii.IntervalPeriodTimestamp.Date <= new DateTime(2018, 2, 28))
    // 按半小时周期分组
    .GroupBy(ii => ii.IntervalPeriodTimestamp)
    // 每个分组内按版本号倒序,取第一条(也就是版本最大的)
    .Select(group => group.OrderByDescending(ii => ii.ChannelInformation.Meter.messageType342.ReadingReplacementVersionNumber)
                          .FirstOrDefault())
    // 过滤掉可能的空值(如果某个分组没有数据的话)
    .Where(item => item != null)
    .ToList();

方法2:模拟SQL的ROW_NUMBER()逻辑

如果你想更贴近SQL里CTE的写法,可以给每条记录计算一个“行号”,然后筛选行号为1的记录(也就是每个周期里版本最大的那条):

var query = db.IntervalInformations
    // 同样先加上所有过滤条件
    .Where(ii => ii.ChannelInformation.RegisterTypeCode == "62"
             && ii.ChannelInformation.Meter.messageType342.MarketMessage.MPRN == 101010101010
             && ii.IntervalPeriodTimestamp.Date >= new DateTime(2018, 2, 1)
             && ii.IntervalPeriodTimestamp.Date <= new DateTime(2018, 2, 28))
    // 给每条记录计算行号:统计同周期内版本号比当前大的记录数+1,就是当前的行号
    .Select(ii => new {
        IntervalInfo = ii,
        RowNumber = db.IntervalInformations
            .Where(other => other.IntervalPeriodTimestamp == ii.IntervalPeriodTimestamp
                         && other.ChannelInformation.RegisterTypeCode == "62")
            .Count(other => other.ChannelInformation.Meter.messageType342.ReadingReplacementVersionNumber > ii.ChannelInformation.Meter.messageType342.ReadingReplacementVersionNumber) + 1
    })
    // 只保留行号为1的记录
    .Where(x => x.RowNumber == 1)
    // 提取出原始的IntervalInformation对象
    .Select(x => x.IntervalInfo)
    .ToList();

小提示:

  • 方法1的性能通常更好,因为EF会把GroupBy转换成高效的SQL分组逻辑,尤其是在EF Core 3.0+版本中,GroupBy的支持非常完善;
  • 确保你的EF导航属性(比如ChannelInformation、Meter这些关联对象)配置正确,避免不必要的延迟加载导致性能问题;
  • 如果你的IntervalPeriodTimestamp是精确到分钟的时间戳,分组时直接用它就可以对应每个半小时周期,和你的SQL逻辑一致。

内容的提问来源于stack exchange,提问作者Jay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:22:32