次の方法で共有


競合の検出と解決

レコードセットを即時モードで処理する場合、コンカレンシーの問題が発生する可能性ははるかに低くなります。 一方、アプリケーションでバッチ モードの更新を使用している場合は、同じレコードを編集している別のユーザーによって行われた変更が保存される前に、あるユーザーがレコードを変更する可能性が高い可能性があります。 このような場合は、アプリケーションで競合を適切に処理する必要があります。 最後のユーザーがサーバーに更新プログラムを送信することを望む場合があります。または、最新のユーザーに、競合する 2 つの値のどちらかを選択して、どの更新プログラムを優先するかを決定できるようにすることもできます。

どのような場合でも、ADO は、これらの種類の競合を処理する Field オブジェクトの UnderlyingValue プロパティと OriginalValue プロパティを提供します。 これらのプロパティは、Recordset の Resync メソッドと Filter プロパティと組み合わせて使用します。

備考

バッチ更新中に ADO で競合が発生すると、Errors コレクションに警告が追加されます。 そのため、BatchUpdate を呼び出した直後に常にエラーを確認し、見つけた場合は、競合が発生したという仮定のテストを開始する必要があります。 最初の手順では、レコードセットの Filter プロパティを adFilterConflictingRecords と等しく設定します。 これにより、レコードセットのビューが競合しているレコードのみに制限されます。 この手順の後に RecordCount プロパティが 0 に等しい場合は、競合以外によってエラーが発生したことがわかります。

BatchUpdate を呼び出すと、ADO とプロバイダーは、データ ソースに対して更新を実行する SQL ステートメントを生成します。 特定のデータ ソースには、WHERE 句で使用できる列の種類に制限があります。

次に、AffectRecords 引数が adAffectGroup に等しく設定され、ResyncValues 引数が adResyncUnderlyingValues に等しく設定されている Recordset の Resync メソッドを呼び出します。 Resync メソッドは、基になるデータベースから現在の Recordset オブジェクト内のデータを更新します。 adAffectGroup を使用すると、現在のフィルター設定で表示されるレコード (競合するレコードのみ) のみがデータベースと再同期されるようにすることができます。 これにより、大きな Recordset を処理する場合、パフォーマンスに大きな違いが生じます。 Resync を呼び出すときに ResyncValues 引数を adResyncUnderlyingValues に設定することで、データベースの (競合する) 値が UnderlyingValue プロパティに含まれていること、Value プロパティがユーザーによって入力された値を保持すること、および OriginalValue プロパティがフィールドの元の値 (最後に成功した UpdateBatch 呼び出しが行われる前の値) を保持するようにします。 その後、これらの値を使用して、プログラムによって競合を解決したり、使用する値をユーザーに選択するよう要求したりできます。

この手法を次のコード例に示します。 この例では、UpdateBatch が呼び出される前に、別の Recordset を使用して基になるテーブルの値を変更することで、競合が人為的に作成されます。

'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 プロパティを使用して、競合が発生した種類を判断できます。

エラー処理の詳細については、「エラー処理 を参照してください。

関連項目

バッチモード