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

C#/WPF调用SQL存储过程传年月参数查销售额问题排查

C#/WPF对接SQL Server月度销售额查询功能修复方案

问题根因说明

  • 调用存储过程抛出InvalidOperationException的原因:
    1. FromSqlRaw调用存储过程时未写EXEC关键字,EF Core将存储过程名称识别为普通可组合SQL语句,尝试在外层嵌套查询;
    2. 存储过程返回的是聚合计算结果,直接在FromSqlRaw后拼接FirstOrDefault属于在数据库端做查询组合,而存储过程本身不支持SQL嵌套组合,需要显式调用AsEnumerable()将后续操作切换到客户端执行。
  • 调整存储过程后查询年份返回1905的原因:
    1905是SQL Server中数值0隐式转换为日期类型时对应的默认年份,本质是C#端调用时未给@year、@month参数正确赋值,传入了int类型默认值0,并非存储过程筛选逻辑错误。
  • 初期版本的逻辑缺陷:
    1. 存储过程入参设计为date类型,和前端直接传入int类型年、月的交互逻辑不匹配;
    2. 原分组逻辑按RentDate完整日期分组,会把不同日期的订单拆分为多条聚合结果,无法返回整月的销售总额。

具体实现代码

1. 修正后的SQL存储过程

直接接收int类型年、月入参,筛选后直接返回月度销售总额,无冗余分组,增加空值处理避免无订单时返回NULL:

ALTER PROCEDURE [dbo].[salesForSelectedMonth] 
    @year INT,
    @month INT
AS
BEGIN
    SET NOCOUNT ON;
    -- 当月无订单时返回0,避免C#端类型转换报错
    SELECT ISNULL(SUM(TotalPrice), 0) AS TOTAL_SALES
    FROM [TruckRental-PB]
    WHERE MONTH(RentDate) = @month
      AND YEAR(RentDate) = @year;
END

2. EF Core配置调整

存储过程返回的是聚合结果,不是业务表对应的实体类,需要定义专用DTO接收结果,在Data_Context中做无主键配置:

// 存储过程结果接收类
public class MonthlySalesResult
{
    public decimal TOTAL_SALES { get; set; }
}

// 在Data_Context类中添加对应DbSet
public DbSet<MonthlySalesResult> MonthlySalesResults { get; set; }

// 在OnModelCreating方法中配置无主键
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 其他原有配置...
    modelBuilder.Entity<MonthlySalesResult>().HasNoKey();
}

3. 修正后的C#调用方法

显式使用EXEC语法调用存储过程,添加AsEnumerable()规避SQL端组合查询问题,直接对接前端传入的int类型年、月参数:

public static int GetMonthlySales(int selectedYear, int selectedMonth)
{
    using (var ctx = new Data_Context())
    {
        var salesData = ctx.MonthlySalesResults
            .FromSqlRaw("EXEC salesForSelectedMonth @year, @month",
                new Microsoft.Data.SqlClient.SqlParameter("@year", selectedYear),
                new Microsoft.Data.SqlClient.SqlParameter("@month", selectedMonth))
            .AsEnumerable()
            .FirstOrDefault();
        
        return salesData == null ? 0 : Convert.ToInt32(salesData.TOTAL_SALES);
    }
}

4. 前端交互注意事项

  • 两个ComboBox分别绑定1-12的int类型月份集合、业务覆盖范围内的int类型年份集合;
  • 点击查询按钮时,先校验选中值是否为合法int类型,确认参数非0、非空后再传入查询方法,避免出现参数默认值0导致的1905年份异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:31:01