EF7插入重复键报错后,修改条码重提交仍触发相同异常求助
解决EF Core上下文保留错误实体导致重复键异常的问题
问题原因
EF Core的DbContext内置状态跟踪机制,第一次添加的Barcode为"aa"的Position实体已经被上下文标记为Added状态。即使后续创建了新的实体,之前的错误实体仍在上下文的追踪列表中,调用SaveChangesAsync时会尝试提交所有追踪的变更,因此重复抛出唯一键冲突异常。
解决方案
1. 在异常处理中移除错误实体的追踪
修改通用仓储的Add方法,捕获DbUpdateException后,将出错的实体从上下文的状态追踪中分离:
public virtual async Task<int> Add(TDto dto) { var entity = _mapper.Map<TEntity>(dto); SetNavigationPropertiesToNull(entity); var entry = _db.Set<TEntity>().Add(entity); try { await _db.SaveChangesAsync(); return entity.Id; } catch (DbUpdateException) { // 将错误实体从上下文追踪中移除 _db.Entry(entity).State = EntityState.Detached; throw; // 重新抛出异常,让上层UI处理错误提示 } }
2. 确保上下文的短生命周期
虽然你已将DataContext配置为Transient,但需确认仓储服务的生命周期也为Transient,保证每次操作都获取全新的上下文实例,避免复用带有错误实体的上下文:
// Program.cs中配置仓储(示例) builder.Services.AddTransient<IRepository<Position, PositionDto>, Repository<Position, PositionDto>>();
3. 提前验证唯一性(减少异常触发)
在执行Add操作前,先查询数据库检查Barcode是否已存在,提前拦截重复值,提升用户体验(注意:此方法无法完全避免并发冲突,数据库唯一索引仍是最终保障):
public virtual async Task<int> Add(TDto dto) { var entity = _mapper.Map<TEntity>(dto); // 针对Position实体的Barcode唯一性检查 if (entity is Position position) { var isDuplicate = await _db.Set<Position>() .AnyAsync(p => p.Barcode == position.Barcode); if (isDuplicate) { throw new InvalidOperationException($"条码 {position.Barcode} 已存在"); } } SetNavigationPropertiesToNull(entity); _db.Set<TEntity>().Add(entity); await _db.SaveChangesAsync(); return entity.Id; }
4. 清空所有追踪实体(极端场景)
如果上下文存在多个错误追踪实体,可在异常后清空所有追踪状态(谨慎使用,避免影响正常操作):
catch (DbUpdateException) { foreach (var entry in _db.ChangeTracker.Entries()) { entry.State = EntityState.Detached; } throw; }
内容的提问来源于stack exchange,提问作者Kieran
相关产品推荐
相关产品推荐

