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
相关产品推荐
相关产品推荐

