如何使用Entity Framework Code-First执行CRUD?

qua*_*els 6 database asp.net entity-framework entity-framework-4.1

我很难用EF Code-first更新和删除多对多的关系.

我有一个相当简单的模型:

    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; }
    }
Run Code Online (Sandbox Code Playgroud)

我一直无法弄清楚如何使用EF上下文更新多对多的实现.在我的isnert/update操作中,我有以下代码:

    [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);
    }
Run Code Online (Sandbox Code Playgroud)

我可以插入Issues,我可以插入新的issue.Creators没有问题.但是,当我试图删除当前,issue.Creators所以我可以插入新的,issue.Creators总是为空,所以它永远不会更新为空列表.我不明白这一点.issue.Creators有记录,因为当代码继续插入新的创建者时,我收到如下错误:

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");
Run Code Online (Sandbox Code Playgroud)

如何issue.Creators准确显示当前的关系,以便删除它们?

更新:工作控制器

    [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);
    }
Run Code Online (Sandbox Code Playgroud)

Ada*_*SFT 1

模型绑定器不会为您加载它们 - 来自视图的问题对象不会神奇地包含它们,除非您正确设置了绑定的所有内容。

如果没有看到您的视图,人们无法说出原因,但足以说明您必须加载它们,然后删除它们。您可以加载新的 issues 对象,然后执行 TryUpdateModel(issues) 将表单值更新到该模型中。然后删除每个 issues.Creators(如果这是预期的操作)


 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
   }




但是,如果您只是希望所有创建者从页面返回而不加载,请检查绑定到可枚举。有很多关于此的帖子,这里是一篇:ASP.NET MVC3 Model Binding using IEnumerable (Cannot infer type from)

如果存在这种关系,创建者应该通过加载问题来自动加载。您不需要仅加载创建者。加载您的完整模型以确保其正常工作,就像我在上面的编辑中所做的那样。您的代码“应该”工作正常,但您可能需要 .Include("Creators") 尝试以下操作:

var testIssue = from o in db.Issues.Include("Creators")
其中 o.IssueId == issues.IssueId
选择o;
foreach(testIssue.Creators 中的 var 创建者)
{
//检查创建者
}

这会让您知道“Creators”是否正确加载。