MVC结合Datatables调用存储过程生成月度销售报表出现数据重复与差异问题
问题原因分析
1. 实体主键配置错误(最高概率)
你当前MonthlySalesReport实体类将CampaignType(活动类型)标注为主键,但该字段显然不具备唯一性:同类型的活动会有大量重复记录。EF Core默认会对查询到的实体按主键做身份映射,只要主键值相同,后续查询到的相同主键的实体会直接复用之前缓存的实例,最终导致返回大量重复数据,和直接执行SQL的结果不一致。
2. 存储过程多余JOIN导致笛卡尔积
你在存储过程中LEFT JOIN flight FD 但整个SELECT语句没有用到任何FD表的字段,属于完全多余的关联。如果flight表中同一个mod_id存在多条记录,关联后就会产生笛卡尔积,导致行数翻倍,就算加了DISTINCT也可能因为部分字段差异无法去重,产生重复数据。此外你使用了多个FULL OUTER JOIN,如果关联的表存在一对多关系,也会导致行数异常增加。
3. EF上下文跟踪缓存问题
EF Core默认启用实体跟踪,如果上下文之前已经查询过相同主键的MonthlySalesReport实体,后续调用存储过程查询时会直接返回缓存的旧数据,导致结果和直接执行SQL不一致。
4. 字段映射不匹配
部分字段的映射可能存在偏差:比如存储过程返回的12月列名为Dec,实体类中属性名拼写错误为Decmber,如果Column属性和返回列名大小写/拼写不匹配,会导致字段映射失败,出现数据缺失或异常。
解决方案
- 修正实体主键配置:放开注释的
ID字段,将其标注为主键,删除CampaignType上的[Key]注解,确保主键是唯一的Md.id值:
[Column("ID"), Key] public int ID { get; set; } // 删掉CampaignType上的[Key] [Column("CAMPAIGN TYPE")] public string CampaignType{ get; set; }
- 清理存储过程多余关联:删除没用的
left outer join flight FD关联,根据实际业务需求将不必要的FULL OUTER JOIN改为LEFT JOIN或INNER JOIN,避免笛卡尔积产生多余行。 - 禁用实体跟踪:调用存储过程时添加
AsNoTracking(),关闭EF的跟踪缓存,保证每次都拿到最新的查询结果:
var rpt = await _context.MonthlySalesReport.FromSql(@"MonthlySalesReport").AsNoTracking().ToListAsync();
- 校验字段映射:修正实体类中拼写错误的属性(比如
Decmber改为December),确保所有[Column]注解的名称和存储过程返回的列名完全匹配。 - 定位问题层级:在API返回结果前打断点查看
rpt集合是否已经存在重复,如果已经重复说明是后端EF/存储过程的问题,如果未重复则需要检查前端DataTables的配置是否存在重复渲染的问题。
内容的提问来源于stack exchange,提问作者Monsur MonPaulo
相关产品推荐
相关产品推荐

