C# API中Operacao类Update()正常但Create()执行失败排查
我开发的C# API中,多表的更新与创建操作均正常,但Operacao类存在异常:Update()方法运行正常,Create()方法执行失败,抛出DbUpdateConcurrencyException。
实体类定义
Operacao实体类
public class Operacao { public virtual short OperacaoID { get; set; } public virtual short? Codigo { get; set; } public virtual string Nome { get; set; } public virtual string? Descricao { get; set; } public virtual bool FlagAtivo { get; set; } public virtual bool FlagPadrao { get; set; } public virtual int DtUpdate { get; set; } }
输入数据类OperacaoDados
public class OperacaoDados { [Key] [JsonIgnore] public short OperacaoID { get; set; } [NotMapped] public virtual string Nome { get; set; } public virtual string? Descricao { get; set; } }
控制器代码
[HttpPost] [Authorize] public async Task<ActionResult> PostOperacao(OperacaoDados operacaoDados) { var operacaoExistente = await _context.Operacao .FirstOrDefaultAsync(o => o.Nome == operacaoDados.Nome); DateTime dateTime = DateTime.UtcNow; long ticks = dateTime.Ticks; int dataInteiro = (int)(ticks & 0xFFFFFFFF); if (operacaoExistente != null) { operacaoExistente.Descricao = operacaoDados.Descricao; operacaoExistente.FlagAtivo = true; try { await _operacaoRepository.Update(operacaoExistente); return Ok("Operação atualizada com sucesso"); } catch (DbUpdateConcurrencyException) { // Handle the concurrency exception here return Conflict("A operação que você está tentando atualizar foi modificada por outro usuário."); } } else { Operacao novoOperacao = new Operacao { Codigo = short.Parse(operacaoDados.Nome), DtUpdate = dataInteiro, Nome = operacaoDados.Nome, Descricao = operacaoDados.Descricao, FlagAtivo = true, FlagPadrao = false }; var result = await _operacaoRepository.Create(novoOperacao); if (result != null) { return Ok("Operação cadastrada com sucesso"); } return BadRequest("Erro ao salvar Operação"); } }
仓库层代码
public async Task<Operacao> Create(Operacao operacao) { _context.Operacao.Add(operacao); await _context.SaveChangesAsync(); return operacao; } public async Task Update(Operacao operacao) { _context.Entry(operacao).State = EntityState.Modified; await _context.SaveChangesAsync(); }
错误信息
Microsoft.EntityFrameworkCore.Database.Command: 信息:
已执行DbCommand (12ms) [参数=[@p0='?' (DbType = Int16), @p1='?' (Size = 4000), @p2='?' (DbType = Int32), @p3='?' (DbType = Boolean), @p4='?' (DbType = Boolean), @p5='?' (Size = 4000)],
命令类型='文本', 命令超时时间='30']
SET NOCOUNT ON;
INSERT INTO [Operacao] ([Codigo], [Descricao], [DtUpdate], [FlagAtivo], [FlagPadrao], [Nome])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5);
SELECT [OperacaoID]
FROM [Operacao]
WHERE @@ROWCOUNT = 1 AND [OperacaoID] = scope_identity();引发的异常:
'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException' 位于 Microsoft.EntityFrameworkCore.Relational.dll 中
引发的异常:
'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException' 位于 System.Private.CoreLib.dll 中
排查与解决方案
核心原因
创建时抛出该异常,本质是EF Core执行INSERT后,尝试读取自动生成的OperacaoID时未找到对应行,常见触发场景:
OperacaoID未配置为数据库自增主键,导致插入后无自动生成的ID值- 数据库表的INSERT触发器修改/删除了刚插入的行
- EF Core未识别
OperacaoID为主键,无法正确获取生成的ID
修复步骤
确认数据库主键配置:
检查Operacao表的OperacaoID列是否设置为IDENTITY(1,1)(SQL Server),确保数据库自动生成主键值。显式配置实体主键:
在Operacao类的OperacaoID属性上添加特性,明确告知EF Core这是自增主键:public class Operacao { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public virtual short OperacaoID { get; set; } // 其他属性... }或通过Fluent API在DbContext中配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Operacao>() .HasKey(o => o.OperacaoID); modelBuilder.Entity<Operacao>() .Property(o => o.OperacaoID) .ValueGeneratedOnAdd(); }检查数据库触发器:
查看Operacao表是否存在INSERT触发器,若触发器有删除/修改插入行的逻辑,需调整确保插入行保留且OperacaoID值正确。验证Codigo赋值逻辑:
控制器中Codigo = short.Parse(operacaoDados.Nome)存在格式转换风险,若Nome无法转为short会抛出异常,同时需确保该值符合数据库列的约束(如非空、唯一性)。
内容的提问来源于stack exchange,提问作者TheVipZo123

