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

EF Core 8添加子实体时触发DbUpdateConcurrencyException问题排查

DbUpdateConcurrencyException 问题分析与解决方案

问题根源

从日志中的SQL语句可以定位核心问题:

  • EF Core 针对新创建的Device生成了UPDATE语句(而非预期的INSERT),这条UPDATE找不到对应数据库行(Device尚未插入),直接触发并发异常。
  • 同时生成了多余的Organisation UPDATE语句,但实际上Organisation的属性并未发生任何修改。

导致该问题的关键原因是调用了_organisationRepository.Update(organisation):

public void Update(Organisation organisation)
{
    _context.Organisations.Update(organisation);
}

DbSet.Update()方法会强制将传入实体及其所有关联实体(包括刚添加的Device)的状态标记为Modified,而非Added。EF基于这个错误状态生成UPDATE语句,自然找不到目标行,抛出并发异常。

另外,查询Organisation时未加载Devices导航属性,虽然不是直接诱因,但会导致内存中Devices集合与数据库不一致,可能引发重复添加设备的逻辑错误。

解决方案

1. 移除不必要的Update调用

EF Core的变更追踪机制会自动检测实体状态变化,包括新添加的关联实体。无需手动调用Update,直接执行SaveChangesAsync即可:

修改Handle方法:

public async Task<Result> Handle(CreateDeviceCommand command, CancellationToken cancellationToken)
{
    var organisation = await _organisationRepository.GetAsync(command.OrganisationId);

    if (organisation == null) 
        return Result.Failure(CreateDeviceErrors.NullOrganisation);

    var deviceResult = Device.Create(organisation, command.DeviceId, command.DeviceName);

    if (deviceResult.IsFailure) 
        return Result.Failure(deviceResult.Error);

    var addDeviceResult = organisation.AddDevice(deviceResult.Value);

    if (addDeviceResult.IsFailure) 
        return Result.Failure(addDeviceResult.Error);

    // 移除该行,不需要手动触发Update
    // _organisationRepository.Update(organisation);
    
    await _unitOfWork.SaveChangesAsync(cancellationToken);

    return Result.Success();
}

2. 优化Organisation查询(可选)

获取Organisation时显式加载Devices导航属性,确保内存集合与数据库一致,避免重复添加设备的逻辑出错:

修改OrganisationRepository的GetAsync方法:

public async Task<Organisation> GetAsync(Guid organisationId)
{
    return await _context.Organisations
        .Include(o => o.Devices) // 显式加载导航属性
        .FirstOrDefaultAsync(o => o.Id == organisationId);
}

3. 调整Update逻辑(特殊场景适配)

如果某些业务场景必须保留Repository的Update方法,需修改逻辑,仅更新Organisation自身,不覆盖关联实体状态:

public void Update(Organisation organisation)
{
    // 仅标记Organisation自身为Modified,不处理关联实体
    _context.Entry(organisation).State = EntityState.Modified;
}

注意:当前场景下Organisation无属性变更,仍无需调用该方法。

验证效果

修改后,EF Core会正确将新添加的Device标记为Added,生成INSERT语句,同时不会生成多余的Organisation UPDATE语句,彻底避免并发异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:13:09