考虑
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添加到同一项目。保存时,将传递整个对象,包括现有的相关ItemTag。 EF然后尝试插入现有的ItemTag,但失败,但出现“无法将值插入到身份列...”
那么如何防止现有对象被插入?
我的解决方法是遍历ItemTags,并将所有具有ID的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();
答案 0 :(得分:1)
AutoMapper不适合返回到持久性或域模型。 AutoMapper stated的作者。
这也不能像EF(核心)执行change tracking的方式一样有效。
基于从数据库加载的实体,完成了更改跟踪。更改实体值时,其状态从Unchanged
变为Modified
,并会导致更新方法。
当您加载没有项目关系的实体时(使用紧急加载),那么当您添加实体时,它将被标记为Added
,并在保存时插入。
您还可以使用Attach
和Detach
实体。
来自链接的博客文章:
Rowan Miller在GitHub问题(bit.ly/295goxw)中总结了新行为:
添加:添加所有尚未跟踪的可达实体。
附加:附加每个可访问实体,除非可访问实体具有商店生成的键并且未分配键值;这些将被标记为已添加。
更新:与附加相同,但实体被标记为已修改。
删除:与“附加”相同,然后将根标记为已删除。由于级联删除现在发生在SaveChanges上,因此以后级联规则可以流到实体。
因此,您必须附加您的项目(如果您只想添加带有主键的新项目)或致电Update/UpdateRange
上的DbSet
,以使用密钥更新项目并添加没有的。
您也可以通过设置/更改其跟踪状态来自己处理它。但是请记住,Unchanged
不会更新传递的实体。
答案 1 :(得分:0)
要插入新的ItemTag
,可以直接插入到ItemTag
表中,而不反映Item
。
按如下所示定义模型:
public class ItemTag
{
public int Id { get; set; }
public int Name { get; set; }
public int ItemId { get; set; }
public virtual Item Item { get; set; }
}
尝试为ItemId
设置ItemTag
,为ItemTag
插入新的Item
。
如果您喜欢将Item
插入ItemTag
,则可以尝试使用JsonPatchDocument
来描述如何操作模型。
尝试参考JSON Patch With ASP.net Core。
对于JsonPatchDocument
,您需要在客户端生成JsonPatchDocument<Item>
。尝试引用ASP Core PatchDocument returning Invalid Input。