我在4年内第n次遇到此问题,但从未找到解释和解决方案的理由。
我有2节课:
public class Question
{
public Guid Id { get; set; }
public String Text { get; set; }
public virtual Survey Survey { get; set; }
public virtual List<Answer> Answers { get; set; }
}
public class Answer
{
public Guid Id { get; set; }
public String Text { get; set; }
public virtual Question Question { get; set; }
}
然后在Seed方法中,我想创建问题和答案并将其链接在一起:
Guid guid23 = new Guid("c2c6900a-c8a7-4a4b-aa65-79cd0317f9d1");
//some other guids ...
Survey survey1 = new Survey { Id = guid21, Title = "Cars" };
Survey survey2 = new Survey { Id = guid22, Title = "Phones" };
Question question1 = new Question { Id = guid23, Text = "What type of car do you have?" };
Question question2 = new Question { Id = guid24, Text = "What size is the engine?" };
Question question3 = new Question { Id = guid25, Text = "What phone do you have?" };
Question question4 = new Question { Id = guid26, Text = "What big is the screen?" };
Answer answer1 = new Answer { Id = guid27, Text = "Sedan"};
Answer answer2 = new Answer { Id = guid28, Text = "3000" };
context.Questions.AddOrUpdate(a => a.Id, question1, question2, question3, question4);
context.Answers.AddOrUpdate(a => a.Id, answer1, answer2);
context.SaveChanges();
context.Answers.Find(answer1.Id).Question = question1;
context.Answers.Find(answer2.Id).Question = question2;
context.SaveChanges();
然后,当我运行database update -v
时,我得到:
违反主键约束'PK_dbo.Questions'。无法插入 对象“ dbo.Questions”中的重复键。重复的键值为 (c2c6900a-c8a7-4a4b-aa65-79cd0317f9d1)。该声明已经 终止。
如何在实体框架中以一对多关联链接两个对象?
答案 0 :(得分:1)
这是由于known bug in AddOrUpdate
引起的。这就是发生的情况。
开始的情况是您已经在数据库中找到了问题和答案。
第一个AddOrUpdate
...
context.Questions.AddOrUpdate(a => a.Id, question1, question2,...
...找到问题并将其附加为上下文UnChanged
。但是,实际找到的实例与question1, question2,...
不同。找到的实例是隐藏在上下文中的新对象。实例question1, question2,...
是Detached
!
因此,声明...
context.Answers.Find(answer1.Id).Question = question1;
...将answer1
连接到对上下文来说是全新的问题实例。在语句question1
的状态为Added
之后,SaveChanges
将尝试在现有Id
下插入一个新问题。
您已经快解决了。您似乎已经在某种程度上意识到了这个问题,因为您已经在使用context.Answers.Find(answer1.Id)
。该语句从上下文的缓存中拉出隐藏的answer1
副本,因此EF不会将那个看成是新的。解决方法是对以下问题执行相同的操作:
question1 = context.Questions.Find(question1.Id);
question2 = context.Questions.Find(question2.Id);
context.Answers.Find(answer1.Id).Question = question1;
context.Answers.Find(answer2.Id).Question = question2;
context.SaveChanges();