I find it very difficult to update and delete many of the many relationships with EF Code-first.
I have a pretty simple model:
public class Issue { [Key] public int IssueId { get; set; } public int Number { get; set; } public string Title { get; set; } public DateTime Date { get; set; } public virtual ICollection<Creator> Creators { get; set; } } public class Creator { [Key] public int CreatorId { get; set; } public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } public virtual ICollection<Issue> Issues { get; set; } } public class Icbd : DbContext { public DbSet<Issue> Issues { get; set; } public DbSet<Creator> Creators { get; set; } }
I was not able to figure out how to update the many-to-many reality using the EF context. In my isnert / update action, I have this code:
[HttpPost] public ActionResult EditIssue ( Issue issue, int[] CreatorIds ) { if(CreatorIds == null) ModelState.AddModelError("CreatorIds", "Please specify at least one creator"); if(ModelState.IsValid) { // insert or update the issue record (no relationship) if (issue.IssueId == 0) db.Issues.Add(issue); else db.Entry(issue).State = System.Data.EntityState.Modified; db.SaveChanges(); // delete - delete current relationships if (issue.Creators != null) { issue.Creators = new List<Creator>(); db.Entry(issue).State = System.Data.EntityState.Modified; db.SaveChanges(); } // insert - get creators for many-to-many realtionship issue.Creators = db.Creators.Where(x => CreatorIds.Contains(x.CreatorId)).ToList(); db.Entry(issue).State = System.Data.EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } IssueEditModel issueEdit = new IssueEditModel{ Creators = db.Creators.ToList(), Issue = issue, }; return View(issueEdit); }
I can insert Issues , and I can insert a new issue.Creators without problems. But, when I try to delete the current issue.Creators , so I can insert new, issue.Creators ALWAYS null so that it never issue.Creators updated to an empty list. I do not understand this. issue.Creators has entries in it because when the code continues to insert new creators, I get the following:
Violation of PRIMARY KEY constraint 'PK__CreatorI__13D353AB03317E3D'. Cannot insert duplicate key in object 'dbo.CreatorIssues'. The statement has been terminated. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK__CreatorI__13D353AB03317E3D'. Cannot insert duplicate key in object 'dbo.CreatorIssues'. The statement has been terminated. Source Error: Line 59: issue.Creators = db.Creators.Where(x => CreatorIds.Contains(x.CreatorId)).ToList(); Line 60: db.Entry(issue).State = System.Data.EntityState.Modified; Line 61: db.SaveChanges(); Line 62: Line 63: return RedirectToAction("Index");
How do I get issue.Creators to accurately display current relationships so that I can delete them?
Update: working controller
[HttpPost] public ActionResult EditIssue ( Issue issue, int[] CreatorIds ) { if(CreatorIds == null) ModelState.AddModelError("CreatorIds", "Please specify at least one creator"); if(ModelState.IsValid) { // insert or update the issue record (no relationship) if (issue.IssueId == 0) db.Issues.Add(issue); else db.Entry(issue).State = System.Data.EntityState.Modified; db.SaveChanges(); // insert and update many to many relationship issue = db.Issues.Include("Creators").Where(x => x.IssueId == issue.IssueId).Single(); issue.Creators = db.Creators.Where(x => CreatorIds.Contains(x.CreatorId)).ToList(); db.Entry(issue).State = System.Data.EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } IssueEditModel issueEdit = new IssueEditModel{ Creators = db.Creators.ToList(), Issue = issue, }; return View(issueEdit); }