提问人:Raso 提问时间:10/31/2023 更新时间:11/1/2023 访问量:48
在实体框架上更新跟踪的实体
Update tracked entity on Entity Framework
问:
我在使用实体框架更新跟踪实体时遇到问题。我正在使用 dotnet 6。 假设我有一个 SnapshotEntity 和一个 UpdateSnapshotDto。 UpdateSnapshotD设置为用作“input”的那个,它从前端获取字段。我使用 AutoMapper 将 UpdateSnapshotDto 转换为 SnapshotEntity。 我尝试过(但失败了)的最简单方法是:
var oldSnapshot = await snapshotRepository.GetSingleOrDefaultAsync(e => e.Id == request.snapshot.Id);
var newSnapshot = mapper.Map<SnapshotEntity>(request.snapshot);
oldSnapshot = newSnapshot;
await snapshotRepository.SaveChangesAsync();
但当然不起作用,因为当我分配 oldSnapshot = newSnapshot 时,它可能会丢失跟踪。
所以我想我可以从我的输入中更新,就像这样:
var newSnapshot = mapper.Map<SnapshotEntity>(request.snapshot);
snapshotRepository.Update(newSnapshot);
但是这种方法对我不起作用,因为有些东西保存在原始文件中,如果我像这样进行暴力更新,我会丢失这些东西(例如,在数据库中,旧快照有一个 CreatedDate 和未在 UpdateSnapshotDto 中传递的列)。
所以我想读取文件,分配值并像这样更新:
var oldSnapshot = await snapshotRepository.GetSingleOrDefaultAsync(e => e.Id == request.snapshot.Id);
var newSnapshot = mapper.Map<SnapshotEntity>(request.snapshot);
newSnapshot.CreatedDate = oldSnapshot.CreatedDate;
newSnapshot.CreatedBy = oldSnapshot.CreatedBy;
snapshotRepository.Update(newSnapshot);
但这种方法都行不通,因为 oldSnapshot 被跟踪,当我尝试执行 Update 方法时,它说它已经被跟踪了。
我找到了 2 个解决方案,但不想使用它们:
- 第一个解决方案是我逐个字段分配给 oldSnapshot,例如 oldSnapshot.Name = newSnapshot.Name 等所有字段,但实际上我会避免这种方法,因为如果快照会增加属性,此逻辑将不再起作用,需要修复;
- 第二种解决方案,我使用我描述的第三次尝试,但使用 AsNoTracking() 读取实体,并且我想避免在项目中引入 AsNoTracking() 逻辑。
有什么想法吗?另一种解决方案可能是使用反射在旧的跟踪实体上分配所有新实体,但我不知道该怎么做,而且对于简单的更新来说,它可能“太高了”。
答:
我使用 AutoMapper 将 UpdateSnapshotDto 转换为 SnapshotEntity。
AutoMapper 能够从数据映射到现有实例,因此您可以只使用它,而不是创建一个新实例:
mapper.Map(request.snapshot, oldSnapshot);
// ...
await snapshotRepository.SaveChangesAsync();
另请参阅 AutoMapper.Collection。
上一个:更新实体的 EF Core 问题
下一个:如何使用 EF 映射实体的属性
评论
request.snapshot
oldSnapshot
mapper.Map
- 是自动映射器调用吗?