【実務・中級編】CurrentDb.TableDefsでリンクテーブルの接続先を起動時に自動修復するツール開発 – Access VBA解析バイブル

スポンサーリンク

接続エラーでユーザーを絶望させるな:CurrentDbを掌握する「リンクテーブル自動修復」の極意

Accessアプリケーションの運用において、最も回避すべき「無様なエラー」が何か知っているか?
それは、バックエンドのデータベース(BE)をサーバー移動した際や、ファイルパスが変更された際に発生する「パスが見つかりません」という実行時エラーだ。

一般の解説書では「リンクテーブルマネージャーを使え」と説く。だが、我々プロフェッショナルが構築するツールにおいて、ユーザーにそんな手動操作を強いるのは敗北を意味する。

システム起動時、アプリケーション自らが「自身の接続状況」を診断し、必要であれば静かに、かつ確実にリンクを張り替える。この自己修復能力(Self-Healing)こそが、堅牢なAccessツールの必須要件だ。

今回は、`CurrentDb.TableDefs`を操作し、接続文字列を動的に書き換える「プロダクションレベル」の実装コードとその設計思想を伝授する。

1. なぜ「リンクの張り替え」に失敗するのか

初心者はよく「既存のリンクテーブルを一度削除し、`DoCmd.TransferDatabase`で再作成する」という力技に走る。これは最悪の手だ。
理由は明白。テーブルに設定していたインデックス情報や、リレーションシップ、あるいはフォーム側で保持していたプロパティとの整合性が失われるリスクがあるからだ。

正解は、既存の`TableDef`オブジェクトの`Connect`プロパティを書き換え、`RefreshLink`メソッドを叩くこと。これ以外にない。

重要な注意点:`CurrentDb`の罠

VBAコード内で `CurrentDb.TableDefs` と何度も記述していないか?
`CurrentDb`は呼び出されるたびに新しいデータベースオブジェクトのインスタンスを生成する。ループ内でこれを繰り返すと、パフォーマンスが著しく低下し、最悪の場合リソース不足に陥る。必ず変数(`dao.Database`)にセットしてから操作するのが鉄則だ。

2. 実装:リンクテーブル自動修復プロトコル

以下のコードは、単なるサンプルではない。私が実務で長年磨き上げ、数千人規模のユーザーが利用する環境でも安定稼働を証明してきた「黄金のテンプレート」だ。

黄金のコード:`RelinkTables` プロシージャ

Option Compare Database
Option Explicit

‘—————————————————————————————
‘ Procedure : RelinkTables
‘ Purpose : リンクテーブルの接続先を検証し、不整合があれば自動修復する
‘ Argument : strNewPath – 新しいバックエンドDBのフルパス
‘ Return : Boolean – 成功ならTrue
‘—————————————————————————————
Public Function RelinkTables(ByVal strNewPath As String) As Boolean
On Error GoTo Err_Handler

Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strConnect As String
Dim isSuccess As Boolean

‘ 1. インスタンスを固定(パフォーマンスと安定性の確保)
Set db = CurrentDb

‘ 2. 接続文字列のプレフィックスを定義
‘ Accessファイル(accdb/mdb)の場合は “;DATABASE=” が必須
strConnect = “;DATABASE=” & strNewPath

‘ 3. 全テーブル定義をスキャン
For Each tdf In db.TableDefs
‘ 属性をチェック:リンクテーブルかつ、システムテーブルでないものを対象とする
‘ tdf.Attributes のビット演算でリンクテーブル(dbAttachedTable)を判定
If (tdf.Attributes And dbAttachedTable) <> 0 Then

‘ 現在の接続先と異なる場合のみ更新(無駄な書き込みを抑制)
If tdf.Connect <> strConnect Then
Debug.Print “Repairing: ” & tdf.Name

‘ 接続文字列の書き換え
tdf.Connect = strConnect

‘ リンクの更新(ここで実際に接続テストが行われる)
‘ 失敗した場合はエラーハンドラへ飛ぶ
tdf.RefreshLink
End If

End If
Next tdf

RelinkTables = True
Debug.Print “All tables relinked successfully.”

Exit_Handler:
Set tdf = Nothing
Set db = Nothing
Exit Function

Err_Handler:
‘ リンク失敗時のエラーログ記録(実際にはログテーブルやファイルへ出力すべき)
MsgBox “リンクテーブルの更新に失敗しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical, “致命的エラー”
RelinkTables = False
Resume Exit_Handler
End Function

3. この設計が「堅牢」である理由

① 属性(Attributes)による厳密なフィルタリング

`TableDefs`コレクションには、隠しシステムテーブル(`MSys`から始まるもの)やローカルテーブルも含まれる。これらに対して`Connect`プロパティを操作しようとするとエラーを吐く。
`if (tdf.Attributes And dbAttachedTable) <> 0` というビット判定を用いることで、純粋なリンクテーブルのみを確実に捕捉している。

② 無駄な「書き込み」の排除

`tdf.Connect <> strConnect` の比較を挟んでいる。
Accessのシステムカタログ(`MSysObjects`)への書き込みはコストが高い。すでに正しいパスを指しているテーブルをスキップすることで、起動速度をコンマ数秒、確実に稼いでいる。

③ アトミックな更新

`RefreshLink`を実行した瞬間、Accessはバックエンドファイルへの接続テストを行う。パスが間違っていれば即座にエラーを吐く。この「失敗を即座に検知できる」仕組みが、ツールの信頼性を担保する。

4. 運用上の極意:どこで実行すべきか?

この修復ロジックをどこで呼び出すべきか。答えは「起動時に表示される隠しフォーム(またはメインフォーム)の `Form_Open` イベント」だ。

1. 設定情報の保持: 外部のINIファイルや、レジストリ、あるいはツール内の隠し設定テーブルに「BEの期待されるパス」を保持しておく。
2. 存在チェック: `Dir(strPath)` 関数で、BEファイルが物理的に存在するかまず確認する。
3. 修復実行: ファイルが存在し、かつ現在のリンクが古い場合にのみ、上記の `RelinkTables` を走らせる。

‘ 呼び出し例
Sub AutoExec_Check()
Dim targetPath As String
targetPath = “C:\Database\Backend.accdb” ‘ 本来は動的に取得

If Dir(targetPath) = “” Then
MsgBox “バックエンドDBが見つかりません。ネットワーク接続を確認してください。”
DoCmd.Quit
Else
If Not RelinkTables(targetPath) Then
MsgBox “データベースの同期に失敗しました。”
DoCmd.Quit
End If
End If
End Sub

結論:プロのコードは「沈黙」を守る

優れた業務自動化ツールは、裏側で何が起きているかをユーザーに意識させない。
接続先が変わったことに気づかせず、昨日と同じようにログイン画面を表示させる。その裏で、今回解説した `TableDefs` の精密な操作が行われているのだ。

君が次にAccessツールをデプロイする時は、この「自動修復プロトコル」を必ず組み込んでほしい。それが、メンテナンスコストを劇的に下げ、君の評価を「ただのVBA使い」から「システムアーキテクト」へと引き上げる一歩になるはずだ。

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