導(dǎo)言:
在前面的教程里,我們考察了如何為SqlDataSource控件添加插入、更新、刪除功能。簡(jiǎn)而言之,就是為其nsertCommand, UpdateCommand和DeleteCommd屬性賦以相應(yīng)的INSERT,UPDATE和DELETESQL語(yǔ)句,并將相應(yīng)的參數(shù)放置在InsertParameters>, UpdateParameters>和DeleteParameters>標(biāo)簽里。我們可以手工書寫這些代碼,也可以通過(guò)在設(shè)置數(shù)據(jù)源向?qū)Ю飭螕簟案呒?jí)”按鈕,選擇“自動(dòng)生成INSERT, UPDATE和DELETE命令”,自動(dòng)的生成語(yǔ)句。
在“高級(jí)SQL生成選項(xiàng)”對(duì)話框里有個(gè)“使用開(kāi)放式并發(fā)”選項(xiàng)(見(jiàn)圖1)。當(dāng)
選擇該項(xiàng)后,數(shù)據(jù)庫(kù)中的數(shù)據(jù)在自上一次成功保存以來(lái)沒(méi)發(fā)生任何改變的情況下,才能成功地執(zhí)行更新或刪除操作。
圖1:在“高級(jí)SQL生成選項(xiàng)”對(duì)話框添加開(kāi)放式并發(fā)支持
在實(shí)現(xiàn)開(kāi)放式并發(fā)教程路我們探討了開(kāi)放式并發(fā)控制的基本原理以及如何對(duì)ObjectDataSource控件使用開(kāi)放式并發(fā)。在本教程我們看如何對(duì)SqlDataSource控件使用開(kāi)放式并發(fā)。
新的開(kāi)放式并發(fā)
在一個(gè)允許多人同時(shí)編輯或刪除相同數(shù)據(jù)的應(yīng)用程序里,有這種可能:一個(gè)人修改后的記錄意外地被另一個(gè)人修改的記錄所覆蓋。在Implementing Optimistic Concurrency 這篇教程我們例舉過(guò)這樣的例子:
例如,假設(shè)兩個(gè)用戶,Jisun和Sam,都訪問(wèn)我們的應(yīng)用軟件中的一個(gè)頁(yè)面,這個(gè)頁(yè)面允許訪問(wèn)者通過(guò)一個(gè)GridView控件更新和刪除產(chǎn)品數(shù)據(jù)。他們都同時(shí)點(diǎn)擊GridView控件中的Edit按鈕。Jisun把產(chǎn)品名稱更改為“Chai Tea”并點(diǎn)擊Update按鈕,實(shí)質(zhì)結(jié)果是向數(shù)據(jù)庫(kù)發(fā)送一個(gè)UPDATE語(yǔ)句,它將更新此產(chǎn)品的所有可修改的字段(盡管Jisun實(shí)際上只修改了一個(gè)字段:ProductName)。在這一刻,數(shù)據(jù)庫(kù)中包含有這條產(chǎn)品記錄“Chai Tea”—種類為Beverages、供應(yīng)商為Exotic Liquids、等該產(chǎn)品的詳細(xì)信息。然而,在Sam的屏幕中的GridView里,當(dāng)前編輯行里顯示的產(chǎn)片名稱依舊是“Chai”。在Jisun的更改被提交后片刻,Sam把種類更改為“Condiments”并點(diǎn)擊Update按鈕。這個(gè)發(fā)送到數(shù)據(jù)庫(kù)的UPDATE語(yǔ)句的結(jié)果是將產(chǎn)品名稱更改為“Chai”、CategoryID字段的值是種類Beverages對(duì)應(yīng)的ID,等等。Jisun所作的對(duì)產(chǎn)品名稱的更改就被覆蓋了。
圖2展示了這些連續(xù)的事件
圖2:當(dāng)兩個(gè)用戶同時(shí)更新一條記錄,則存在一個(gè)用戶的更改覆蓋另一個(gè)的更改的可能性
為了應(yīng)對(duì)這種可能性,我們必須執(zhí)行某種并發(fā)控制。本文的焦點(diǎn)——開(kāi)放式并發(fā)控制便是其中之一,它適合于這種情況:假定并發(fā)沖突只是偶爾發(fā)生,絕大多數(shù)的時(shí)候并不會(huì)出現(xiàn)。 當(dāng)發(fā)生一個(gè)沖突時(shí),僅僅簡(jiǎn)單的告知用戶,他所作的更改不能保存,因?yàn)閯e的用戶已經(jīng)修改了同一條記錄。
注意:對(duì)應(yīng)用程序來(lái)說(shuō),假定并發(fā)沖突經(jīng)常發(fā)生,且無(wú)法容忍。在這種情況下最后用保守式并發(fā)控制。關(guān)于保守式并發(fā)控制的更多討論,請(qǐng)參考Implementing Optimistic Concurrency 教程。
開(kāi)放式并發(fā)控制的作用在于:確保要更新或刪除的記錄的值與該記錄在updating or deleting階段的值相同。比如,例如,當(dāng)在一個(gè)可編輯的GridView里點(diǎn)擊編輯按鈕時(shí),該記錄的原始值從數(shù)據(jù)庫(kù)中讀取出來(lái)并顯示在TextBox和其他Web控件中。這些原始的值保存在GridView里。隨后,當(dāng)用戶完成他的修改并點(diǎn)擊更新按鈕,這些原始值加上修改后的新值發(fā)送到業(yè)務(wù)邏輯層,然后到數(shù)據(jù)訪問(wèn)層。數(shù)據(jù)訪問(wèn)層必定發(fā)出一個(gè)SQL語(yǔ)句,它將僅僅更新那些開(kāi)始編輯時(shí)的原始值根數(shù)據(jù)庫(kù)中的值一致的記錄。圖3描述了這些事件發(fā)生的順序。
圖3:為了更新或刪除能夠成功,原始值必須與數(shù)據(jù)庫(kù)中相應(yīng)的值一致
有多種方法可以實(shí)現(xiàn)開(kāi)放式并發(fā)控制(查看Peter A. Bromberg的文章 Optmistic Concurrency Updating Logic,從摘要中看到許多選擇)。SqlDataSource控件使用該方法(就像數(shù)據(jù)訪問(wèn)層中ADO.NET類型的數(shù)據(jù)集使用的那樣)擴(kuò)展WHERE字句,用以包含用來(lái)做比較的原始值。例如下面的UPDATE語(yǔ)句,當(dāng)當(dāng)前數(shù)據(jù)庫(kù)中的值與GridView中開(kāi)始編輯的原始值一致才更新某個(gè)產(chǎn)品的名稱和價(jià)格。@ProductName 和 @UnitPrice參數(shù)包含的是用戶輸入的新值,而參數(shù)@original_ProductName 和 @original_UnitPrice則包含最初點(diǎn)擊編輯按鈕時(shí)加載到GridView中的值:
UPDATE Products SET
ProductName = @ProductName,
UnitPrice = @UnitPrice
WHERE
ProductID = @original_ProductID AND
ProductName = @original_ProductName AND
UnitPrice = @original_UnitPrice
就像我們將在本教程看到的一樣,使SqlDataSource能實(shí)現(xiàn)開(kāi)放式并發(fā)控制是很簡(jiǎn)單的事情。
第一步:創(chuàng)建一個(gè)支持開(kāi)放式并發(fā)的SqlDataSource控件
打開(kāi)SqlDataSource文件夾中的OptimisticConcurrency.aspx頁(yè)面,從工具箱拖一個(gè)SqlDataSource控件到頁(yè)面,設(shè)置其ID為ProductsDataSourceWithOptimisticConcurrency。在其智能標(biāo)簽里點(diǎn)“設(shè)置數(shù)據(jù)源”,數(shù)據(jù)庫(kù)選為“NORTHWINDConnectionString”,點(diǎn)下一步。
圖4:選“ORTHWINDConnectionString”數(shù)據(jù)庫(kù)
在此例子里,我們將添加一個(gè)GridView控件以編輯表Products。所以在“Configure the Select Statement”界面選擇從表Products返回ProductID, ProductName, UnitPrice和Discontinued列,如圖5所示:
圖5:從表Products返回ProductID, ProductName, UnitPrice和Discontinued列
然后,點(diǎn)“高級(jí)”按鈕,打開(kāi)“Advanced SQL Generation Options”對(duì)話框,選擇“Generate INSERT, UPDATE, and DELETE statements”和“Use optimistic concurrency”2項(xiàng),點(diǎn)“OK”(見(jiàn)圖1)。再點(diǎn)下一步、完成,結(jié)束設(shè)置。
完成設(shè)置數(shù)據(jù)源向?qū)Ш?,花幾分鐘查看DeleteCommand和UpdateCommand屬性,以及DeleteParameters和UpdateParameters標(biāo)簽。最快的方法是切換到“源模式”直接在頁(yè)面代碼查看,你會(huì)看到UpdateCommand的值像這樣:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
同時(shí)在UpdateParameters>標(biāo)簽里有7個(gè)參數(shù):
asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ...>
DeleteParameters>
...
/DeleteParameters>
UpdateParameters>
asp:Parameter Name="ProductName" Type="String" />
asp:Parameter Name="UnitPrice" Type="Decimal" />
asp:Parameter Name="Discontinued" Type="Boolean" />
asp:Parameter Name="original_ProductID" Type="Int32" />
asp:Parameter Name="original_ProductName" Type="String" />
asp:Parameter Name="original_UnitPrice" Type="Decimal" />
asp:Parameter Name="original_Discontinued" Type="Boolean" />
/UpdateParameters>
...
/asp:SqlDataSource>
同樣的,DeleteCommand屬性和DeleteParameters>標(biāo)簽如下:
DELETE FROM [Products]
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ...>
DeleteParameters>
asp:Parameter Name="original_ProductID" Type="Int32" />
asp:Parameter Name="original_ProductName" Type="String" />
asp:Parameter Name="original_UnitPrice" Type="Decimal" />
asp:Parameter Name="original_Discontinued" Type="Boolean" />
/DeleteParameters>
UpdateParameters>
...
/UpdateParameters>
...
/asp:SqlDataSource>
選擇了“Use optimistic concurrency”選項(xiàng)后,不僅擴(kuò)展了UpdateCommand 和DeleteCommand屬性里的WHERE字句(同時(shí)在相關(guān)參數(shù)集里添加了參數(shù)),同時(shí)調(diào)整了以下2個(gè)屬性:
1. 將ConflictDetection屬性由“OverwriteChanges”(默認(rèn)值)改為 “CompareAllValues ”
2. 將OldValuesParameterFormatString屬性由“{0}”(默認(rèn)值)改為 “original_{0}”
當(dāng)數(shù)據(jù)Web控件調(diào)用SqlDataSource的Update()或Delete()方法時(shí),它將傳遞原始值。當(dāng)SqlDataSource的ConflictDetection屬性設(shè)置為“CompareAllValues”時(shí),就會(huì)將這些原始值添加到命令中。而OldValuesParameterFormatString屬性則為這些原始值提供了命名規(guī)范,向?qū)б浴皁riginal_{0}”的形式為 UpdateCommand和DeleteCommand中的原始值以及UpdateParameters>和DeleteParameters>中的參數(shù)命名。
注意:由于我們沒(méi)有使用SqlDataSource控件的插入功能,因此可以將InsertCommand 屬性和InsertParameters>標(biāo)簽清除。
正確地處理NULL值
不幸的是,當(dāng)使用開(kāi)放式并發(fā)的時(shí)候,由設(shè)置數(shù)據(jù)源向?qū)ё詣?dòng)生成的、擴(kuò)展成包含WHERE字句的UPDATE和 DELETE命令不能處理那些含有NULL值的記錄。為什么呢?先看SqlDataSource的UpdateCommand語(yǔ)句:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
[UnitPrice] = @original_UnitPrice AND
[Discontinued] = @original_Discontinued
表Products的UnitPrice列的值允許為NULL,如何某條記錄的UnitPrice確實(shí)為NULL,那么WHERE字句的“[UnitPrice] = @original_UnitPrice”總是為False,NULL = NULL總是返回False。所以凡是y包含NULL值的記錄不能被編輯或刪除,因?yàn)閁PDATE和DELETE命令中的WHERE字句不能返回記錄。
注意:這個(gè)漏洞最早于2004年6月報(bào)告給微軟,據(jù)業(yè)內(nèi)傳言,微軟將在ASP.NET的下一個(gè)版本修補(bǔ)該漏洞。
為修補(bǔ)該漏洞,我們需要在UpdateCommand和DeleteCommand屬性里手工修改所有允許為NULL值的列。一般來(lái)說(shuō),將[ColumnName] = @original_ColumnName to改成:
(
([ColumnName] IS NULL AND @original_ColumnName IS NULL)
OR
([ColumnName] = @original_ColumnName)
)
你可以在屬性窗口的UpdateQuery或DeleteQuery選項(xiàng)的代碼聲明里修改,或者在設(shè)置數(shù)據(jù)源向?qū)У摹爸付ㄗ远xSQL語(yǔ)句或存儲(chǔ)過(guò)程”選項(xiàng)的“更新”和“刪除”標(biāo)簽里修改。確保在UpdateCommand和DeleteCommand的WHERE字句里做相同的修改。如下:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
DELETE FROM [Products]
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
第2步:為GridView控件添加編輯和刪除項(xiàng)
當(dāng)設(shè)置SqlDataSource控件支持開(kāi)放式并發(fā)時(shí),我們需要在頁(yè)面上添加一個(gè)數(shù)據(jù)Web控件,以便執(zhí)行開(kāi)放式并發(fā)控制。本章我們添加一個(gè)提供編輯和刪除功能的GridView控件。從工具箱拖一個(gè)GridView到頁(yè)面上,設(shè)置其ID為Products,并綁定到第一步添加的SqlDataSource控件ProductsDataSourceWithOptimisticConcurrency,最后啟用其“編輯”和“刪除”功能。
圖6:將GridView綁定到SqlDataSource并啟用編輯和刪除功能
添加GridView控件后,優(yōu)化其界面。將ProductID列移除;將ProductName列的HeaderText屬性設(shè)置為“Product”;同樣,UnitPrice列的設(shè)置為“Price”。另外,我們最好為ProductName添加一個(gè)RequiredFieldValidator控件;為UnitPrice添加一個(gè)CompareValidator控件(確保其為格式化的數(shù)字值)。參考教程Customizing the Data Modification Interface看如何自定義GridView界面。
注意:必須確保激活GridView控件的view state(視圖狀態(tài)),因?yàn)镚ridView控件傳遞原始值時(shí),將原始值保存在view state中。
對(duì)GridView控件做了這些修改后,GridView控件和SqlDataSource控件的聲明代碼看起來(lái)和下面的差不多:
asp:SqlDataSource ID="ProductsDataSourceWithOptimisticConcurrency"
runat="server" ConflictDetection="CompareAllValues"
ConnectionString="%$ ConnectionStrings:NORTHWNDConnectionString %>"
DeleteCommand=
"DELETE FROM [Products]
WHERE [ProductID] = @original_ProductID
AND [ProductName] = @original_ProductName
AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice))
AND [Discontinued] = @original_Discontinued"
OldValuesParameterFormatString=
"original_{0}"
SelectCommand=
"SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued]
FROM [Products]"
UpdateCommand=
"UPDATE [Products]
SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE [ProductID] = @original_ProductID
AND [ProductName] = @original_ProductName
AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL)
OR ([UnitPrice] = @original_UnitPrice))
AND [Discontinued] = @original_Discontinued">
DeleteParameters>
asp:Parameter Name="original_ProductID" Type="Int32" />
asp:Parameter Name="original_ProductName" Type="String" />
asp:Parameter Name="original_UnitPrice" Type="Decimal" />
asp:Parameter Name="original_Discontinued" Type="Boolean" />
/DeleteParameters>
UpdateParameters>
asp:Parameter Name="ProductName" Type="String" />
asp:Parameter Name="UnitPrice" Type="Decimal" />
asp:Parameter Name="Discontinued" Type="Boolean" />
asp:Parameter Name="original_ProductID" Type="Int32" />
asp:Parameter Name="original_ProductName" Type="String" />
asp:Parameter Name="original_UnitPrice" Type="Decimal" />
asp:Parameter Name="original_Discontinued" Type="Boolean" />
/UpdateParameters>
/asp:SqlDataSource>
asp:GridView ID="Products" runat="server"
AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="ProductsDataSourceWithOptimisticConcurrency">
Columns>
asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
asp:BoundField DataField="UnitPrice" HeaderText="Price"
SortExpression="UnitPrice" />
asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
/Columns>
/asp:GridView>
來(lái)實(shí)際地感受一下開(kāi)放式并發(fā)控制。在2個(gè)瀏覽器里同時(shí)打開(kāi)OptimisticConcurrency.aspx頁(yè)面,且都點(diǎn)擊第一條記錄的編輯按鈕。在第一個(gè)瀏覽器里改變產(chǎn)品名稱并點(diǎn)“編輯”。瀏覽器將發(fā)生回傳,GridView控件又回到“預(yù)編輯”狀態(tài),顯示新的產(chǎn)品名稱。
在第2個(gè)瀏覽器里,改變產(chǎn)品的價(jià)格(不要改產(chǎn)品名稱)后,點(diǎn)“編輯”。發(fā)生回傳,GridView控件又回到“預(yù)編輯”狀態(tài),和第1個(gè)瀏覽器顯示的結(jié)果一樣——產(chǎn)品的名稱改變了但價(jià)格沒(méi)改變,第2個(gè)瀏覽器做的修改失敗了。然而,一切都發(fā)生的那么靜悄悄,沒(méi)有任何提示剛才發(fā)生了并發(fā)沖突!
圖7:第2個(gè)瀏覽器所做的修改悄悄的丟失了
第2個(gè)瀏覽器更新失敗的原因在于:UPDATE命令中WHERE字句過(guò)濾掉了所以的記錄,沒(méi)有影響到任何一行記錄(即沒(méi)找到滿足條件的記錄)。我們?cè)賮?lái)看UPDATE 語(yǔ)句:
UPDATE [Products] SET
[ProductName] = @ProductName,
[UnitPrice] = @UnitPrice,
[Discontinued] = @Discontinued
WHERE
[ProductID] = @original_ProductID AND
[ProductName] = @original_ProductName AND
(([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR
([UnitPrice] = @original_UnitPrice)) AND
[Discontinued] = @original_Discontinued
當(dāng)?shù)?個(gè)瀏覽器更新記錄時(shí),WHERE字句里的原始產(chǎn)品名(即Chai)與當(dāng)前任意一條記錄的產(chǎn)品名不匹配(因?yàn)榈?個(gè)瀏覽器將Chai改為了Chai Tea)。所以表達(dá)式“[ProductName] = @original_ProductName ”返回False,導(dǎo)致更新失敗。
注意:刪除的原理于此相同。同時(shí)打開(kāi)2個(gè)瀏覽器,第1個(gè)先對(duì)某個(gè)產(chǎn)品作更改,再在第2個(gè)瀏覽器刪除該產(chǎn)品,同樣是因?yàn)樵贾蹬c更新后的值不匹配,刪除失敗。
在最終用戶(更新失敗的那個(gè))看來(lái),他點(diǎn)“更新”按鈕后,GridView控件返回“預(yù)編輯”狀態(tài),但提交的修改丟失了。然而沒(méi)有任何直觀的提醒表明修改失敗。當(dāng)用戶的更新因并發(fā)沖突失敗時(shí),我們最好提醒用戶,比如將GridView控件保持在“編輯”狀態(tài)。下面我們來(lái)看如何實(shí)現(xiàn)這一點(diǎn)。
第3步:并發(fā)沖突的處理
因?yàn)椴l(fā)沖突拒絕用戶的更改,所以當(dāng)發(fā)生并發(fā)沖突時(shí)最好提示用戶。在頁(yè)面上添加一個(gè)Label控件,其ID為ConcurrencyViolationMessage,設(shè)置其Text 屬性為“You have attempted to update or delete a record that was simultaneously updated by another user. Please review the other user's changes and then redo your update or delete”,設(shè)置其CssClass屬性為“Warning”,它定義在Styles.css中。最后,把Visible和EnableViewState屬性設(shè)置為“false” 。這樣Label控件將不可見(jiàn),除非發(fā)生了某些回傳事件(我們?cè)谶@些回傳事件里指定Label控件的Visible屬性為true)
圖8:在頁(yè)面添加一個(gè)Label控件用以顯示提醒信息
執(zhí)行更新或刪除操作時(shí),當(dāng)GridView的數(shù)據(jù)源控件完成更新或刪除后,才開(kāi)始執(zhí)行GridView控件的RowUpdated和RowDeleted事件處理器(event handler)。我們可以在這些事件處理器里計(jì)算影響了多少條記錄。假如影響了0條記錄,亦即操作失敗,我們希望將Label控件ConcurrencyViolationMessage顯示出來(lái)。
為RowUpdated和RowDeleted事件創(chuàng)建處理器,添加如下代碼:
protected void Products_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
if (e.AffectedRows == 0)
{
ConcurrencyViolationMessage.Visible = true;
e.KeepInEditMode = true;
// Rebind the data to the GridView to show the latest changes
Products.DataBind();
}
}
protected void Products_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
if (e.AffectedRows == 0)
ConcurrencyViolationMessage.Visible = true;
}
在這2個(gè)事件處理器中我們都要檢驗(yàn)e.AffectedRows 屬性,如果為0,設(shè)置Label控件ConcurrencyViolationMessage的Visible屬性為true。特別的,在RowUpdated事件處理器中,我們通過(guò)將GridView控件的KeepInEditMode屬性設(shè)置為true,使其保持在編輯狀態(tài)。這樣的話,通過(guò)GridView的DataBind() 方法,將他人已經(jīng)成功更新的數(shù)據(jù)顯示在編輯狀態(tài)。
如圖9所示,當(dāng)發(fā)生并發(fā)沖突時(shí),顯示提示信息
圖9:當(dāng)發(fā)生并發(fā)沖突時(shí),顯示提示信息:
總結(jié):
創(chuàng)建一個(gè)應(yīng)用程序時(shí),當(dāng)多人同時(shí)編輯相同數(shù)據(jù)的時(shí)候,要考慮到并發(fā)沖突的問(wèn)題。在默認(rèn)情況下,ASP.NET數(shù)據(jù)Web控件和數(shù)據(jù)源控件沒(méi)有采取并發(fā)控制。就像我們?cè)诒菊驴吹降囊粯樱瑢?duì)SqlDataSource控件使用開(kāi)放式并發(fā)控制還是比較迅速和容易的。通過(guò)在UPDATE和DELETE語(yǔ)句里擴(kuò)展WHERE字句,SqlDataSource能應(yīng)對(duì)絕大部分情況,但就像在“正確處理NULL值”部分探討的那樣,對(duì)包含NULL值列的處理有漏洞。
本章是對(duì)SqlDataSource考察的完結(jié)篇,接下來(lái)的教程繼續(xù)探討層次結(jié)構(gòu)以及用bjectDataSource處理數(shù)據(jù)。
祝編程快樂(lè)!
作者簡(jiǎn)介
本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創(chuàng)始人,自1998年以來(lái)一直應(yīng)用 微軟Web技術(shù)。大家可以點(diǎn)擊查看全部教程《[翻譯]Scott Mitchell 的ASP.NET 2.0數(shù)據(jù)教程》,希望對(duì)大家的學(xué)習(xí)ASP.NET有所幫助。
您可能感興趣的文章:- jquery獲取ASP.NET服務(wù)器端控件dropdownlist和radiobuttonlist生成客戶端HTML標(biāo)簽后的value和text值
- ASP.NET jQuery 實(shí)例16 通過(guò)控件CustomValidator驗(yàn)證RadioButtonList
- ASP.NET服務(wù)器端控件RadioButtonList,DropDownList,CheckBoxList的取值、賦值用法
- Asp.Net如何將多個(gè)RadioButton指定在一個(gè)組中
- asp.net使用jQuery獲取RadioButtonList成員選中內(nèi)容和值示例
- ASP.NET單選按鈕控件RadioButton常用屬性和方法介紹
- ASP.NET GridView中加入RadioButton不能單選的解決方案
- ASP.NET中 RadioButtonList 單選按鈕組控件的使用方法
- ASP.NET中RadioButtonList綁定后臺(tái)數(shù)據(jù)后觸發(fā)點(diǎn)擊事件
- 在ASP.NET 2.0中操作數(shù)據(jù)之四十九:為GridView控件添加RadioButton