CQRS模式Update方法中AutoMapper的报错解决与映射方案
问题原因
你先通过FindAsync从数据库加载了entity,此时该实体已被DbContext跟踪。之后用AutoMapper从request映射出一个新的Vehicle实例,调用_context.Vehicles.Update()时,EF发现新实例的Id与已跟踪的entity重复,因此抛出跟踪冲突错误。
解决方案
方法一:映射到已加载的实体(推荐)
直接将request的属性值映射到已被跟踪的entity上,EF会自动检测属性变化,无需额外调用Update方法:
修改Handle方法中的映射逻辑:
var entity = await _context.Vehicles .FindAsync(new object[] { request.Id }, cancellationToken); if (entity == null) { throw new NotFoundException(nameof(Vehicle), request.Id); } // 用AutoMapper将request的数据映射到已加载的实体上 _mapper.Map(request, entity); // 无需调用Update,EF会自动跟踪entity的属性变化 await _context.SaveChangesAsync(cancellationToken);
这种方式只会更新实际变化的字段,性能更优,也完全避免了跟踪冲突。
方法二:解绑原跟踪实体后更新新实例(不推荐)
若必须使用映射生成的新实例,需先将原加载的实体从DbContext跟踪中移除,再处理新实例:
var entity = await _context.Vehicles .FindAsync(new object[] { request.Id }, cancellationToken); if (entity == null) { throw new NotFoundException(nameof(Vehicle), request.Id); } // 解绑原实体的跟踪状态 _context.Entry(entity).State = EntityState.Detached; // 映射生成新实例并执行更新 var updatedVehicle = _mapper.Map<Domain.Entities.Vehicle.Vehicle>(request); _context.Vehicles.Update(updatedVehicle); await _context.SaveChangesAsync(cancellationToken);
此方法会让EF更新实体的所有字段(无论是否有变化),且可能丢失原实体的关联跟踪状态,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者irancss
相关产品推荐
相关产品推荐

