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

如何在ASP.NET Core中按月查询销售数据并存储到PostgreSQL?

解决方案:ASP.NET Core + PostgreSQL 实现月度销售统计并存储

一、问题分析

你的现有代码错误地按销售记录ID统计次数(每条记录ID唯一,统计结果无实际意义),需要改为按销售年月分组统计总销量,同时需创建专门的月度报表表存储聚合后的统计数据(而非更新单条销售记录的字段)。

二、步骤1:定义月度报表实体与数据库上下文

首先创建存储月度统计的实体类,并将其添加到DbContext:

// 月度销售报表实体
public class MonthlySalesReport
{
    public int Id { get; set; }
    public int Year { get; set; }
    public int Month { get; set; }
    public int TotalSales { get; set; }

    // 可选:添加唯一约束,避免重复插入同一年月的记录
    [Index(nameof(Year), nameof(Month), IsUnique = true)]
    public string YearMonthKey => $"{Year}{Month:D2}";
}

// 在你的DbContext中添加DbSet
public DbSet<MonthlySalesReport> MonthlySalesReports { get; set; }

执行数据库迁移创建对应表:

dotnet ef migrations add AddMonthlySalesReport
dotnet ef database update

三、步骤2:优化查询逻辑(数据库端分组统计)

不要拉取所有数据到内存统计,直接用EF Core的Linq查询在PostgreSQL端完成分组,提升性能:

// 从数据库查询并分组统计月度销量(过滤已删除记录)
var monthlySalesStats = Repository.repoSales
    .Where(s => !s.IsDeleted)
    .GroupBy(s => new { s.SaleDate.Year, s.SaleDate.Month })
    .Select(g => new 
    {
        Year = g.Key.Year,
        Month = g.Key.Month,
        TotalSales = g.Count()
    })
    .ToList();

四、步骤3:将统计结果保存到数据库

采用"存在则更新,不存在则插入"的逻辑,避免重复数据:

foreach (var stat in monthlySalesStats)
{
    // 检查该年月的报表是否已存在
    var existingReport = Repository.repoMonthlySalesReports
        .FirstOrDefault(r => r.Year == stat.Year && r.Month == stat.Month);

    if (existingReport != null)
    {
        // 更新现有记录
        existingReport.TotalSales = stat.TotalSales;
        Repository.repoMonthlySalesReports.Update(existingReport);
    }
    else
    {
        // 创建新记录
        var newReport = new MonthlySalesReport
        {
            Year = stat.Year,
            Month = stat.Month,
            TotalSales = stat.TotalSales
        };
        Repository.repoMonthlySalesReports.Add(newReport);
    }
}

// 统一提交所有修改到数据库
Repository.SaveChanges();

五、步骤4:输出期望的统计结果

格式化年月为MM/yyyy格式并输出:

foreach (var stat in monthlySalesStats)
{
    Console.WriteLine($"{stat.Month:D2}/{stat.Year} - {stat.TotalSales}");
}

六、完整代码示例

整合后的控制台应用代码:

// 统计月度销量
var monthlySalesStats = Repository.repoSales
    .Where(s => !s.IsDeleted)
    .GroupBy(s => new { s.SaleDate.Year, s.SaleDate.Month })
    .Select(g => new 
    {
        Year = g.Key.Year,
        Month = g.Key.Month,
        TotalSales = g.Count()
    })
    .ToList();

// 保存到数据库
foreach (var stat in monthlySalesStats)
{
    var existingReport = Repository.repoMonthlySalesReports
        .FirstOrDefault(r => r.Year == stat.Year && r.Month == stat.Month);

    if (existingReport != null)
    {
        existingReport.TotalSales = stat.TotalSales;
        Repository.repoMonthlySalesReports.Update(existingReport);
    }
    else
    {
        var newReport = new MonthlySalesReport
        {
            Year = stat.Year,
            Month = stat.Month,
            TotalSales = stat.TotalSales
        };
        Repository.repoMonthlySalesReports.Add(newReport);
    }
}

Repository.SaveChanges();

// 输出结果
foreach (var stat in monthlySalesStats)
{
    Console.WriteLine($"{stat.Month:D2}/{stat.Year} - {stat.TotalSales}");
}

关键说明

  • 避免内存统计:直接通过EF Core将分组逻辑推送到PostgreSQL执行,减少内存消耗与网络传输量。
  • 数据唯一性:通过实体的唯一约束确保同一年月的报表只存一份,避免重复统计。
  • 独立存储统计数据:月度统计是聚合数据,应存储在专门的报表表中,而非修改原始销售记录的字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:37:48