EF 4 - MVC3:保存复杂对象图(嵌套的一对多关系)

时间:2011-11-04 14:31:08

标签: asp.net-mvc-3 entity-framework

我有一个Code First EF 4.1模型,如下所示:

http://pct.staging.xeed.nl/images/model.png

此模型的对象被序列化为JSON,以便使用jQuery在浏览器中处理。在jQuery中,此对象图被实例化为Javascript对象。用户交互(添加/删除操作,添加/删除任务)导致Javascript对象的修改。将新任务或操作对象添加到图形时,它将获得ID = 0.删除任务或操作对象时,将获得ui_status =“已删除”。在用户界面中的保存事件后,修改后的Javascript对象被序列化为JSON并发送到'AssignmentController'。

我的问题是我无法弄清楚保存此对象图的最佳方法是什么。我继续遇到问题,例如:(1)'不允许与处于Deleted状态的实体添加关系'或者(2)'ObjectStateManager中已存在具有相同键的对象'。

(ad 1) - 尝试从任务中删除操作时出现此错误。

(ad 2) - 尝试一次保存2个或更多新对象时出现此错误。新对象都有ID = 0,这可能是导致此错误的原因。

这是我的代码:

        // POST: /Assignment/Save/assignment
    [HttpPost]
    public string Save([Bind(Exclude="date")] Assignment assignment )
    {
        string message;

        assignment.date = DateTime.Now;
        Session["currentAssignment"] = assignment;

        if (!User.Identity.IsAuthenticated)
        {
            return "Please Log in first.";
        }

        if (ModelState.IsValid)
        {
            assignment.username = User.Identity.Name;

            if (assignment.tasks != null)
            {
                foreach (var task in assignment.tasks.ToList())
                {
                    db.Tasks.Attach(task);

                    if (task.actions != null)
                    {
                        foreach (var action in task.actions.ToList())
                        {
                            db.Actions.Attach(action);

                            if ((task.ui_status == "deleted" || action.ui_status == "deleted"))
                            {
                                if (action.actionID > 0)
                                {
                                    db.Entry(action).State = EntityState.Deleted;

                                }
                                else
                                {   //object was deleted from a new object graph
                                    //just save it with ui_status="deleted", it will be deleted from the db next time around
                                }
                            }
                            else if (action.actionID == 0)
                            {
                                db.Entry(action).State = EntityState.Added;
                            }
                            else
                            {
                                db.Entry(action).State = EntityState.Modified;
                            }

                        }
                    }

                    if (task.ui_status == "deleted")
                    {
                        if (task.taskID > 0)
                        {
                            db.Entry(task).State = EntityState.Deleted;
                        }
                        else
                        {   //object was deleted from a new object graph
                            //just save it with ui_status="deleted", it will be deleted from the db next time around
                        }
                    }
                    else if (task.taskID== 0)
                    {
                        db.Entry(task).State = EntityState.Added;
                    }
                    else
                    {
                        db.Entry(task).State = EntityState.Modified;
                    }

                }
            }

            db.Assignments.Attach(assignment);
            db.Entry(assignment).State = assignment.assignmentID == 0 ? EntityState.Added : EntityState.Modified;
            db.SaveChanges();

            return js.Serialize(assignment);
        }
    }

我一直在努力解决这个问题,阅读所有帖子。我认为EF会照顾这样的事情,因为大多数非常重要的应用都会遇到这种情况。

对此的任何想法将不胜感激。

1 个答案:

答案 0 :(得分:1)

管理自己解决问题。我首先通过首先将EntityState.Added /EntityState.Modified设置为每个对象来更新对象图。然后我调用db.SaveChanges()并再次运行所有对象以在需要时设置EntityState.Deleted。然后我再次调用db.SaveChanges()。

这是代码:

        [HttpPost]
    public string Save([Bind(Exclude="date")] Assignment assignment )
    {
        string message;

        assignment.date = DateTime.Now;
        Session["currentAssignment"] = assignment;

        if (!User.Identity.IsAuthenticated)
        {
            return "Please Log in first.";
        }

        if (ModelState.IsValid)
        {
            assignment.username = User.Identity.Name;

            if (assignment.tasks != null)
            {
                foreach (var task in assignment.tasks.ToList())
                {
                    if (task.actions != null)
                    {
                        foreach (var action in task.actions.ToList())
                        {
                            db.Entry(action).State = action.actionID == 0 ? EntityState.Added : EntityState.Modified;
                        }
                    }
                    db.Entry(task).State = task.taskID == 0 ? EntityState.Added : EntityState.Modified;
                }
            }

            db.Entry(assignment).State = assignment.assignmentID == 0 ? EntityState.Added : EntityState.Modified;
            db.SaveChanges();

            if (assignment.tasks != null)
            {
                foreach (var task in assignment.tasks.ToList())
                {
                    if (task.actions != null)
                    {
                        foreach (var action in task.actions.ToList())
                        {
                            if ((task.ui_status == "deleted" || action.ui_status == "deleted"))
                            {
                                db.Entry(action).State = EntityState.Deleted; 
                            }
                        }
                    }
                    if (task.ui_status == "deleted")
                    {
                        db.Entry(task).State = EntityState.Deleted;
                    }
                }
            }
            db.SaveChanges();

            return js.Serialize(assignment);
        }

希望这可以帮助将来遇到类似问题的人。