使用entity framework代码保存分离的对象图首先导致主键冲突

我正在尝试使用Code First流利的符号保存我已映射到EF6的POCO的对象图。

然而,在保存对象图之后,我偶然发现了主键冲突exception。

对象图非常简单:

一个Issue可以包含多个WorkItems ,每个Author (作为User )。

外部填充对象(使用Web API)

当我尝试使用两个引用同一作者的工作项来保存问题时,我希望插入问题,插入工作项和插入一个作者,另一个要引用或更新。

然而,会发生的问题是插入问题,插入工作项并插入对同一用户的两个引用,从而导致主键冲突。

简化的问题对象:

 public class Issue { public Issue() { WorkItems = new List(); } public string Id { get; set; } private List _workItems; public List WorkItems { get { return _workItems ?? new List(); } set { _workItems = value; } } } 

简化的WorkItem:

 public class WorkItem { public string Id { get; set; } public string AuthorLogin { get; set; } private WorkItemAuthor _author; public WorkItemAuthor Author { get { return _author; } set { _author = value; if (value != null) { AuthorLogin = value.Login; } else { AuthorLogin = string.Empty; } } } } 

简化的用户对象:

 public class User { public string Login { get; set; } public string FullName { get; set; } } 

他们的代码优先配置:

  internal IssueConfiguration() { HasKey(x => x.Id); HasMany(x => x.WorkItems); } internal WorkItemConfiguration() { HasKey(x => x.Id); HasRequired(p => p.Author) .WithMany(b => b.WorkItems) .HasForeignKey(x=>x.AuthorLogin); } internal UsersConfiguration() { HasKey(x => x.Login); } 

一切都很简单。 在数据库创建时,de表也看起来很好,花花公子也是如此,在人们期望它们的列上有FK

现在,当保存问题时,如果插入对象图将会很好,并且对现有对象的引用将被自动识别并且可选地仅插入或引用。

我试图相应地添加问题:

 using (var db = new Cache.Context()) { if (db.Issues.Any(e => e.Id == issue.Id)) { db.Issues.Attach(issue); db.Entry(issue).State = EntityState.Modified; } else { db.Issues.Add(issue); } db.SaveChanges(); } 

解决这个问题的方法是我在对象图中手动添加或附加图中的其他对象吗? 我希望通过定义适当的外键值来识别这些引用。

我终于做了类似的事情,非常费力,我仍然希望找到更好的方法。 找出一个实体是否已经附加或存在于数据库中,结果是过多地污染了模型(实​​现IEquatable很好,但我认为在我的POCO上实施IEntityWithKey过多地污染POCO。(直到那个似乎不足以跟踪上下文中的实体)

 internal static void Save(this List issues) { using (var db = new Context()) { foreach (var issue in issues.ToList()) { foreach (var workItem in issue.WorkItems.ToList()) { if (workItem.Author != null) { var existing = db.Users.SingleOrDefault(e => e.Login == workItem.Author.Login); if (existing == null) { db.Users.Add(workItem.Author); } else { //Update existing entities' properties existing.Url = workItem.Author.Url; //Replace reference workItem.Author = existing; } db.SaveChanges(); } var existingWorkItem = db.WorkItems.SingleOrDefault(e => e.Id == workItem.Id); if (existingWorkItem == null) { db.WorkItems.Add(workItem); } else { //Update existing entities' properties existingWorkItem.Duration = workItem.Duration; //Replace reference issue.WorkItems.Remove(workItem); issue.WorkItems.Add(existingWorkItem); } db.SaveChanges(); } var existingIssue = db.Issues.SingleOrDefault(x => x.Id == issue.Id); if (existingIssue == null) { db.Issues.Add(issue); } else { //Update existing entities' properties existingIssue.SpentTime = issue.SpentTime; } db.SaveChanges(); } } } 

Issue对象中有一个小错误。

“return _workItems ?? new List();” 如果_workItems变为null,则可以在每次获取时返回一个新的WorkItem。 这是固定版本。

 public class Issue { public Issue() { WorkItems = new List(); } public String Id { get; set; } public List WorkItems { get; private set; } }