在实体框架上更新跟踪的实体

Update tracked entity on Entity Framework

提问人:Raso 提问时间:10/31/2023 更新时间:11/1/2023 访问量:48

问:

我在使用实体框架更新跟踪实体时遇到问题。我正在使用 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() 逻辑。

有什么想法吗?另一种解决方案可能是使用反射在旧的跟踪实体上分配所有新实体,但我不知道该怎么做,而且对于简单的更新来说,它可能“太高了”。

C# asp.net .NET 数据库 实体框架

评论

0赞 Gert Arnold 10/31/2023
必须将属性复制到 。request.snapshotoldSnapshot
0赞 Raso 10/31/2023
这是唯一的选择吗?我的意思是,我真的必须一一分配所有属性吗?假设它们是 40 处房产,没有其他方法吗?我必须做 40 个作业吗?
0赞 Gert Arnold 10/31/2023
请看这里以获得灵感。
0赞 Guru Stron 10/31/2023
mapper.Map- 是自动映射器调用吗?
0赞 Lucian Bargaoanu 10/31/2023
研究 AutoMapper.Collection。

答:

0赞 Guru Stron 11/1/2023 #1

我使用 AutoMapper 将 UpdateSnapshotDto 转换为 SnapshotEntity。

AutoMapper 能够从数据映射到现有实例,因此您可以只使用它,而不是创建一个新实例:

mapper.Map(request.snapshot, oldSnapshot);

// ...

await snapshotRepository.SaveChangesAsync();

另请参阅 AutoMapper.Collection