Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10全般 : Access 2021)
別のaccdbのテーブルをフォームに表示したい
投稿日時: 23/02/14 15:27:29
投稿者: miyagi07

Access初心者です。
操作用accdbのデータシートフォームにデータ保管用accdbにあるテーブルを表示させたいです。
調べながらなんとかコードを書いてみたのですが、フォームを開くと「データプロバイダーを初期化できませんでした」というエラーが出てしまいます。
Me.RecordSource〜の文を削除するとテーブルが表示されますが、「すべて更新」のボタンを押すと同じエラーメッセージが表示される上に、フォームがなぜか読み取り専用になってしまい、レコードを更新することができません。
原因が分かる方がいらっしゃいましたらアドバイスいただけないでしょうか。
よろしくお願いいたします。
 
――――――――
 
Private Sub Form_Load()
 
Dim Cn As ADODB.Connection
Dim Rs As ADODB.Recordset
Dim BackT As String
 
Set Cn = New ADODB.Connection
Cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" _
            & "Data Source=データ保管用accdbのファイルパス"
Set Rs = New ADODB.Recordset
 
BackT = "SELECT * FROM 表示させたいテーブル名"
 
Rs.Open BackT, Cn, adOpenKeyset, adLockOptimistic
 
Set Me.Recordset = Rs
Me.RecordSource = BackT
 
Set Rs = Nothing: Close
Set Cn = Nothing: Close
 
End Sub

回答
投稿日時: 23/02/14 18:33:10
投稿者: sk

引用:
操作用accdbのデータシートフォームにデータ保管用accdbにあるテーブルを表示させたいです。

[データ保管用accdb]にあるテーブルを参照するリンクテーブルを
[操作用accdb]に設けた上、そのリンクテーブルをレコードソースとする
フォームを作成された方が最も手っ取り早いと思いますが。
(コードを書くまでもない)
 
(フォームモジュール)
---------------------------------------------------------------
Option Compare Database
Option Explicit
 
Private adoCn As ADODB.Connection
Private adoRs As ADODB.Recordset
 
Private Sub Form_Open(Cancel As Integer)
On Error GoTo Err_Form_Open
 
    Me.Painting = False
 
    Dim strSourceFilePath As String
    strSourceFilePath = "C:\FolderName\FileName.accdb"
 
    Set adoCn = New ADODB.Connection
    With adoCn
        .CursorLocation = adUseClient
        .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                            "Data Source=" & strSourceFilePath
        .Open
    End With
     
    Dim strSQL As String
    strSQL = "SELECT * FROM [テーブル名]"
     
    Set adoRs = New ADODB.Recordset
    With adoRs
        Set .ActiveConnection = adoCn
        .CursorLocation = adUseClient
        .CursorType = adOpenKeyset
        .LockType = adLockOptimistic
        .Source = strSQL
        .Open
    End With
     
    Set Me.Recordset = adoRs
 
Exit_Form_Open:
 
    Me.Painting = True
 
    Exit Sub
 
Err_Form_Open:
     
    Dim strTitle As String
    Dim strMsg As String
     
    strTitle = "実行時エラー(" & Me.Name & ".Form_Open)"
    strMsg = Err.Number & ": " & Err.Description
     
    Debug.Print strTitle & vbCrLf & strMsg
    MsgBox strMsg, vbCritical, strTitle
     
    Call ReleaseObjects
     
    Cancel = True
     
End Sub
 
Private Sub Form_Unload(Cancel As Integer)
 
    Call ReleaseObjects
 
End Sub
 
Private Sub ReleaseObjects()
On Error Resume Next
 
    If Not adoRs Is Nothing Then
        If adoRs.State = adStateOpen Then
            adoRs.Close
        End If
        Set adoRs = Nothing
    End If
     
    If Not adoCn Is Nothing Then
        If adoCn.State = adStateOpen Then
            adoCn.Close
        End If
        Set adoCn = Nothing
    End If
 
End Sub
---------------------------------------------------------------
 
ADODB.Recordset オブジェクトとフォームを連結させたいなら
大体こんな感じで。
これとは別に、各コントロールのコントロールソースの設定も
必要です。

投稿日時: 23/02/15 09:40:09
投稿者: miyagi07

返信ありがとうございます。
リンクテーブルを使えば簡単にできることは分かっていますが、できれば使用を避けたい事情があり、ADOでの解決法を探しておりました。
 
コード非常に参考になります。
このコードだと勝手に読み取り専用にはなりませんが、「すべて更新」を押すとやはり「データプロバイダーを初期化できません」のメッセージが出てしまいます。
操作用accdb自体にテーブルを置いていない以上どうしようもないのでしょうか。
 
また、今後ADOを使えるようになるために教えていただきたいのですが、私のコードで不具合が起きたのは「Form_Lord」内に記述したためでしょうか。
それともCursorLocationの指定がないためでしょうか。
教えていただけますと幸いです。

回答
投稿日時: 23/02/15 12:08:08
投稿者: sk

引用:
このコードだと勝手に読み取り専用にはなりませんが、
「すべて更新」を押すとやはり「データプロバイダーを初期化できません」の
メッセージが出てしまいます。

[ホーム]タブ -> [レコード]グループ -> [すべて更新]ボタンを
クリックすればそうなるでしょう。
 
回避策としては、そのフォームの Error イベントの発生時に
Access が返したエラーの番号に応じてエラーメッセージを
表示させないようにしつつ、フォームと連結しているレコードセットの
再クエリ処理を自前で実行することが挙げられます。
 
(フォームモジュール)
------------------------------------------------------------
Private Sub Form_Error(DataErr As Integer, Response As Integer)
 
    'Debug.Print DataErr
     
    Select Case DataErr
        Case 31
            Response = acDataErrContinue
            Call RequeryRecordset
        Case Else
            Response = acDataErrDisplay
    End Select
 
End Sub
 
Private Sub RequeryRecordset()
On Error GoTo Err_RequeryRecordset
 
    Me.Painting = False
 
    If Not adoRs Is Nothing Then
        If adoRs.State = adStateOpen Then
            Set Me.Recordset = Nothing
            adoRs.Requery
            adoRs.Resync adAffectAll
            Set Me.Recordset = adoRs
        End If
    End If
 
Exit_RequeryRecordset:
 
    Me.Painting = True
 
    Exit Sub
 
Err_RequeryRecordset:
 
    Dim strTitle As String
    Dim strMsg As String
     
    strTitle = "実行時エラー(" & Me.Name & ".RequeryRecordset)"
    strMsg = Err.Number & ": " & Err.Description
     
    Debug.Print strTitle & vbCrLf & strMsg
    MsgBox strMsg, vbCritical, strTitle
 
    Resume Exit_RequeryRecordset
End Sub
------------------------------------------------------------
 
引用:
私のコードで不具合が起きたのは「Form_Lord」内に記述したためでしょうか。

Load イベントで実行することも可能です。
 
Open イベントで実行するようにしたのは、実行時エラーが発生したら
Open イベントをキャンセルしてフォームが(中途半端な状態で)
開かれないようにするためです。
 
引用:
それともCursorLocationの指定がないためでしょうか。

フォームと連結されたレコードセットが読み取り専用になった理由は
その通りです。
 
引用:
フォームを開くと「データプロバイダーを初期化できませんでした」という
エラーが出てしまいます。

引用:
「すべて更新」のボタンを押すと同じエラーメッセージが表示される

実行中の Access アプリケーションの管理下にあるデータベースエンジンとは
別のインスタンスを介して取得されたレコードセットとそのフォームが
既に連結されている状態だからです。

投稿日時: 23/02/15 13:38:13
投稿者: miyagi07

大変丁寧に解説していただきありがとうございました。
私のコードでエラーになる理由が理解できました。
また、中途半端な状態でフォームを表示させないために「Form_Open」イベントを使うというのは目から鱗でした。キャンセルすることができるのは分かっていたのにまったく思いつきませんでした。
 
「データプロバイダーを初期化できません」というエラーについて、どんなに調べても原因どころか意味すら分からなかったので非常に助かりました。
Accessについて一から勉強しなおそうと思います。
本当にありがとうございました。