偵測並解決衝突
如果您是以立即模式處理資料錄集,則發生並行問題的可能性較低。 另一方面,如果您的應用程式使用批次模式進行更新,則很可能會有一個使用者在另一個編輯相同記錄的使用者儲存其所做的變更之前變更記錄。 在這種情況下,您會希望應用程式能夠正常處理衝突。 您可能想要讓最後將更新傳送至伺服器的人「勝出」。或者,您可能會想要為最新的使用者提供兩個衝突值之間的選擇,讓他決定哪些更新應優先。
無論是哪種情況,ADO 都會提供 Field 物件的 UnderlyingValue 和 OriginalValue 屬性來處理這些類型的衝突。 請將這些屬性與資料錄集的 Resync 方法和 Filter 屬性搭配使用。
備註
ADO 在批次更新期間遇到衝突時,會將警告新增至 Errors 集合。 因此,您應一律在呼叫 BatchUpdate 之後立即檢查錯誤,如果發現錯誤,請開始測試您遇到衝突的假設。 第一個步驟是將資料錄集上的 Filter 屬性設定為 adFilterConflictingRecords。 這會將資料錄集上的檢視限定於發生衝突的記錄。 如果 RecordCount 屬性經此步驟後等於零,則可得知錯誤並非衝突所引起的。
當您呼叫 BatchUpdate 時,ADO 和提供者會產生 SQL 陳述式,以對資料來源執行更新。 請記住,某些資料來源具有哪些類型的資料行可在 WHERE 子句中使用的限制。
接著,將 AffectRecords 引數設定為 adAffectGroup,並將 ResyncValues 引數設定為 adResyncUnderlyingValues,在資料錄集上呼叫 Resync 方法。 Resync 方法會從基礎資料庫更新目前 Recordset 物件中的資料。 使用 adAffectGroup,可以確保只有透過目前的篩選設定可見的記錄 (即只有發生衝突的記錄) 會與資料庫重新同步處理。 如果您處理的是大型資料錄集,這可能會造成顯著的效能差異。 在呼叫 Resync 時將 ResyncValues 引數設定為 adResyncUnderlyingValues,可確保 UnderlyingValue 屬性將包含資料庫中的 (衝突) 值,Value 屬性將保有使用者輸入的值,且 OriginalValue 屬性會保留欄位的原始值 (上次成功呼叫 UpdateBatch 呼叫之前的值)。 您隨後可以使用這些值以程式設計方式解決衝突,或要求使用者選取將使用的值。
下列程式碼範例中顯示了這項技巧。 此範例使用個別的資料錄集,在呼叫 UpdateBatch 之前變更基礎資料表中的值,而刻意產生衝突。
'BeginConflicts
strConn = "Provider=SQLOLEDB;Initial Catalog=Northwind;" & _
"Data Source=MySQLServer;Integrated Security=SSPI;"
strSQL = "SELECT * FROM Shippers WHERE ShipperID = 2"
'Open Rs and change a value
Set objRs1 = New ADODB.Recordset
Set objRs2 = New ADODB.Recordset
objRs1.CursorLocation = adUseClient
objRs1.Open strSQL, strConn, adOpenStatic, adLockBatchOptimistic, adCmdText
objRs1("Phone") = "(111) 555-1111"
'Introduce a conflict at the db...
objRs2.Open strSQL, strConn, adOpenKeyset, adLockOptimistic, adCmdText
objRs2("Phone") = "(999) 555-9999"
objRs2.Update
objRs2.Close
Set objRs2 = Nothing
On Error Resume Next
objRs1.UpdateBatch
If objRs1.ActiveConnection.Errors.Count <> 0 Then
Dim intConflicts As Integer
intConflicts = 0
objRs1.Filter = adFilterConflictingRecords
intConflicts = objRs1.RecordCount
'Resync so we can see the UnderlyingValue and offer user a choice.
'This sample only displays all three values and resets to original.
objRs1.Resync adAffectGroup, adResyncUnderlyingValues
If intConflicts > 0 Then
strMsg = "A conflict occurred with updates for " & intConflicts & _
" record(s)." & vbCrLf & "The values will be restored" & _
" to their original values." & vbCrLf & vbCrLf
objRs1.MoveFirst
While Not objRs1.EOF
strMsg = strMsg & "SHIPPER = " & objRs1("CompanyName") & vbCrLf
strMsg = strMsg & "Value = " & objRs1("Phone").Value & vbCrLf
strMsg = strMsg & "UnderlyingValue = " & _
objRs1("Phone").UnderlyingValue & vbCrLf
strMsg = strMsg & "OriginalValue = " & _
objRs1("Phone").OriginalValue & vbCrLf
strMsg = strMsg & vbCrLf & "Original value has been restored."
MsgBox strMsg, vbOKOnly, _
"Conflict " & objRs1.AbsolutePosition & _
" of " & intConflicts
objRs1("Phone").Value = objRs1("Phone").OriginalValue
objRs1.MoveNext
Wend
objRs1.UpdateBatch adAffectGroup
Else
'Other error occurred. Minimal handling in this example.
strMsg = "Errors occurred during the update. " & _
objRs1.ActiveConnection.Errors(0).Number & " " & _
objRs1.ActiveConnection.Errors(0).Description
End If
On Error GoTo 0
End If
objRs1.MoveFirst
objRs1.Close
Set objRs1 = Nothing
'EndConflicts
您可以使用目前的記錄或特定欄位的 Status 屬性,判斷發生的是何種衝突。
如需錯誤處理的詳細資訊,請參閱錯誤處理。