开发者

How to perform CRUD with Entity Framework Code-First?

开发者 https://www.devze.com 2023-03-12 06:03 出处:网络
I am having a really hard time updating and deleting many to many relationships with EF Code-first. I have a fairly simple Model:

I am having a really hard time updating and deleting many to many relationships with EF Code-first.

I have a fairly 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 have been unable to figure out how to update the many-to-many realtionship 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 new issue.Creators without a problem. But, when I am trying to delete the current issue.Creators so I can then insert the new ones, issue.Creators is ALWAYS null so it will never update to an empty list. I don't understand this. issue.Creators has records in it because when the code proceeds to insert the new creators, I get an error like this:

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 show the current relationships so 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);
    }


The model binder isn't loading them up for you - your issues object coming from the view won't magically contain them unless you setup everything up properly for binding.

Without seeing your view one can't say why, but suffice to say you'll have to load them up, then delete them. You can load a new issues object and then do TryUpdateModel(issues) to get the form values updated into that model. Then delete each issues.Creators (if thats 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
   }




However if you just want all of your creators to come back from the page without loading, check out binding to an enumerable. there are many posts out there on this, heres one: ASP.NET MVC3 Model Binding using IEnumerable (Cannot infer type from)

If the relationship is there, the Creators should automatically load just by loading the Issue. You don't need to load only the creators. Load your full model to be sure its working as I did in the edit above. Your code 'should' work ok but its possible you need to .Include("Creators") try this:

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 "Creators" is loading properly.


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

Once you have the duplicates you may need to go into the database and delete the rows manually

0

精彩评论

暂无评论...
验证码 换一张
取 消