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

使用EF更新租车记录时触发DbUpdateConcurrencyException如何解决

排查与解决方法

排查步骤

  • 第一步:打印EF Core生成的实际SQL语句,确认SaveChanges执行的UPDATE语句的WHERE条件是否符合预期,是否存在匹配多条记录的可能。可以通过在上下文配置中添加日志输出实现:
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.LogTo(Console.WriteLine); // 输出SQL到控制台
    }
    
  • 第二步:直接在数据库执行SQL查询SELECT COUNT(*) FROM CarRentalFields WHERE CarNumber = 1000 AND ActualReturnDate IS NULL,确认符合条件的记录确实只有1条,排除事务未提交、脏读等数据层面问题。
  • 第三步:检查对应数据库表是否存在UPDATE触发器,触发器执行的额外操作可能会增加总影响行数。
  • 第四步:核对modelBuilder中CarRentalFields实体的配置,检查主键、并发令牌的配置是否和数据库表结构一致。

对应解决方案

场景1:主键配置错误

如果实体主键被误配置为非唯一字段(如CarNumber),会导致UPDATE语句的WHERE条件按非唯一字段匹配,可能命中多条记录。需修改为和数据库一致的主键配置,例:

// 假设表实际主键为自增Id字段
modelBuilder.Entity<CarRentalFields>().HasKey(x => x.Id);

场景2:存在UPDATE触发器

如果表上有不可移除的UPDATE触发器,EF Core 7及以上版本可以通过配置触发器避免EF校验影响行数时报错:

modelBuilder.Entity<CarRentalFields>()
    .ToTable(t => t.HasTrigger("触发器实际名称"));

场景3:上下文跟踪异常

同上下文下重复跟踪了多个相同实体实例时,也可能出现该错误,可通过修改查询和更新逻辑解决:

public void updateStatus(int carNumber1, string actualDate1)
{
    DateTime accReturn = DateTime.Parse(actualDate1);
    // 加空判断避免空引用异常
    var orderCar1 =  db.CarRentalFields
        .FirstOrDefault(carNum => carNum.CarNumber == carNumber1 && carNum.ActualReturnDate == null);
    if (orderCar1 == null)
    {
        // 可根据业务逻辑添加不存在的处理
        return;
    }
    // 手动清理多余跟踪
    db.ChangeTracker.Clear();
    orderCar1.ActualReturnDate = accReturn;
    db.Update(orderCar1);
    db.SaveChanges();
}

场景4:误配置并发令牌

如果非必要字段被配置为并发令牌,会导致UPDATE的WHERE条件添加多余匹配项,命中多条记录,移除多余的IsConcurrencyToken()配置即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:24:07