6

従来の Access アプリケーションを Sql Server、つまり DAO+Linked テーブルに移行しています。

リンクされたテーブルでレコードセットを使用して変更を行うと、Access は複数の接続を使用します。複数の接続とは、サーバー側で一度に複数のトランザクションを意味します。これらのトランザクションは独立しています。ネストされていません。

.mdb ファイルへのリンク テーブルを使用する標準の MS-Access の動作は異なります。一度に 1 つのトランザクションしかありません。すべてのデータベースの変更は、コミットを実行する前に同じ DAO.Workspace で実行されるすべてのコードによって表示されます。

ルールが変更され、クライアント側トランザクションを使用する既存の DAO コードは失敗します。

dbOpenDynaset として開いているレコードセットを使用してレコードを追加または更新すると、後で読み取ろうとするコードはすべて失敗します。新しいレコードが見つからず、既存のレコードが元の状態で表示されません。なんで?操作は複数の独立したトランザクションで行われるため

提供されたサンプル コードを実行すると、SQL プロファイラーは、さまざまな操作がさまざまなトランザクション ID で行われていることを示します。

ADO を使用してこれをテストしたところ、すべて正常に動作しました。しかし、何千ものコード行があります。

ADO を使用してコードを書き直す以外に解決策はありますか?

標準の Access の動作を変更できますか? (コミットされていない分離レベルの読み取りを使用し、新しい接続を開かないように指示します...)

以下のコードは問題を再現します。とても簡単です:

1.- 既存のレコードでレコードセットを開く
2.- 新しいレコードを追加する
3.- 最近追加されたレコードを読み取ろうとする

(1) で dbOpenDynaset を使用すると、(3) で新しいレコードが表示されません。

Acc-2010、.accdb 形式のファイル、および Sql Server 2008 R2 を使用しています

ありがとう。

    Private Sub test0()
     Dim bResult As Boolean

    Dim bUseTrans As Boolean 'New record added in transaction

    Dim rsExist As DAO.Recordset2 'Dummy recordset
     Dim tRecordsetExist As DAO.RecordsetTypeEnum 'Dummy recordset type:
                                                  '  with dbOpenDynaset fail.
                                                  '  Any other works fine

    Dim rs2Add As DAO.Recordset

    Dim rs2Read As DAO.Recordset 'Used to read recently added record
     Dim tRecordset2Read As DAO.RecordsetTypeEnum 'Recordset type used to read new record. Doesn't affect

    Dim bTranInitiated As Boolean 'Track if we are in transaction

    Dim lngExistingNumber As Long
     Dim lngNewNumber As Long
     Dim lngNewID As Long
     Dim strSQL As String
 On Error GoTo HandleErr

    'Invoices table definition in SS. Table is linked as [dbo_Invoices]:
     '   CREATE TABLE [dbo].[Invoices](
     '       [IdInvoice] [int] IDENTITY(1,1) NOT NULL,
     '       [InvoiceNumber] [int] NOT NULL,
     '       [InvoiceDescription] [varchar](50) NOT NULL,
     '    CONSTRAINT [PK_Invoices] PRIMARY KEY CLUSTERED
     '   (
     '       [IdInvoice] Asc
     '   )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
     '   ) ON [PRIMARY]

    Set wks = DBEngine.Workspaces(0)
     Set dbs = wks.Databases(0)

    bUseTrans = True 'Without transaction everything works well

    tRecordsetExist = dbOpenDynaset 'Dummy recordset type:
                                     '  dbOpenDynaset makes fail.
                                     '  Any other works fine

    tRecordset2Read = dbOpenForwardOnly 'Does not affect

    lngExistingNumber = 12001
     lngNewNumber = -lngExistingNumber

    'Clean previous runs of the test and make sure that referenced invoice exists.
     dbs.Execute "Delete from dbo_Invoices Where InvoiceNumber = " & lngNewNumber, dbFailOnError Or dbSeeChanges
     On Error Resume Next
     strSQL = "Insert Into dbo_Invoices (InvoiceNumber, InvoiceDescription) " & _
             " Values (" & lngExistingNumber & ", 'Original invoice' )"
     dbs.Execute strSQL, dbFailOnError Or dbSeeChanges
     On Error GoTo HandleErr

    If bUseTrans Then
         wks.BeginTrans
         bTranInitiated = True
     End If

    strSQL = "Select IdInvoice, InvoiceNumber from dbo_Invoices " & _
             " Where InvoiceNumber = " & lngExistingNumber
     If tRecordsetExist = dbOpenDynaset Then
         Set rsExist = dbs.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)
     Else
         Set rsExist = dbs.OpenRecordset(strSQL, tRecordsetExist)
     End If
     If rsExist.BOF And rsExist.EOF Then
         Err.Raise vbObjectError, , "Original invoice " & lngExistingNumber & " not found"
     End If

    Set rs2Add = dbs.OpenRecordset("Select * from dbo_Invoices", dbOpenDynaset, dbAppendOnly Or dbSeeChanges)

    rs2Add.AddNew
     rs2Add!InvoiceNumber = lngNewNumber
     rs2Add!InvoiceDescription = "Invoice anulation, ref " & lngExistingNumber
     rs2Add.Update

    'After executing .Update rs2Add goes to .EOF. This action reposition the recordset on the new record
     rs2Add.Move 0, rs2Add.LastModified

    lngNewID = rs2Add!IdInvoice
     Debug.Print "New record added: IdInvoice = " & rs2Add!IdInvoice & ", InvoiceNumber = " & rs2Add!InvoiceNumber

    'Try to read the new record
     strSQL = "Select * from dbo_Invoices Where IdInvoice = " & lngNewID
     If tRecordset2Read = dbOpenDynaset Then
         Set rs2Read = dbs.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)
     Else
         Set rs2Read = dbs.OpenRecordset(strSQL, tRecordset2Read)
     End If
     If (rs2Read.BOF And rs2Read.EOF) Then
         Err.Raise vbObjectError, , "rs2Read: Not found using IdInvoice = " & lngNewID
     End If
     Debug.Print "New record found with IdInvoice = " & rs2Read!IdInvoice
     rs2Read.Close

    bResult = True
 ExitHere:
     If Not wks Is Nothing Then
         If bTranInitiated Then
             If bResult Then
                 wks.CommitTrans
             Else
                 wks.Rollback
             End If
             bTranInitiated = False
         End If
     End If
     On Error Resume Next
     If Not rs2Add Is Nothing Then
         rs2Add.Close
         Set rs2Add = Nothing
     End If
     If Not rs2Read Is Nothing Then
         rs2Read.Close
         Set rs2Read = Nothing
     End If
     Exit Sub
 HandleErr:
     Dim e As Object
     If Err.Description Like "ODBC*" Then
         For Each e In DBEngine.Errors
             MsgBox e.Description, vbCritical
         Next
     Else
         MsgBox Err.Description, vbCritical
     End If
     bResult = False
     Resume ExitHere
     Resume
 End Sub
4

2 に答える 2

2

残念ながら、Microsoft はWorkspace.IsolateODBCTransプロパティ について次のように述べています

Microsoft SQL Server などの一部の ODBC サーバーでは、単一接続での同時トランザクションが許可されていません。このようなデータベースに対して複数のトランザクションを同時に保留する必要がある場合は、ワークスペースを開いた直後に、各ワークスペースで IsolateODBCTrans プロパティを True に設定します。これにより、ワークスペースごとに個別の ODBC 接続が強制されます。

これが何をすべきかを決めるのに役立つかどうかはわかりません。

于 2012-09-25T14:34:54.883 に答える
0

mdbに残っているテーブルには引き続きdaoを使用できます。ただし、次のようなsqlserverテーブル(リンクテーブル)の場合:Global objConn As New ADODB.Connection

そしてルーチンで:

    Dim rst As ADODB.Recordset
    DoCmd.SetWarnings False
    If objConn.State <> adStateOpen Then
        MsgBox ("Connection to SQL server has not been made. Please exit and resolve problem.")
        Exit Sub
    End If

    Set rst = New ADODB.Recordset

Dim stdocname As String
rst.Open "tblbilling", objConn, adOpenDynamic, adLockPessimistic

などなどなど.....

于 2012-09-25T23:57:16.730 に答える