How to execute CRUD with Entity Framework Code-First?

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); } 
+6
source share
2 answers

The model binder does not load them for you - your problem object coming from the view will not contain them magically unless you configure everything correctly for binding.

Without seeing your opinion, you cannot say why, but suffice it to say that you will have to download them and then delete them. You can load a new problem object and then try TryUpdateModel (problems) to get the form values ​​updated in this model. Then remove all problems. Creators (if this is the intended action)

 if(ModelState.IsValid) { var issueFromDb = db.Issues.Where(x => criteria here); bool updateSuccessful = TryUpdateModel(issueFromDb); foreach(var creator in issueFromDb.Creators) { //delete creator if thats what you want }
if(ModelState.IsValid) { var issueFromDb = db.Issues.Where(x => criteria here); bool updateSuccessful = TryUpdateModel(issueFromDb); foreach(var creator in issueFromDb.Creators) { //delete creator if thats what you want } 

However, if you just want all your creators to return from the page without loading, check the binding to the enumeration. there are many posts on this, heres one: binding an ASP.NET MVC3 model using IEnumerable (cannot deduce type from)

If a connection exists, the Creators should automatically load, just downloading the problem. You do not need to download only the creators. Download the full model to make sure that it works the way I did in the rule above. Your code "should" work fine, but maybe you need it. Turn on ("Creators") try the following:

  var testIssue = from o in db.Issues.Include ("Creators") 
 where o.IssueId == issue.IssueId 
 select o;
 foreach (var creator in testIssue.Creators)
 {
 // check creator
 }

this will let you know if the Creators load correctly.

+1
source

You are missing a key tag in the problem class (IssueId).

Once you have duplicates, you may need to enter the database and manually delete the rows

0
source

Source: https://habr.com/ru/post/890156/


All Articles