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

时间:2011-06-09 15:08:23

标签: asp.net database 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; }
    }

我一直无法弄清楚如何使用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);
    }

我可以插入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");

如何让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);
    }

2 个答案:

答案 0 :(得分:1)

模型活页夹没有为您加载 - 除非您正确设置所有内容以进行绑定,否则来自视图的问题对象不会神奇地包含它们。

如果没有看到你的观点,就不能说出原因,但足以说你必须加载它们,然后删除它们。您可以加载新的问题对象,然后执行TryUpdateModel(问题)以将表单值更新到该模型中。然后删除每个issue.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") 
where o.IssueId == issue.IssueId 
select o;
foreach(var creator in testIssue.Creators)
{
//check creator
}

这将告诉您“创作者”是否正确加载。

答案 1 :(得分:0)

您缺少问题类(IssueId)中的密钥标记。

获得重复项后,您可能需要进入数据库并手动删除行