(又翻出來一篇一年多以前的半成品,趕緊給補充完整放出來。)
最近終于得以試用Linq to Sql了,剛開始用,感覺還挺不錯,因為一切都顯得很簡單。也許是我還不太熟悉,所以也有不少的困惑。別的先不說,只說一個:“有狀態的”實體類。
Linq to Sql 所創建出來的實體類本身并不是有狀態的,有狀態的是DataContext。但是正是這個有狀態的DataContext,造成了實體類也帶上了“狀態”。對于一般的桌面應用,或者是結合得比較緊密的Web程序,這還不是什么太大的問題。但是如果我們考慮一個分離得比較充分的N層結構,比如說通過WebService提供數據層或者應用層的服務,這就有問題了。例如有一個ModifyCustomer的WebMethod:
[WebMethod]
public void ModifyCustomer(Customer customer)
{
// 
}
由于Customer是反序列化得來的,并不在DataContext的監管中。因此在調用DataContext.SubmitUpdate()的時候,這些對象是無法進行更新操作的。同時DataContext并沒有提供一個直接的方法,來進行Update的操作。
這個問題在英文網上還真是有一些討論,解決的方法就是用DataContext.Attach。在這之下還有兩種方案:
1、
[WebMethod]
public void ModifyCustomer(Customer customer)
{
//
XXDataContext dtx = new XXDataContext();
dtx.Attach(customer, true);
dtx.SubmitChanges();
}
[WebMethod]
public void ModifyCustomer(Customer modified, Customer original)
{
// 
XXDataContext dtx = new XXDataContext();
dtx.Attach(modified, original);
dtx.SubmitChanges();
}
然而這兩種方法都有各自的一些缺陷。首先說第一種方法,這種方法由于把該實體類強制設置為“已修改”狀態,于是就要求該實體類要么有一個時間戳字段,要么就是要求該實體類所有字段都不進行“更新沖突檢查”。顯然后者是難以接受的,尤其是在一些較為關鍵的數據表當中,一旦沖突后還允許更新會出現災難性后果。而前者則要求改動數據庫的物理設計,有點為難沒有數據庫物理設計權限的開發人員。而且即使這樣改動,似乎也只能夠保證檢測出任意的沖突,而在互不相干的改動中是不能認為沒有發生沖突的。舉個例子:
| Client | FieldA | FieldB | TimeStamp |
| (Original) | A | B | 0 |
| User1 | A1 | 1 | |
| User2 | B2 | Conflict! |
如果兩個客戶端都在對Customer表進行修改,其中User1的客戶端修改了FieldA,User2的客戶端隨后修改了FieldB,這個時候用時間戳判斷法,就會被系統判定為沖突。因為在強行向DataContext中塞入一個User對象的時候,這個User對象的所有屬性并沒有有效的“原值”,或者說認為所有屬性都被修改了。數據庫更不可能有修改前數值的記錄,因此對于DataContext來說,只能當作所有值都修改了,因此自然引發了沖突。但是實際上我們可以看出來,這種情況下并沒有任何實際上的沖突,是可以更新的。
而第二種方式呢,看起來可以解決上面的這一個問題。但是,即使拋開需要多傳一份對象不說,也會造成客戶端變得比較復雜。我們可以想象,客戶端中調用Web服務獲取原始對象的代碼,與更新對象的代碼很可能根本就不在一個函數內,甚至不在一個調用堆棧上。比如說我們想象一下,客戶端實際上也是一個網站,某個網頁需要列出當前用戶的一些信息,并允許瀏覽者對某些屬性進行一些修改。那么很明顯,獲取原始用戶對象的Web服務調用是在第一次頁面訪問上的,而更新用戶對象則是在第二次訪問過程中的。因此,我們必須在第一次訪問的時候,將所有可能會被更新的對象都保存到Session里面,以供更新的時候將這些原始對象回傳到服務端。這樣做會極大地增加客戶端設計的復雜度,也不見得很好。
更麻煩的地方是,Linq to sql里面的每一個對象都是設計器自動生成的,那些打上去的標記一不小心就會被丟掉!在我看來,LinqToSql的設計以及自動代碼生成過程,對于WebService/WCF的開發來說,還是比較不友好的。不知道各位以為如何?
P.S.: EntityFramework我也小試了一下,有些東西確是比Linq To Sql好用一些,不過似乎這個問題還是沒有很好的解決,如果有這方面經驗的請賜教。此外,我覺得EntityFramework取消了Log機制,使非常可惜的一件事情,使得一些Sql性能方面的調試不太方便了,恢復到了要用Sql profiler的時代。而我在用Linq to sql做開發的時候,設計了一套能即時開關,并且可設置針對某一特定Session還是所有訪問的Trace系統,使得有問題發生時,可以立即在線上查看,而不需要將整個環境(包括數據庫相關部分)Dump下來在調試環境下恢復,然后再進行調試(包括Debug和Sql profiler)。可是在EntityFramework下面,這種方式似乎就不太好使了。
___________________
P.S.: 發布到首頁還是有Bug,就是保存草稿也算時間。


浙公網安備 33010602011771號