1.1、
Code1: using (PubsDataContext pubsContent = new PubsDataContext()) { pubsContent.Log = Console.Out; Author author = pubsContent.Authors.Single(a => a.au_id == "111-11-1111"); pubsContent.Authors.DeleteOnSubmit(author); pubsContent.SubmitChanges(); }
可是,馬上我的程序支持到這裡就跑不動了,第二行有異常。
為什麼呢?
看一下MSDN關於Signle方法的說明:
哦,問題出在這裡,Single要求符合條件的記錄有且只有一行,否則就會發飙。
從以前的學習中我知道,調用Single方法時DataContent即刻從數據庫中獲取數據庫,而這個時間如果獲取不到auid="111-11-1111"的記錄,返回的記錄集是空的,就引發了上面的異常。
1.2、
我想找一個方法,讓Linq不執行Select而直接Delete,搜完了MSDN,翻完了《LINQ in Action》,沒有。
後來我想,既然Linq to sql有“延遲加載”功能,那麼刪除時能不能也“延遲”呢,我嘗試這樣:
Code 2: using (PubsDataContext pubsContent = new PubsDataContext()) { var q = from a in pubsContent.Authors where a.au_id == "111-11-1111" select a; pubsContent.Log = Console.Out; pubsContent.Authors.DeleteAllOnSubmit(q); pubsContent.SubmitChanges(); }我的程序被馴服了,不在這裡發飙了。
難道Linq to sql真如我所想的直接執行delete from Authors where au_id='111-11-1111'這樣的語句了嗎?
2.1
帶著上面的疑問,一步一步跟蹤查看DataContent的Log。我發現,在用Single()方法來刪除的時候,如果不出現異常,提交的SQL語句是這樣的。
這裡可以很清楚看出,Linq先從數據庫中取出記錄,然後再Delete。我們知道主鍵就可以確定表中唯一的記錄了,可是為什麼刪除條件要把所有的列都加進去呢?老趙在這個post(在Linq to Sql中管理並發更新時的沖突[1],[2],[3] )裡很詳細的說明了這個問題。
我的目的只是要刪除一行記錄,可是這樣使用Linq to sql卻先從數據庫裡取出來再刪除,實在是多此一舉。那Code 2中的方法又是如何運行的呢?我們再來跟蹤它。
2.2
為了更好的說明問題,我把Code 1中的代碼改一下,另外還在數據庫中預先添加二行記錄,au_id分別為111-11-1111、111-11-1112
Code 3: using (PubsDataContext pubsContent = new PubsDataContext()) { pubsContent.Log = Console.Out; var q = from a in pubsContent.Authors where a.au_id.StartsWith("111-11-111") select a; pubsContent.Authors.DeleteAllOnSubmit(q); pubsContent.SubmitChanges(); }把==條件換成了StartsWith(生成SQL語句時,StartWith會生成Like '111-11-111%'匹配)。
現在再下這段代碼執行的Log:
SELECT [t0].[au_id], [t0].[au_lname], [t0].[au_fname], [t0].[phone],很失望,和我期待的結果不一樣。
在這個測試中,DataContent先把所有符合條件的記錄全部取回來,再一個一個Delete。
如果要刪除的有10000條記錄的話,天都黑了...
這點,不得不說Linq to sql有點笨了。
3
解決?
只能繞個圈子了。
DataContext提供有ExecuteCommend方法,可能使用此方法直接執行SQL命令。比如這樣:
Code 4: using (PubsDataContext pubsContent = new PubsDataContext()) { pubsContent.Log = Console.Out; pubsContent.ExecuteCommand("delete from Authors where au_id like '111-11-111%'"); }也可以通過DataContext.Connection取得當前的數據庫連接,然後再通過DBCommend來提交自己的SQL語句,
或者寫個存儲過程來負責刪除。
4
LINQ,語言級集成查詢(Language INtegrated Query)
明顯,強在查詢,刪除就弱弱點 ;-)...