Access VBAの「死」を回避せよ:`CurrentData.AllTables`を用いた防御的プログラミングの極意
Access開発の現場において、最も初歩的でありながら、最も多くのシステムを崩壊させる原因。それは「存在しないオブジェクトへの安易なアクセス」だ。
リンクテーブルが切断された瞬間、あるいはユーザーが誤ってテーブルを削除した瞬間、君の書いた `DoCmd.OpenTable` や `CurrentDb.Execute` は無慈悲なランタイムエラーを吐き出し、画面の前でユーザーを呆然とさせる。
「エラー処理で拾えばいい」? 甘い。エラーハンドリングは最後の砦であり、設計の免罪符ではない。 プロのエンジニアであれば、エラーが発生する前に「その道が通行可能か」を判断する防御的設計を徹底すべきだ。
今回は、Accessオブジェクトモデルの深層に触れ、`CurrentData.AllTables` を使った「壊れないコード」の書き方を伝授する。
—
なぜ `On Error Resume Next` で誤魔化してはいけないのか
初学者が陥る罠は、テーブルアクセスの直前に `On Error Resume Next` を置き、結果を無視して処理を強行することだ。これは、「ブレーキが壊れていると分かっているのに、アクセルを踏み込む」のと同じだ。
システム開発において、エラーを無視することは「異常を隠蔽する」ことと同義である。もしテーブルが消えているのなら、プログラムは即座に停止し、管理者に「環境異常」を通知するのが正しい挙動だ。
我々が目指すべきは、以下のステップだ。
1. 存在を確認する(Validation)
2. 存在しない場合の代替ルートを用意する(Fallback)
3. 予期せぬ事態には正確なエラーログを残す(Logging)
—
実践:堅牢なテーブル存在確認関数
`CurrentData.AllTables` は、Accessのコンテナ内に存在する全テーブルを列挙するコレクションだ。これをラップし、再利用可能な関数を作成するのが、保守性を高める唯一の解だ。
‘ @brief 指定されたテーブルがデータベース内に存在するかを判定する
‘ @param tableName 存在を確認したいテーブル名
‘ @return Boolean 存在すればTrue
Public Function IsTableExists(ByVal tableName As String) As Boolean
Dim tbl As AccessObject
‘ CurrentData.AllTables は、リンクテーブルを含む全てのテーブルを内包する
‘ コレクションをイテレートし、名前を突き合わせる
For Each tbl In CurrentData.AllTables
If tbl.Name = tableName Then
IsTableExists = True
Exit Function
End If
Next tbl
IsTableExists = False
End Function
—
プロダクションコード:防御的アクセスの実装例
この関数をどのように業務ツールに組み込むか。実務でそのまま使える設計パターンを示す。
Public Sub ProcessData()
Const TARGET_TABLE As String = “T_SalesData”
‘ 1. 事前検証:テーブルが存在しなければ処理を中断し、ユーザーに警告する
If Not IsTableExists(TARGET_TABLE) Then
MsgBox “エラー: 必要なテーブル ‘” & TARGET_TABLE & “‘ が見つかりません。” & vbCrLf & _
“リンク切れの可能性があります。システム管理者に連絡してください。”, vbCritical
Exit Sub
End If
‘ 2. 処理実行:検証済みのため、ここは安心して記述できる
On Error GoTo ErrorHandler
Dim db As DAO.Database
Set db = CurrentDb
‘ テーブル操作のロジックをここに記述
Exit Sub
ErrorHandler:
‘ 3. ここでのエラーは「存在確認漏れ」ではなく「予期せぬ例外」
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical
End Sub
—
アーキテクトからの助言:なぜこの設計が最強なのか
1. パフォーマンスの最適化:
`CurrentData.AllTables` は、`DAO.TableDefs` よりもアクセスが高速で、かつリンク切れのテーブルに対しても安定して情報を返してくれる。`TableDefs` は存在しないテーブルにアクセスしようとすると即座にエラーを投げるが、`AllTables` はコレクションとして静的に存在するため、エラーハンドリングのコストが不要だ。
2. 保守性の向上:
「テーブルの存在確認」というロジックを関数化することで、将来的に「テーブル名が動的に変わる」といった要件変更が起きた場合も、修正箇所は関数内の一点のみで済む。
3. 責任の分離:
ビジネスロジック(データの加工)と、環境の整合性チェックを分けることで、コードの可読性が飛躍的に向上する。後からこのコードを見た後輩が「なぜここでIF文があるのか」を迷うことはない。
最後に:コードは「生き物」である
Accessで構築されたシステムは、多くの場合、ネットワーク越しにリンクテーブルを参照するような不安定な環境で運用される。「テーブルは常にそこにあるとは限らない」。この前提に立ってコードを書く者だけが、真に信頼されるツールを納品できる。
さあ、君のコードから `On Error Resume Next` を消し去り、この防御的なアーキテクチャを実装してほしい。それが、卓越した業務自動化エンジニアへの第一歩だ。
