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

EntityFrameworkCore更新实体列表时DbUpdateConcurrencyException异常求助

问题原因分析

出现Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException的核心原因:

  • 在UpdatePersonAsync方法中,查询出PersonDb实体后,AutoMapper直接替换了WorkExperiences集合,而非在EF Core已追踪的现有集合上做增量变更。
  • AutoMapper生成的新WorkExperienceDb实例未被EF Core标记为Added状态;同时原PersonDb实体本身无其他字段变更,EF Core执行更新操作时发现无实际数据变化触发并发异常;或是EF Core误将新实体当作已存在数据去更新,因数据库无对应行抛出异常。
解决方案

方案1:配置AutoMapper实现集合增量更新

修改映射规则,让AutoMapper对WorkExperiences执行合并(新增/更新/删除)而非替换,确保EF Core能追踪变更:

CreateMap<Person, PersonDb>()
    // 保留原有字段映射
    .ForMember(personDb => personDb.WorkExperiences, opt => opt.MapFrom(person => person.GetWorkExperiences()))
    .AfterMap((src, dest, context) =>
    {
        var existingExperiences = dest.WorkExperiences.ToList();
        var newExperiences = context.Mapper.Map<List<WorkExperienceDb>>(src.GetWorkExperiences());

        // 删除新集合中不存在的旧记录
        foreach (var existing in existingExperiences)
        {
            if (!newExperiences.Any(e => e.Id == existing.Id))
            {
                dest.WorkExperiences.Remove(existing);
            }
        }

        // 新增或更新记录
        foreach (var newExp in newExperiences)
        {
            var existing = existingExperiences.FirstOrDefault(e => e.Id == newExp.Id);
            if (existing == null)
            {
                newExp.PersonId = src.Id;
                dest.WorkExperiences.Add(newExp);
            }
            else
            {
                context.Mapper.Map(newExp, existing);
            }
        }
    });

同时修改UpdatePersonAsync,查询时加载关联的WorkExperiences以保证EF Core追踪:

public async Task UpdatePersonAsync(Person person, CancellationToken cancellationToken)
{
    var entity = await _dbContext.Persons
        .Include(p => p.WorkExperiences) // 必须加载关联集合
        .FirstOrDefaultAsync(p => p.Id == person.Id, cancellationToken);

    _mapper.Map(person, entity);
}

方案2:手动标记新增实体状态(简化版)

若仅需处理新增场景,可在映射后手动将新实体标记为Added:

public async Task UpdatePersonAsync(Person person, CancellationToken cancellationToken)
{
    var entity = await _dbContext.Persons
        .Include(p => p.WorkExperiences)
        .FirstOrDefaultAsync(p => p.Id == person.Id, cancellationToken);

    var originalCount = entity.WorkExperiences.Count;
    _mapper.Map(person, entity);

    // 标记新增的WorkExperience为Added状态
    for (int i = originalCount; i < entity.WorkExperiences.Count; i++)
    {
        _dbContext.Entry(entity.WorkExperiences[i]).State = EntityState.Added;
    }
}

关键注意事项

  • 查询PersonDb时必须通过Include加载WorkExperiences,否则EF Core无法追踪现有集合的变更。
  • 禁止直接替换EF Core已追踪实体的集合属性,应始终在现有集合上执行增删改操作,确保EF Core正确生成变更语句。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:03:31