asp.net-core - EntityFrameworkCore 插入现有的相关项
问题描述
考虑
public class Item
{
public int Id{get;set;}
public string Name{get;set;}
public List<ItemTag> ItemTags{get;set;}
}
public class ItemTag
{
public int Id{get;set;}
public int Name{get;set;}
}
我现在使用实体框架核心将 ItemTag 添加到 Item。这工作得很好。
现在我将第二个 ItemTag 添加到同一个项目。保存时,传递整个对象,包括现有的相关ItemTags。然后 EF 尝试插入现有的 ItemTag 失败,但出现“无法将值插入标识列...”的异常
那么如何防止现有对象被插入呢?
我的解决方法是遍历 ItemTags,并将任何具有 Id 的内容设置为 EntityState.Unchanged 以强制它不保存它。但似乎不需要这样的解决方法。
这是保存项目的代码:
//Get the current item, so that only updated fields are saved to the database.
var item = await this.DbContext.Items.SingleAsync(a => a.Id == itemInput.Id);
item.UpdatedBy = this._applicationUserProvider.CurrentAppUserId;
item.Updated = DateTimeOffset.UtcNow;
//Use Automapper to map fields.
this._mapper.Map(itemInput, item);
//Workaround for issue.
foreach (var itemTag in item.ItemTags)
{
var entry = this.DbContext.Entry(itemTag);
if (itemTag.Id > 0)
{
entry.State = EntityState.Unchanged;
}
}
await this.SaveChangesAsync();
解决方案
AutoMapper 不适合回溯到持久性或域模型。AutoMapper 的作者表示。
这也不适用于 EF (Core)更改跟踪的方式。
根据从数据库加载的实体完成更改跟踪。当您更改实体值时,其状态将从 更改Unchanged
为Modified
并将导致更新方法。
当您加载一个没有项目关系的实体(使用急切加载)时,当您添加一个实体时,它会被标记为Added
,从而在保存时插入。
你也有可能Attach
和Detach
实体。
从链接的博客文章:
Rowan Miller 在 GitHub 问题 (bit.ly/295goxw) 中总结了新行为:
添加:添加尚未跟踪的每个可访问实体。
附加:附加每个可达实体,除非可达实体具有存储生成的键且未分配键值;这些将被标记为已添加。
更新:与附加相同,但实体被标记为已修改。
删除:与附加相同,然后将根标记为已删除。因为级联删除现在发生在 SaveChanges 上,这允许级联规则稍后流向实体。
因此,您必须附加您的项目(如果您只想添加带有主键的新项目)或调用Update/UpdateRange
以DbSet
更新带有键的项目并添加没有的项目。
或者通过设置/更改它的跟踪状态来自己处理它,就像你已经做的那样。但请记住,Unchanged
不会更新传递的实体。
推荐阅读
- git - 在 Colab 中将文件推送到 Git 时出错:致命:无法读取“https://github.com”的用户名:没有这样的设备或地址
- python - 从父目录导入python
- mongodb - 如何从集合中获取最高概率的记录。(显示搜索最多的时间)
- java - 如何使用 Kotlin 使用其路径播放 Mp3 文件?
- android - 如何创建视图 A 关闭然后视图 B 需要使用本机反应显示?
- django - 产品匹配查询不存在 Django
- javascript - 根据用户单选输入有条件地显示表单字段
- reactjs - 即使问题已在 React 应用程序中修复,TypeScript 也不会更改错误(终端输出)
- python - 正则表达式 python \1 \2 将字符串添加到结果文本的可能性
- node.js - 为什么在 res.redirect 之前使用 res.location?