Erkennen und Lösen von Konflikten
Wenn Sie sich im unmittelbaren Modus mit Ihrem Recordset befassen, besteht viel weniger Chance, dass Parallelitätsprobleme auftreten. Wenn Ihre Anwendung jedoch im Batch-Modus aktualisiert wird, besteht eine gute Chance, dass ein Benutzer einen Datensatz ändert, bevor die Änderungen eines anderen Benutzers, der denselben Datensatz bearbeitet, gespeichert werden. In diesem Fall möchten Sie, dass Ihre Anwendung den Konflikt ordnungsgemäß behandelt. Sie möchten vielleicht, dass die Person, die als letzte eine Aktualisierung an den Server sendet, „gewinnt“. Oder Sie möchten den letzten Benutzer entscheiden lassen, welche Aktualisierung Vorrang haben soll, indem Sie ihm die Wahl zwischen den beiden sich widersprechenden Werten lassen.
Wie auch immer, ADO bietet die Eigenschaften UnderlyingValue und OriginalValue des Field-Objekts, um diese Arten von Konflikten zu behandeln. Verwenden Sie diese Eigenschaften in Kombination mit der Methode Resync und der Eigenschaft Filter des Recordsets.
Bemerkungen
Wenn ADO während eines Batchupdates einen Konflikt findet, wird der Errors-Auflistung eine Warnung hinzugefügt. Daher sollten Sie immer sofort nach dem Aufrufen von BatchUpdate nach Fehlern suchen, und wenn Sie sie finden, beginnen Sie mit dem Testen der Annahme, dass ein Konflikt aufgetreten ist. Der erste Schritt besteht darin, die Filter-Eigenschaft für das Recordset gleich "adFilterConflictingRecords" festzulegen. Dadurch wird die Ansicht auf Ihrem Recordset auf nur die Datensätze beschränkt, die in Konflikt stehen. Wenn die RecordCount-Eigenschaft nach diesem Schritt gleich Null ist, wissen Sie, dass der Fehler von einem anderen Als einem Konflikt ausgelöst wurde.
Wenn Sie BatchUpdate aufrufen, generieren ADO und der Anbieter SQL-Anweisungen, um Updates für die Datenquelle auszuführen. Beachten Sie, dass bestimmte Datenquellen Einschränkungen haben, auf welche Spaltentypen in einer WHERE-Klausel verwendet werden können.
Rufen Sie als Nächstes die Resync-Methode im Recordset auf, wobei das Argument „AffectRecords“ gleich „adAffectGroup“ und das Argument „ResyncValues“ auf „adResyncUnderlyingValues“ festgelegt ist. Die Methode Resync aktualisiert die Daten im aktuellen Recordset-Objekt aus der zugrunde liegenden Datenbank. Mithilfe von adAffectGroup stellen Sie sicher, dass nur die Datensätze, die mit der aktuellen Filtereinstellung sichtbar sind, also nur die konfliktierenden Datensätze, mit der Datenbank neu synchronisiert werden. Dies könnte einen erheblichen Leistungsunterschied machen, wenn Sie mit einem großen Recordset umgehen. Indem Sie das Argument ResyncValues beim Aufruf von Resync auf adResyncUnderlyingValues setzen, stellen Sie sicher, dass die Eigenschaft UnderlyingValue den (widersprüchlichen) Wert aus der Datenbank enthält, dass die Eigenschaft Value den vom Benutzer eingegebenen Wert beibehält und dass die Eigenschaft OriginalValue den ursprünglichen Wert für das Feld enthält (den Wert, den es vor dem letzten erfolgreichen UpdateBatch-Aufruf hatte). Anschließend können Sie diese Werte verwenden, um den Konflikt programmgesteuert zu beheben, oder der Benutzer muss den verwendeten Wert auswählen.
Diese Technik wird in dem folgenden Codebeispiel gezeigt. Das Beispiel schafft künstlich einen Konflikt, indem es ein separates Recordset verwendet, um einen Wert in der zugrunde liegenden Tabelle zu ändern, bevor UpdateBatch aufgerufen wird.
'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
Sie können die Eigenschaft Status des aktuellen Datensatzes oder eines bestimmten Feldes verwenden, um festzustellen, welche Art von Konflikt aufgetreten ist.
Ausführliche Informationen zur Fehlerbehandlung finden Sie unter Fehlerbehandlung.