前面提到,資料繫結控制項將傳遞給資料來源的值存放在獨立的 Keys、Values(新值)和 OldValues 字典中。預設情況下,SqlDataSource 和 ObjectDataSource 會忽略 OldValues 欄位,只使用 Keys 和 Values。此行為由資料來源的 ConflictDetection 屬性控制,預設值為 OverwriteChanges。OverwriteChanges 模式意謂「為了更新或刪除記錄,僅比對主鍵值」。此操作意謂著,記錄更新或刪除不考慮該記錄底層值是否已改變。通常理想狀態是:只有當資料列值與最初選取的值完全匹配時,才讓 Update 或 Delete 操作成功。在此理想狀態下,若另一用戶在你選取某列與更新該列之間也更新了此列,你的更新操作會失敗。透過將 ConflictDetection 屬性設為 CompareAllValues,資料來源也支援此操作。此模式下,資料來源會將 OldValues 套用到命令或方法上,使用這些值確保更新或刪除記錄前,操作必須與記錄所有值都匹配。你還必須將 OldValuesParameterFormatString 屬性設為有效的 .NET Framework 格式化字串(如 "original_{0}"),以區分 OldValues 和 Keys 字典中的參數與 NewValues 參數。
下列程式碼範例顯示 SqlDataSource 控制項在 OverwriteChanges 和 CompareAllValues 模式下使用的典型 SQL 命令。假設 ID 欄位為主鍵。請注意,後者命令在 WHERE 子句中比對資料列所有原始值,而非僅比對主鍵。此情況下,資料來源的 OldValuesParameterFormatString 需設為 "original_{0}"。
SELECT [ID], [Name], [Address] from [Contacts]
-- OverwriteChanges
UPDATE [Contacts] SET [Name] = @Name, [Address] = @Address WHERE [ID] = @ID
DELETE FROM [Contacts] WHERE [ID] = @ID
-- CompareAllValues
UPDATE [Contacts] SET [Name] = @Name, [Address] = @Address WHERE [ID] = @original_ID
AND [Name] = @original_Name AND [Address] = @original_Address
DELETE FROM [Contacts] WHERE [ID] = @original_ID AND [Name] = @original_Name
AND [Address] = @original_Address
請注意,Insert 操作不需要 OldValues,ConflictDetection 僅對 Update 和 Delete 操作有意義。
下列範例示範衝突發生時的行為。執行此範例,需在兩個獨立瀏覽器視窗開啟範例兩個實例(點擊兩次「Run Sample」)。接著在兩個視窗同一列點擊「Edit」按鈕,使該列進入編輯模式。在第一視窗改變一值並點擊「Update」,注意此更新成功。在第二視窗,在該列輸入新值並點擊「Update」,此更新操作未成功,因底層資料列值已被第一更新操作改變。此範例偵測 Updated 或 Deleted 事件參數的 AffectedRows 屬性,為 0 確認衝突發生。
<script runat="server">
Protected Sub SqlDataSource1_Updated(sender As Object, e As SqlDataSourceStatusEventArgs)
If e.AffectedRows = 0 Then
Response.Write("Row changed, update aborted<br />")
End If
End Sub
Protected Sub SqlDataSource1_Deleted(sender As Object, e As SqlDataSourceStatusEventArgs)
If e.AffectedRows = 0 Then
Response.Write("Row changed, delete aborted<br />")
End If
End Sub
</script>