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点を守るだけで、衝突の恐怖からは完全に解放されます。
これからは、単に「動くコード」を書くのではなく、「誰が見ても、どのエンジンを使っているか一目でわかる、美しい設計」を目指していきましょう。その積み重ねが、あなたを一流のエンジニアへと引き上げてくれます。
応援していますよ。頑張ってくださいね!
