Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Se você estiver lidando com o conjunto de registros no modo imediato, há muito menos chance de ocorrer problemas de simultaneidade. Por outro lado, se o aplicativo usar a atualização do modo em lote, pode haver uma boa chance de um usuário alterar um registro antes que as alterações feitas por outro usuário editando o mesmo registro sejam salvas. Nesse caso, você desejará que seu aplicativo lide normalmente com o conflito. Pode ser seu desejo que a última pessoa a enviar uma atualização para o servidor "ganhe". Ou talvez você queira permitir que o usuário mais recente decida qual atualização deve ter precedência, fornecendo-lhe uma escolha entre os dois valores conflitantes.
Seja qual for o caso, o ADO fornece as propriedades UnderlyingValue e OriginalValue do objeto Field para lidar com esses tipos de conflitos. Use essas propriedades em combinação com o método Resync e a propriedade Filter do Recordset.
Observações
Quando o ADO encontrar um conflito durante uma atualização em lote, um aviso será adicionado à coleção Errors. Portanto, você sempre deve verificar se há erros imediatamente após chamar BatchUpdate e, se encontrá-los, comece a testar a suposição de que você encontrou um conflito. A primeira etapa é definir a propriedade Filter no Recordset igual a adFilterConflictingRecords. Isso limita a visualização no conjunto de registros a somente os registros que estão em conflito. Se a propriedade RecordCount for igual a zero após esta etapa, você saberá que o erro foi gerado por algo diferente de um conflito.
Quando você chama BatchUpdate, o ADO e o provedor estão gerando instruções SQL para executar atualizações na fonte de dados. Lembre-se de que determinadas fontes de dados têm limitações sobre quais tipos de colunas podem ser usadas em uma cláusula WHERE.
Em seguida, chame o método Resync no Recordset com o argumento AffectRecords definido igual a adAffectGroup e o argumento ResyncValues definido como adResyncUnderlyingValues. O método Resync atualiza os dados no objeto Recordset atual do banco de dados subjacente. Usando adAffectGroup, você está garantindo que apenas os registros visíveis com a configuração de filtro atual, ou seja, apenas os registros conflitantes, sejam ressincronizados com o banco de dados. Isso pode fazer uma diferença significativa de desempenho se você estiver lidando com um conjunto de registros grande. Ao definir o argumento ResyncValues como adResyncUnderlyingValues ao chamar Resync, você garante que a propriedade UnderlyingValue contenha o valor (conflitante) do banco de dados, que a propriedade Value mantenha o valor inserido pelo usuário e que a propriedade OriginalValue contenha o valor original do campo (o valor que ele tinha antes de a última chamada bem-sucedida de UpdateBatch ter sido feita). Em seguida, você pode usar esses valores para resolver o conflito programaticamente ou exigir que o usuário selecione o valor que será usado.
Essa técnica é mostrada no exemplo de código a seguir. O exemplo cria artificialmente um conflito usando um Conjunto de Registros separado para alterar um valor na tabela subjacente antes que UpdateBatch seja chamado.
'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
Você pode usar a propriedade Status do Registro atual ou de um campo específico para determinar que tipo de conflito ocorreu.
Para obter informações detalhadas sobre o tratamento de erros, consulte Tratamento de Erros.