Asp.net-Mvc

ASP.NET MVC / EF4 / POCO / Repository - 如何更新關係?

  • January 12, 2011

我在ReviewRecommendations之間有 1..* 關係。

我的模型的相關部分(也是 EF4 映射的 POCO):

public class Review
{
  public ICollection<Recommendations> Recommendations { get; set; }
}

Edit View上,我將Recommendations表示為一組複選框。

當我嘗試添加新的推薦作為編輯評論的一部分時(例如選中另一個框),什麼都沒有發生 - 我知道為什麼……

我使用“存根技術”來更新我的實體——例如,我用相同的鍵創建一個實體,將它附加到圖形上,然後執行ApplyCurrentValues. 但這僅適用於標量屬性,不適用於導航屬性。

我發現這個 StackOverflow 問題看起來不錯,但我正在嘗試解決如何讓它與 POCO/Repository(和 ASP.NET MVC - 分離上下文)一起使用。

因為我正在使用 POCO review.RecommendationsICollection<Recommendation>所以我不能這樣做review.Recommendations.Attach。我也沒有使用自我跟踪實體,所以我需要手動處理圖形/更改跟踪——直到現在這還不是問題。

因此,您可以視覺化場景:

審查:

  • 建議(ICollection<Recommendation>):

    • 推荐一個 ( Recommendation)
    • 推薦二(Recommendation

如果我在編輯視圖中,則其中兩個複選框已被選中。第三個(代表 RecommendationThree)未選中

但是,如果我選中該框,則上述模型將變為:

審查:

  • 建議(ICollection<Recommendation>):

    • 推荐一個 ( Recommendation)
    • 推薦二(Recommendation
    • 推薦三(Recommendation

所以我需要將 RecommendationThree 作為一個新實體附加到圖表中。

我需要隱藏欄位來比較現有實體的發布數據嗎?或者我應該將實體儲存在 TempData 中並將其與發布的實體進行比較?

編輯

為避免混淆,以下是完整的應用程序堆棧呼叫:

審查控制器

[HttpPost]
public ActionResult Edit(Review review)
{
  _service.Update(review); // UserContentService
  _unitOfWork.Commit();
}

使用者內容服務

public void Update<TPost>(TPost post) where TPost : Post, new()
{
  _repository.Update(post); // GenericRepository<Post>
}

GenericRepository - 用作GenericRepository<Post>

public void Update<T2>(T2 entity) where T2 : class, new()
{
  // create stub entity based on entity key, attach to graph.

  // override scalar values
  CurrentContext.ApplyCurrentValues(CurrentEntitySet, entity);
}

因此,需要為每個推薦呼叫Update(或Add或)儲存庫方法,具體取決於它是新的/修改的/刪除的。Delete

我接受了@jfar 的回答,因為他讓我走上了正確的軌道,但我想我會在此處添加一個答案以使其他人受益。

關係未更新的原因如下:

1)完全斷開的場景。ASP.NET = 無狀態,新的上下文更新了每個 HTTP 請求。

2)由 MVC(模型綁定)創建的編輯實體,但在圖中不存在。

3)當使用沒有更改跟踪的 POCO 時,.Attach對實體執行會將其添加到圖表中,但實體和任何子關係將保持不變。

4)我使用存根實體技巧並ApplyCurrentValues更新實體,但這僅適用於標量屬性,不適用於導航屬性。

所以 - 為了使上述工作,我必須明確設置EntityState對象(由於 自動發生ApplyCurrentValues以及導航屬性。

還有一個問題——我怎麼知道導航屬性是否被添加/修改/刪除?我沒有可比較的對象 - 只有一個我知道是“編輯”的實體,但我不知道編輯了什麼

所以最終的解決方案是這樣的:

[HttpPost]
public ActionResult Edit(Review review)
{
  var existingReview = _service.FindById(review.Id); // review is now in graph.
  TryUpdateModel(existingReview); // MVC equivalent of "ApplyCurrentValues" - but works for ALL properties - including navigationals
  _unitOfWork.Commit(); // save changed
}

就是這樣。我什至不需要我的_service.Update方法——因為我不再需要存根技巧了——因為評論在檢索圖中,並被ApplyCurrentValues替換為TryUpdateModel.

現在當然 - 這不是一個並發證明的解決方案。

如果我載入評論編輯視圖,並且在我點擊“送出”之前,其他人更改了評論,我的更改可能會失去。

幸運的是,我有一個“最後獲勝”的並發模式,所以這對我來說不是問題。

我喜歡 POCO,但是當你擁有無狀態環境 (MVC) 和無變更跟踪的組合時,他們會很痛苦。

使用分離的對像圖是我最喜歡的 EF 缺點。簡直是蛋疼。首先,您必須自己處理它。EF 不會幫你的。這意味著除了Review您還必鬚髮送一些有關所做更改的資訊。當您附加Review到上下文時,它將Review所有Recommendation所有關係設置為Unchanged狀態。ApplyCurrentValues僅適用於您已經找到的標量值。因此,您必須使用有關所做更改的附加資訊並將關係狀態設置為Added使用ObjectContext.ObjectStateManager.ChangeRelationshipState.

我個人放棄了這種方法,我首先從數據庫載入對像圖,將我的更改合併到附加圖中並保存它。

我在這裡更深入地回答了類似的問題。

引用自:https://stackoverflow.com/questions/4653834