2014-01-30 42 views
1

我正在開發WebAPI v2操作方法以使用實體框架6將對象圖的更新持久化,我有點不確定我的語法是否正確。 項目是我的根類型,其中包含問題的集合。該項目已經存在,但帖子行動可能需要提交更改項目性質,改變現有問題的,並添加新問題的。如何使用實體框架在WebAPI操作中提交對象圖

我已經在下面顯示和評論,但更新需要大量的工作時,我想,認爲有一個輔助方法,可以爲我做一些這樣的代碼:

[System.Web.Http.Route("{id:int}")] 
public HttpResponseMessage Post(int id, [FromBody]Project project) 
{ 
    // Validate the submitted project 
    if (!ModelState.IsValid) 
     return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); 

    // Fetch the existing project. This is here to perform row-level 
    // security check. The user will have logged on and this confirms the 
    // organisation they work for. Behind the scenes I will compound the 
    // query below to include a check for organisation id. This prevents 
    // users submitted any project id and overwriting data that isn't theirs. 
    // Would it make the pattern below better if this only executed a .Count()? 
    // Would that mean the context would then be tracking the project before 
    // the update? 
    var existingProject = _context.Projects.Include("Questions").FirstOrDefault(p => p.ProjectId == id); 
    if (existingProject == null) 
     return Request.CreateErrorResponse(HttpStatusCode.NotFound, ModelState); 

    // Copy model updates to the project 
    var projectEntry = _context.Entry(existingProject); 
    projectEntry.CurrentValues.SetValues(project); 

    // Now work out which questions are updates or additions 
    foreach (var question in project.Questions) 
    { 
     // No id so must be an addition 
     if (question.QuestionId == 0) 
     { 
      existingProject.Questions.Add(question); 
     } 
     else 
     { 
      // Fetch the existing question so we can copy values 
      var existingQuestion = existingProject.Questions.FirstOrDefault(q => q.QuestionId == question.QuestionId); 
      if (existingQuestion == null) 
      { 
       // In a single user system finding ourselves here should not 
       // be possible. Ideally we'll need to do some concurrency 
       // when other users make updates or have some record locking 
       // mechanism. 
       existingProject.Questions.Add(question); 
      } 
      else 
      { 
       var questionEntry = _context.Entry(existingQuestion); 
       questionEntry.CurrentValues.SetValues(question); 
      } 
     } 
    } 

    _context.SaveChanges(); 

    return Request.CreateResponse(HttpStatusCode.Created, project); 
} 

更新:我也已經意識到提交後,我甚至沒有處理刪除問題的,但看看我的解決方案,目前不會被照顧,所以我將不勝感激,被認爲是太。

+0

我目前面臨同樣的問題。你有沒有找到一個合理的刪除方法的答案? – John

+0

我嘗試過[GraphDiff](https:// github。com/refactorthis/GraphDiff),但決定繼續使用類似於上面給出的代碼的代碼(有些時候會交叉)支持這種開箱即用的功能,而且我的用例目前相當獨立。 – Phil

+0

我通過在這裏創建一個自定義通用可跟蹤實體解決方案解決了我的問題http://stackoverflow.com/questions/26681390/json-net-serialise-custom-collection-with-additional-properties-and-on-add-to-浩 – John

回答

0

看起來你正在尋找Trackable-Entities,這裏的維基標題:

可跟蹤實體支持跟蹤對象圖中改變的實體,讓他們可以發送到Web服務,並在堅持單程往返單筆交易。此功能作爲一組NuGet packages提供。

服務器端NuGet包提供ApplyChanges擴展方法給實體框架的DbContext類,該類遍歷一個或多個對象圖,通知實體框架每個實體的更改狀態。在致電SaveChanges後,您可以在將所有實體的狀態返回給客戶端之前將其設置爲Unchanged,然後致電AcceptChanges。還有一個LoadRelatedEntities方法,您可以調用該方法以在添加的實體上填充引用屬性。

客戶端側的封裝提供了一種變化跟蹤器用於標記實體Added,或ModifiedDeleted每當它們被插入,修改或在一個對象圖的任何水平除去。要開始跟蹤更改,只需將一個或多個實體添加到ChangeTrackingCollection並將Tracking屬性設置爲true。如果要保留更改,可以在更改跟蹤器上調用GetChanges以僅獲取更改的項目,以便不需要將未更改的實體發送到服務器,從而節省帶寬並提高性能。可跟蹤實體將關聯實體,以便您可以通過調用MergeChanges將更新的實體合併回原始對象圖中。雖然您可以手動設置實體上的TrackingState,但更改跟蹤器會部署爲便攜式類庫,因此您可以從任何.NET客戶端(包括桌面或移動應用程序)使用它。

要考慮的另一個項目是Breeze#