我正在使用Code First,EF 6.0并尝试在请求和标记表之间实现多对多关系。
关系设置正确为:
HasMany(b => b.Tags).WithMany().Map(mc => mc.MapLeftKey("RequestID").MapRightKey("TagID").ToTable("requesttags"));
一切都很好看。但是,当涉及到Request的插入标记时,我以三种方式插入:
> if (request.Tags == null)
> {
> entity.Tags = new List<Tag>();
> }
> // 1 way get the tag and then insert.
> var tag = _tagService.Get(1);
// 2 and 3 way hard code id with the name.
> var tags = new List<Tag> {tag, new Tag {Name = ".Net", ID = 2}, new Tag {Name = "C#"}};
>
> request.Tags.AddRange(tags);
执行插入操作。但是,当我看到最终结果时:第一个标签已正确引用。但是对于两个标签,即使ID和名称匹配,它仍然在Tag表中创建一个新记录并进行引用。
我的想法是因为第一个标记对象是从数据库获取并附加的。但为什么我必须附上?
我该如何解决这个问题?
答案 0 :(得分:1)
但为什么我必须附上?
因为它们是断开连接的对象,将被视为新对象。当您将tags
添加到request.Tags
时,它们都会被标记为已添加,因为EF并不知道它们都是现有实体。
您只需循环Tags
即可查看每个代码的状态。
request.Tags.AddRange(tags);
foreach(var tag in tags)
{
Console.WriteLine(dbContext.Entry(tag).State);
}
输出应该是:
Unchanged
Added
Added
我该如何解决这个问题?
只需Attach
或将Unchanged
标记为已断开连接的对象。
dbContext.Entry(tags[1]).State = EntityState.Unchanged;
// equals to dbContext.Set<Tag>().Attach(tags[1]);
dbContext.Entry(tags[2]).State = EntityState.Unchanged;
// equals to dbContext.Set<Tag>().Attach(tags[2]);
确保两个实体都是现有实体,否则在调用DbUpdateException
时会抛出SaveChanges
。