天天看點

從一個案例看MVC中DataContext和UpdateModel的工作原理(詳解UpdateModel/SubmitChanges錯誤)

昨天遇到一段棘手的程式,嘗試了各種方法,忽而在SubmitChanges的時候沒反應(無錯誤,也不更新),忽而發生ChangeConflict,經過幾個小時,終于大緻理清了思路,也順便把DataContext/UpdateModel/SubmitChanges給搞得更明白了一些,特此分享。

先大緻看看代碼:

xxController

{

AgileRepository _repAgile = new AgileRepository(); //這裡邊是SubmitChanges/DateContext/Tables等屬性,可取出下面提到的story

SFCRepository _repSFC = new SFCRepository(); //相同,可取出下面提到的UDCs

[HttpPost]

public ActionResult Edit(int id, FormCollection collection)

Story story = _repAgile.GetStoryAt(id);

try

UpdateModel(story);

foreach (var udc in story.UDCs)

UpdateModel(udc, udc.ID.ToString("D6"));

}

_repAgile.Save();

_repSFC.Save(); //這裡也是

...

之是以出現紅色的_repSFC.Save(),是因為story的一個屬性List<IUDC> UDCs,也是需要在這個頁面被更新的内容(在View中有控件與其對應),而它的Get過程最初是:

class Story

public List<IUDC> UDCs 

get 

SFCRepository rep = new SFCRepository(); 

return rep.GetUDCs().Where(...); 

set { } 

這裡藍色的rep和前面紅色的rep不是同一個,是以如果從藍色rep的當中取出UDCs并進行UpdateModel,而對另外一個無關的紅色rep儲存,什麼也不會發生;而如果兩者都取出UDCs并都曾經被UpdateModel,在Save(内部執行了SubmitChanges)的時候,會報出confilict changes exception,這個Exception極其麻煩而且不透明Google/MSDN上能找到一些資料但很多不工作。

其實,全部解決方法的秘訣其實就是:讓取出資料的那個Repository執行Save操作(或者從内部看,是讓取出資料的DataContext執行SubmitChanges操作)。

藍色rep的是個局部變量,活不到Save的時候了,隻能用紅色的那個rep了。代碼改為下面這個就好了:

SFCRepository _repSFC = new SFCRepository(); //下面取資料/儲存的都是它。

_repSFC.GetUDCsFor(story); //在這裡邊讓_repSFC的DataContext取資料。

_repSFC.Save(); //這裡會完成存儲。

盡管能用了,但這段代碼很不好,尤其GetUDCsFor,調用的位置很生硬,不好讀也很容易出錯。

最終還是這樣最好:

外面:

UpdateModel(udc, udc.ID.ToString("D6")); //Update的

story.SaveUDCs(); // 這個調用看着順眼。

裡邊:

public partial class Story : IUDCable, IItem

private SFCRepository _repSFC = new SFCRepository(); //這個方案裡取資料/儲存的都是它。_repSFC不再是個局部變量,生命周期正好和UDCs相同。

public void SaveUDCs()

_repSFC.Save(); // 在這裡儲存

_repSFC.GetUDCOf(this, ref _udcs); //取資料。

return _udcs; 

後面本來不應該再把_udcs傳入GetUDCOf了,直接但因為别的IUDCable也要用到,是以封裝了一個函數。

這個方案,取資料/存資料的都是Story内部的_repSFC,而且封裝性更好,是最終結果。

最後重複一下在這種場景中發生問題時的解決方法的秘訣其實就是:讓取出資料的那個Repository執行Save操作(或者從内部看,是讓取出資料的DataContext執行SubmitChanges操作)。

本文轉自火星人陳勇 51CTO部落格,原文連結:http://blog.51cto.com/cheny/1100087

繼續閱讀