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

EF Core使用生成查询存疑:存储过程调用报重复键异常及性能疑问

问题原因与解决方案

为什么调用存储过程会报错?

EF Core 使用 Include 查询时,内部会自动处理关联查询产生的重复行,把重复的实体(比如同一个 Promoter)合并到对象树中,不会重复添加到上下文的跟踪集合里。但用 FromSqlRaw 调用存储过程时,EF 会把返回的扁平化结果集逐行映射为实体对象,当结果集中出现相同主键的实体(比如同一个 Promoter 在多行结果里重复出现),EF 尝试将这些重复实体添加到跟踪集合时,就会触发「重复键已存在」的异常——因为上下文不允许同时跟踪两个主键相同的实体。

而 EF 自己生成的查询,底层会做结果集的去重合并处理,所以不会出现这个问题。

这么做能获得性能提升吗?

不一定,得看具体场景:

  • 如果只是把 EF 自动生成的查询直接复制到存储过程里,性能基本没差别,甚至可能因为存储过程的参数嗅探、编译缓存问题导致性能下降。
  • 如果你的 Include 链太长,EF 生成的查询产生了大量笛卡尔积(结果集行数爆炸),这时候手动优化存储过程的查询逻辑(比如用更高效的关联方式、分页返回必要数据),可能会有性能提升。
  • 但 EF Core 本身对多表关联查询有优化(比如 EF Core 5+ 的拆分查询 SplitQuery),合理使用的话,性能未必比存储过程差。

解决报错的方法

最直接的办法是关闭实体跟踪(如果只是读取数据不需要后续修改):

List<Application> Applications = await dbContext.Applications
    .FromSqlRaw("Exec GetFullApplication {0}", uuid)
    .AsNoTracking() // 关闭跟踪,避免重复键校验
    .ToListAsync();

如果必须保留跟踪,那需要修改存储过程的返回逻辑,确保每个实体只返回一次,但这对于多表关联查询来说很难实现——因为关联必然会产生重复行,所以关闭跟踪是更可行的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 11:45:57