【入門編】DAOとADOの共存環境:同一プロジェクト内で両者を使い分ける際の命名規則と管理術 – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

DAOとADOの共存を極める:名前の衝突を回避し、プロの設計を手に入れる

こんにちは。Access VBAの世界へようこそ。

「マクロの記録」から一歩踏み出し、自分でコードを書き始めたあなた。今、こんな壁にぶつかっていませんか?

「DAOを使おうとしたら、なぜかADOのエラーが出る……」
「『名前が適切ではありません』というエラーが出て、プログラムが止まってしまう……」

実はこれ、Access VBAを使い始めた人が必ずと言っていいほど遭遇する、「ライブラリの衝突」という現象なんです。

でも、安心してください。これが発生するということは、あなたが「ローカルの高速な処理(DAO)」と「外部データベースへの接続(ADO)」の両方を使おうとしている、つまり一歩上のエンジニアへの階段を登っている証拠なのです。

今日は、この「DAOとADOの共存」を完璧にコントロールするための、プロの設計術を伝授します。ここをクリアすれば、あなたのコードの信頼性は劇的に向上しますよ。

1. なぜ「衝突」が起きるのか?:二つのエンジンの正体

まず、敵を知ることから始めましょう。Access VBAには、データを操作するための「エンジン」が主に二つあります。

DAO (Data Access Objects)

  • 役割: Accessのローカルテーブルを操作するための「純正エンジン」。
  • 強み: Access内部の構造を熟知しているため、ローカルテーブルに対する読み書きが圧倒的に高速です。
  • 弱み: Access以外のデータベース(SQL Serverなど)への接続には向きません。

ADO (ActiveX Data Objects)

  • 役割: 外部のデータベース(SQL Server, Oracle, MySQLなど)と通信するための「万能エンジン」。
  • 強み: ネットワーク越しに他のサーバーへ接続するのが得意です。
  • 弱み: Access内部の操作においては、DAOに比べると少しオーバーヘッド(処理の重み)があります。

衝突のメカニズム

問題は、どちらのライブラリにも`Recordset`(レコードセット)や`Database`(データベース)といった、全く同じ名前のオブジェクトが存在することです。

あなたがコードに `Dim rs As Recordset` と書いたとき、VBAはこうパニックを起こします。
> 「えっ、DAOのRecordsetのこと? それともADOのRecordsetのこと? 教えてくれないと動けないよ!」

これが、エラーの正体です。

2. 解決策その1:完全修飾名(Fully Qualified Name)を使う

最も確実で、アーキテクトが推奨する解決策は、「どのライブラリのオブジェクトか」を常に明示することです。これを「完全修飾」と呼びます。

  • ❌ ダメな例(曖昧)

`Dim rs As Recordset`

  • ✅ プロの例(明確)

`Dim rsDao As DAO.Recordset`
`Dim rsAdo As ADODB.Recordset`

このように、`DAO.` や `ADODB.` という「苗字」を付けてあげることで、VBAは迷うことなく正しいオブジェクトを呼び出すことができます。

3. 解決策その2:命名規則(プレフィックス)の徹底

コードが長くなってくると、毎回 `DAO.Recordset` と書くのは少し手間ですし、コードが読みづらくなることもあります。そこで、変数名自体にルールを持たせる「プレフィックス命名規則」を導入しましょう。

私が現場で推奨しているルールはこれです。

オブジェクト種別 DAO用プレフィックス ADO用プレフィックス
Database / Connection `dbDao` `cnAdo`
Recordset `rsDao` `rsAdo`
Command `cmdDao` `cmdAdo`

このルールを守るだけで、「あ、この変数は外部サーバー(ADO)から持ってきたデータだな」「これはローカル(DAO)の操作だな」というのが、一目で判別できるようになります。

4. 実践:DAOとADOを共存させる黄金のテンプレート

それでは、実際にこれらを組み合わせて使うコードを見てみましょう。
「SQL Serverからデータを取得し(ADO)、その結果をAccessのローカルテーブルに書き込む(DAO)」という、実務で非常によくあるシナリオです。

Option Compare Database
Option Explicit

' -------------------------------------------------------------------------
' 処理名:SyncExternalData
' 概要  :SQL Server(ADO)からデータを取得し、ローカルのWorkTable(DAO)へ転送する
' -------------------------------------------------------------------------
Public Sub SyncExternalData()
    
    ' --- 変数宣言:プレフィックスによる明確な使い分け ---
    Dim cnAdo As ADODB.Connection      ' ADOの接続オブジェクト
    Dim rsAdo As ADODB.Recordset       ' ADOのレコードセット
    
    Dim dbDao As DAO.Database          ' DAOのデータベースオブジェクト
    Dim rsDao As DAO.Recordset         ' DAOのレコードセット
    
    Dim strSql As String
    Dim strConn As String
    
    ' 接続文字列(環境に合わせて書き換えてください)
    strConn = "Provider=SQLOLEDB;Data Source=YourServer;Initial Catalog=YourDB;Integrated Security=SSPI;"
    ' 取得するSQL
    strSql = "SELECT ID, UserName FROM Users WHERE Active = 1"
    
    On Error GoTo ErrorHandler

    ' =====================================================================
    ' 1. ADOによる外部データの取得
    ' =====================================================================
    Set cnAdo = New ADODB.Connection
    cnAdo.Open strConn
    
    Set rsAdo = New ADODB.Recordset
    ' カーソルタイプなどを指定して開く
    rsAdo.Open strSql, cnAdo, adOpenStatic, adLockReadOnly
    
    ' =====================================================================
    ' 2. DAOによるローカルへの書き込み
    ' =====================================================================
    Set dbDao = CurrentDb
    ' ローカルのWorkTableを編集モードで開く
    Set rsDao = dbDao.OpenRecordset("WorkTable", dbOpenDynaset)
    
    ' ADOのデータをDAOへ流し込むループ
    Do Until rsAdo.EOF
        rsDao.AddNew                ' 新規レコード作成
        rsDao!UserID = rsAdo!ID     ' ADOの値をDAOへ代入
        rsDao!UserName = rsAdo!UserName
        rsDao.Update                ' 保存
        
        rsAdo.MoveNext              ' 次のレコードへ
    Loop
    
    MsgBox "同期が完了しました!", vbInformation

CleanUp:
    ' =====================================================================
    ' 3. オブジェクトのライフサイクル管理(後始末)
    ' =====================================================================
    ' 閉じる順番は「開いた逆」が鉄則です。
    ' また、メモリリークを防ぐため、必ずNothingで解放します。
    On Error Resume Next
    If Not rsAdo Is Nothing Then
        If rsAdo.State = adStateOpen Then rsAdo.Close
        Set rsAdo = Nothing
    End If
    If Not cnAdo Is Nothing Then
        If cnAdo.State = adStateOpen Then cnAdo.Close
        Set cnAdo = Nothing
    End If
    If Not rsDao Is Nothing Then
        rsDao.Close
        Set rsDao = Nothing
    End If
    Set dbDao = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

このコードの「プロのポイント」

1. 完全修飾名の使用: `ADODB.Connection` や `DAO.Database` と書くことで、参照設定が重複していてもエラーになりません。
2. 命名規則の徹底: `cnAdo`, `rsAdo`, `dbDao`, `rsDao`。これだけで、コードの「動きの方向」が視覚的にわかります。
3. ライフサイクルの管理: `CleanUp` セクションで、開いたものを確実に閉じ、`Nothing` を代入してメモリを解放しています。これは大規模なシステムを安定させるための必須技術です。

まとめ:ここをクリアすれば、もう怖くない

DAOとADOの共存は、一見すると複雑なパズルに見えるかもしれません。しかし、

  • 「苗字(ライブラリ名)」を付けて呼ぶこと
  • 「変数名(プレフィックス)」に役割を持たせること

この2点を守るだけで、衝突の恐怖からは完全に解放されます。

これからは、単に「動くコード」を書くのではなく、「誰が見ても、どのエンジンを使っているか一目でわかる、美しい設計」を目指していきましょう。その積み重ねが、あなたを一流のエンジニアへと引き上げてくれます。

応援していますよ。頑張ってくださいね!

タイトルとURLをコピーしました