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

EF Core实现按CounterOwner.Name过滤后分组计算CounterEntry每日数据差值的数据库端查询方案

EF Core实现按CounterOwner.Name过滤后分组计算CounterEntry每日数据差值的数据库端查询方案

我完全懂你的需求——不想把所有数据拉到内存里折腾,要让数据库来完成过滤、分组和差值计算,这确实是更高效的做法,用EF Core的LINQ查询就能实现,而且能直接转换成对应的SQL逻辑。

下面是具体的实现方案,分两种写法(取决于你用的EF Core版本):

方案一:兼容EF Core 5及以下版本

这种写法用OrderByDescending().First()和OrderBy().First()来获取每组的最后一条和第一条记录,EF Core会把它转换成SQL里的TOP 1查询,所有计算都在数据库端完成:

using Microsoft.EntityFrameworkCore;

// 替换成你的上下文实例和目标名称
var targetOwnerName = "张三";

var dailyDifferences = await dbContext.CounterEntries
    // 关联CounterOwner并过滤名称(EF Core会自动生成JOIN语句,无需手动写SQL)
    .Where(ce => ce.CounterOwner.Name == targetOwnerName)
    // 按日期的“天”分组,把DateTime截断到日期部分
    .GroupBy(ce => ce.DateTime.Date)
    // 投影成匿名对象,计算每日差值
    .Select(g => new
    {
        Date = g.Key,
        // 当日Heating的差值:最后一条记录值 - 第一条记录值
        HeatingDailyUsage = g.OrderByDescending(ce => ce.DateTime).First().Heating - g.OrderBy(ce => ce.DateTime).First().Heating,
        // 各个水表的每日差值同理
        WaterCounter1DailyUsage = g.OrderByDescending(ce => ce.DateTime).First().WaterCounter1 - g.OrderBy(ce => ce.DateTime).First().WaterCounter1,
        WaterCounter2DailyUsage = g.OrderByDescending(ce => ce.DateTime).First().WaterCounter2 - g.OrderBy(ce => ce.DateTime).First().WaterCounter2,
        WaterCounter3DailyUsage = g.OrderByDescending(ce => ce.DateTime).First().WaterCounter3 - g.OrderBy(ce => ce.DateTime).First().WaterCounter3,
        WaterCounter4DailyUsage = g.OrderByDescending(ce => ce.DateTime).First().WaterCounter4 - g.OrderBy(ce => ce.DateTime).First().WaterCounter4
    })
    .ToListAsync();

方案二:EF Core 6+版本简化写法

EF Core 6新增了MaxBy和MinBy方法,能更简洁地获取每组中DateTime最大/最小的记录,代码可读性更好:

using Microsoft.EntityFrameworkCore;

var targetOwnerName = "张三";

var dailyDifferences = await dbContext.CounterEntries
    .Where(ce => ce.CounterOwner.Name == targetOwnerName)
    .GroupBy(ce => ce.DateTime.Date)
    .Select(g => new
    {
        Date = g.Key,
        HeatingDailyUsage = g.MaxBy(ce => ce.DateTime).Heating - g.MinBy(ce => ce.DateTime).Heating,
        WaterCounter1DailyUsage = g.MaxBy(ce => ce.DateTime).WaterCounter1 - g.MinBy(ce => ce.DateTime).WaterCounter1,
        WaterCounter2DailyUsage = g.MaxBy(ce => ce.DateTime).WaterCounter2 - g.MinBy(ce => ce.DateTime).WaterCounter2,
        WaterCounter3DailyUsage = g.MaxBy(ce => ce.DateTime).WaterCounter3 - g.MinBy(ce => ce.DateTime).WaterCounter3,
        WaterCounter4DailyUsage = g.MaxBy(ce => ce.DateTime).WaterCounter4 - g.MinBy(ce => ce.DateTime).WaterCounter4
    })
    .ToListAsync();

关键说明

  1. 数据库端执行:这两种写法都会被EF Core转换成包含GROUP BY、JOIN和聚合逻辑的SQL,所有计算都在数据库服务器完成,不会把大量CounterEntry数据加载到内存,性能更优。
  2. 日期分组逻辑:ce.DateTime.Date会被EF Core转换成对应数据库的日期截断函数(比如SQL Server里的CAST([DateTime] AS DATE)),确保按天分组的正确性。
  3. 边界情况处理:如果某天只有一条记录,差值会自动为0,符合实际业务逻辑(当天没有数据变化)。

备注:内容来源于stack exchange,提问作者schgab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 10:39:31