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

EF Core执行返回非唯一记录的存储过程时重复键错误解决咨询

解决EF Core调用返回非唯一记录的存储过程时的"An Item with the same key has already been added"错误

问题根源

EF Core的实体类型(无论是否启用跟踪)要求键字段(或复合键组合)必须唯一,因为实体模型依赖键来标识记录。即使添加了AsNoTracking(),EF在映射存储过程返回结果时,仍会校验键的唯一性,因此当存储过程返回重复键的记录时,就会触发该错误。


解决方案

方案1:使用无键实体(推荐)

将CustomModel配置为无键实体,EF Core就不会校验记录的键唯一性,可直接读取重复记录。

  1. 修改DbContext中的模型配置,移除所有键配置,添加HasNoKey():
modelBuilder.Entity<CustomModel>(entity =>
{
    // 移除原复合键配置,改为无键
    entity.HasNoKey();

    // 保留原有属性配置
    entity.Property(e => e.ReglerObjekt).IsRequired(false);
    // 其他属性配置...
});
  1. 调用存储过程的代码无需修改(AsNoTracking()可保留,但非必须):
Dim locTableContent = dbContext.CustomModel.FromSqlRaw("EXEC sp_xyz @Id, @globalId",
                 New SqlParameter("@Id", obj.Id),
                 New SqlParameter("@globalId", CType(globalId, Integer?))).AsNoTracking().ToList()

注意:如果之前尝试过HasNoKey()但未生效,大概率是没有完全移除原有的HasKey()配置,需确保模型配置中仅保留HasNoKey()。

方案2:直接使用ADO.NET读取数据

若不想修改实体配置,可绕过EF Core的实体映射,直接用原生ADO.NET执行存储过程并手动映射结果:

Dim locTableContent As New List(Of CustomModel)()

Using connection = dbContext.Database.GetDbConnection()
    connection.Open()
    Using command = connection.CreateCommand()
        command.CommandText = "EXEC sp_xyz @Id, @globalId"
        ' 添加参数
        command.Parameters.Add(New SqlParameter("@Id", obj.Id))
        command.Parameters.Add(New SqlParameter("@globalId", CType(globalId, Integer?)))
        
        Using reader = command.ExecuteReader()
            While reader.Read()
                Dim model As New CustomModel()
                ' 手动映射字段到模型属性
                model.ReglerObjekt = If(reader.IsDBNull(reader.GetOrdinal("ReglerObjekt")), Nothing, reader.GetInt32(reader.GetOrdinal("ReglerObjekt")))
                model.Typ = If(reader.IsDBNull(reader.GetOrdinal("Typ")), Nothing, reader.GetString(reader.GetOrdinal("Typ")))
                model.StatusNr = reader.GetInt32(reader.GetOrdinal("StatusNr"))
                ' 映射其他属性...
                locTableContent.Add(model)
            End While
        End Using
    End Using
End Using

对之前尝试方案的补充说明

  1. 复合键:若存储过程返回的记录中,Id+Typ+StatusNr的组合仍存在重复,即使配置复合键,EF Core仍会因键唯一性校验失败报错。
  2. AsNoTracking():该方法仅关闭实体跟踪,不会取消键唯一性校验,因此无法解决问题。
  3. HasNoKey():必须完全移除所有HasKey()配置才能生效,否则EF会优先使用键配置进行校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:10:09