1.1、
在Linq to SQL中要?jiǎng)h除一行記錄,官方的例子教我這樣做
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(); |
} |
可是,馬上我的程序支持到這里就跑不動(dòng)了,第二行有異常。
為什么呢?
看一下MSDN關(guān)于Signle方法的說(shuō)明:
哦,問(wèn)題出在這里,Single要求符合條件的記錄有且只有一行,否則就會(huì)發(fā)飆。
從以前的學(xué)習(xí)中我知道,調(diào)用Single方法時(shí)DataContent即刻從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)庫(kù),而這個(gè)時(shí)間如果獲取不到auid="111-11-1111"的記錄,返回的記錄集是空的,就引發(fā)了上面的異常。
1.2、
我想找一個(gè)方法,讓Linq不執(zhí)行Select而直接Delete,搜完了MSDN,翻完了《LINQ in Action》,沒(méi)有。
后來(lái)我想,既然Linq to sql有“延遲加載”功能,那么刪除時(shí)能不能也“延遲”呢,我嘗試這樣:
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(); |
} |
我的程序被馴服了,不在這里發(fā)飆了。
難道Linq to sql真如我所想的直接執(zhí)行delete from Authors where au_id='111-11-1111'這樣的語(yǔ)句了嗎?
2.1
帶著上面的疑問(wèn),一步一步跟蹤查看DataContent的Log。我發(fā)現(xiàn),在用Single()方法來(lái)刪除的時(shí)候,如果不出現(xiàn)異常,提交的SQL語(yǔ)句是這樣的。
這里可以很清楚看出,Linq先從數(shù)據(jù)庫(kù)中取出記錄,然后再Delete。我們知道主鍵就可以確定表中唯一的記錄了,可是為什么刪除條件要把所有的列都加進(jìn)去呢?老趙在這個(gè)post(在Linq to Sql中管理并發(fā)更新時(shí)的沖突[1],[2],[3] )里很詳細(xì)的說(shuō)明了這個(gè)問(wèn)題。
我的目的只是要?jiǎng)h除一行記錄,可是這樣使用Linq to sql卻先從數(shù)據(jù)庫(kù)里取出來(lái)再刪除,實(shí)在是多此一舉。那Code 2中的方法又是如何運(yùn)行的呢?我們?cè)賮?lái)跟蹤它。
2.2
為了更好的說(shuō)明問(wèn)題,我把Code 1中的代碼改一下,另外還在數(shù)據(jù)庫(kù)中預(yù)先添加二行記錄,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語(yǔ)句時(shí),StartWith會(huì)生成Like '111-11-111%'匹配)。
現(xiàn)在再下這段代碼執(zhí)行的Log:
SELECT [t0].[au_id], [t0].[au_lname], [t0].[au_fname], [t0].[phone], [t0].[address], [t0].[city], [t0].[state], [t0].[zip], [t0].[contract] |
FROM [dbo].[authors] AS [t0] |
WHERE [t0].[au_id] LIKE @p0 |
-- @p0: Input VarChar (Size = 11; Prec = 0; Scale = 0) [111-11-111%] |
-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.21022.8 |
DELETE FROM [dbo].[authors] WHERE ([au_id] = @p0) AND ([au_lname] = @p1) AND ([au_fname] = @p2) AND ([phone] = @p3) AND ([address] = @p4) AND ([city] = @p5) AND ([state] = @p6) AND ([zip] = @p7) AND ([contract] = 1) |
-- @p0: Input VarChar (Size = 11; Prec = 0; Scale = 0) [111-11-1111] |
-- @p1: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p2: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p3: Input Char (Size = 12; Prec = 0; Scale = 0) [qqq ] |
-- @p4: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p5: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p6: Input Char (Size = 2; Prec = 0; Scale = 0) [qq] |
-- @p7: Input Char (Size = 5; Prec = 0; Scale = 0) [22222] |
-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.21022.8 |
DELETE FROM [dbo].[authors] WHERE ([au_id] = @p0) AND ([au_lname] = @p1) AND ([au_fname] = @p2) AND ([phone] = @p3) AND ([address] = @p4) AND ([city] = @p5) AND ([state] = @p6) AND ([zip] = @p7) AND ([contract] = 1) |
-- @p0: Input VarChar (Size = 11; Prec = 0; Scale = 0) [111-11-1112] |
-- @p1: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p2: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p3: Input Char (Size = 12; Prec = 0; Scale = 0) [qqq ] |
-- @p4: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p5: Input VarChar (Size = 3; Prec = 0; Scale = 0) [qqq] |
-- @p6: Input Char (Size = 2; Prec = 0; Scale = 0) [qq] |
-- @p7: Input Char (Size = 5; Prec = 0; Scale = 0) [22222] |
很失望,和我期待的結(jié)果不一樣。
在這個(gè)測(cè)試中,DataContent先把所有符合條件的記錄全部取回來(lái),再一個(gè)一個(gè)Delete。
如果要?jiǎng)h除的有10000條記錄的話,天都黑了...
這點(diǎn),不得不說(shuō)Linq to sql有點(diǎn)笨了。
3
解決?
只能繞個(gè)圈子了。
DataContext提供有ExecuteCommend方法,可能使用此方法直接執(zhí)行SQL命令。比如這樣:
Code 4: |
using (PubsDataContext pubsContent = new PubsDataContext()) |
{ |
pubsContent.Log = Console.Out; |
pubsContent.ExecuteCommand("delete from Authors where au_id like '111-11-111%'"); |
} |
也可以通過(guò)DataContext.Connection取得當(dāng)前的數(shù)據(jù)庫(kù)連接,然后再通過(guò)DBCommend來(lái)提交自己的SQL語(yǔ)句,
或者寫(xiě)個(gè)存儲(chǔ)過(guò)程來(lái)負(fù)責(zé)刪除。
4
LINQ,語(yǔ)言級(jí)集成查詢(Language INtegrated Query)
明顯,強(qiáng)在查詢,刪除就弱弱點(diǎn) ;-)...
聯(lián)系客服