保存复杂的对象图(嵌套的一对多关系)



我有一个Code First EF 4.1模型,看起来像这样:

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

该模型的对象被序列化为JSON,在浏览器中使用jQuery进行处理。在jQuery中,这个对象图被实例化为Javascript对象。用户交互(添加/删除操作和添加/删除任务)会导致对Javascript对象的修改。当一个新的任务或动作对象被添加到图中时,它将得到ID = 0。当一个任务或动作对象被删除时,它会得到ui_status= " deleted "。在用户界面中发生保存事件时,修改后的Javascript对象被序列化为JSON并发送给' AssignmentController '。

我的问题是,我不知道什么是最好的方式来处理保存这个对象图。我一直遇到的问题得到错误像(1)'添加一个关系的实体是在删除状态是不允许的'或(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会处理这样的事情,因为大多数重要的应用程序都会遇到这样的问题。

自己解决了这个问题。我首先通过设置EntityState来更新对象图。/EntityState补充道。修改到每个对象。然后调用db.SaveChanges()并再次遍历所有对象来设置EntityState。必要时删除。然后再次调用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);
        }

希望这对将来遇到类似问题的人有所帮助。

最新更新