ASP.NET MVC / EF4 / POCO / Repository - 如何更新關係?
我在Review和Recommendations之間有 1..* 關係。
我的模型的相關部分(也是 EF4 映射的 POCO):
public class Review { public ICollection<Recommendations> Recommendations { get; set; } }在Edit View上,我將Recommendations表示為一組複選框。
當我嘗試添加新的推薦作為編輯評論的一部分時(例如選中另一個框),什麼都沒有發生 - 我知道為什麼……
我使用“存根技術”來更新我的實體——例如,我用相同的鍵創建一個實體,將它附加到圖形上,然後執行
ApplyCurrentValues. 但這僅適用於標量屬性,不適用於導航屬性。我發現這個 StackOverflow 問題看起來不錯,但我正在嘗試解決如何讓它與 POCO/Repository(和 ASP.NET MVC - 分離上下文)一起使用。
因為我正在使用 POCO
review.Recommendations,ICollection<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.我個人放棄了這種方法,我首先從數據庫載入對像圖,將我的更改合併到附加圖中並保存它。
我在這裡更深入地回答了類似的問題。