2011-11-04 77 views
0

我有一個代碼優先EF 4.1模型看起來像這樣:EF 4 - MVC3:保存複雜對象圖(嵌套一個一對多關係)

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

該模型的目的是序列化到使用jQuery在瀏覽器中處理JSON。在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會照顧這樣的事情,因爲大多數不重要的應用程序都會遇到這種情況。

對此的任何想法將不勝感激。

+0

如果你解決了這個問題,你應該把它作爲你自己問題的答案貼出來,然後接受它,這樣人們就不會試圖回答這個問題,也不會讓每個人更清楚解決方案。 – Joakim

+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); 
     } 

希望這有助於任何人跑進今後發生類似的問題。