【テクニカル・上級編】QueryDefの「隠し属性」を活用したシステム管理術 – Access VBA解析バイブル

スポンサーリンク

Accessの深淵:QueryDefの「隠し属性」でメタデータ駆動型アーキテクチャを構築する

Access開発の現場において、`QueryDef`は単なるSQLの入れ物ではない。それはデータベースの「実行計画」そのものであり、適切に管理すればシステム全体の保守性を劇的に向上させる強力なメタデータ・コンテナとなり得る。

多くの開発者は、クエリ名を `qry_Sales_Monthly_01` のように命名規則だけで管理しようとするが、それは泥沼への入り口だ。本稿では、`QueryDef`の隠れた機能である`Properties`コレクションを直接操作し、システム管理情報(作成者、用途、依存関係)をオブジェクト自体に埋め込む「メタデータ駆動型管理」の極意を伝授する。

—

1. なぜ「Properties」コレクションなのか

Accessの`QueryDef`オブジェクトには、定義されていないプロパティを動的に追加できる領域がある。特に`Description`プロパティはUI上でも閲覧可能だが、それ以外の独自プロパティを`DAO.Property`として注入することで、外部ドキュメントを一切参照せずとも、コードからクエリの「出自」と「性格」を特定できる。

これは、システムが巨大化し、誰も全クエリの役割を把握できなくなった「レガシーの墓場」と化した現場において、唯一の救いとなる。

—

2. 実装:メタデータ注入エンジンの構築

まずは、任意の`QueryDef`にカスタム属性を付与し、メモリをリークさせずに安全に操作するためのユーティリティクラスの骨格を示そう。

‘ @Module: QueryMetadataManager
Option Compare Database
Option Explicit

‘ クエリにカスタムプロパティを注入する
Public Sub SetQueryMetadata(queryName As String, propName As String, propValue As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim prp As DAO.Property

Set db = CurrentDb
Set qdf = db.QueryDefs(queryName)

On Error Resume Next
‘ プロパティが存在しない場合は作成
Set prp = qdf.Properties(propName)
If Err.Number <> 0 Then
Set prp = qdf.CreateProperty(propName, dbText, propValue)
qdf.Properties.Append prp
Else
prp.Value = propValue
End If
On Error GoTo 0

‘ 明示的なオブジェクト解放(メモリ最適化の鉄則)
Set prp = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub

この手法の肝は、`On Error Resume Next`を局所的に使用し、プロパティの有無を型安全に判定することにある。AccessのDAOはCOMラッパーであるため、不適切なオブジェクト解放は即座にメモリリーク(特にバックエンドDB接続の切断ミス)に繋がる。

—

3. パラメータクエリの動的生成と「疎結合」化

シニアエンジニアであれば、クエリのSQLをハードコーディングすることの危険性は理解しているはずだ。動的SQLを構築する際は、`QueryDef.SQL`を直接書き換えるのではなく、`Parameters`コレクションを介して型を指定する。

これにより、SQLインジェクションのリスクを排除し、JET/ACEデータベースエンジンに対して最適な実行計画を強制できる。

Public Sub ExecuteDynamicParamQuery(qdfName As String, paramDate As Date)
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset

Set qdf = CurrentDb.QueryDefs(qdfName)

‘ 実行計画のキャッシュを最大限に活用する
qdf.Parameters(“[targetDate]”) = paramDate

Set rs = qdf.OpenRecordset(dbOpenSnapshot)

‘ …処理…

‘ 逆順の解放:Recordset -> QueryDef の順序を守るのが伝説の流儀
rs.Close: Set rs = Nothing
qdf.Close: Set qdf = Nothing
End Sub

—

4. システム間連携を見据えた「クエリ辞書」の抽出

管理下の全クエリから、埋め込んだメタデータを一括抽出するプロシージャを持つことは、システム監査において極めて強力だ。

Public Sub ExportQueryManifest()
Dim qdf As DAO.QueryDef
Dim prp As DAO.Property

‘ 隠し属性を列挙し、CSV等のログに出力するロジック
For Each qdf In CurrentDb.QueryDefs
Debug.Print “Query: ” & qdf.Name
For Each prp In qdf.Properties
‘ DAO.PropertyのTypeを判定し、必要なメタデータのみ抽出
If InStr(prp.Name, “Custom_”) > 0 Then
Debug.Print ” -> ” & prp.Name & “: ” & prp.Value
End If
Next prp
Next qdf
End Sub

—

5. 伝説的アーキテクトからの提言

Accessを単なる「小規模ツール」として扱うか、それとも「メタデータ駆動型のフレームワーク」として構築するか。その境界線は、こうした「本来目に見えない情報」をオブジェクトのライフサイクルの中にどれだけ組み込めるかに懸かっている。

1. メモリを信じるな: `Set = Nothing`を省略するエンジニアに、堅牢なシステムを構築する資格はない。特に`QueryDef`をループで回す際は、`DAO.Database`の参照をループの外に置くなど、再計算コストを最小化せよ。
2. 文書化を自動化せよ: 仕様書が陳腐化するのは世の常だ。コードの中に、実行可能な仕様書(メタデータ)を埋め込め。それが最強の保守ツールになる。
3. APIを知る: Accessは、Windows APIを呼び出せば、メモリの強制開放やOSイベントのフックさえ可能だ。だが、まずはADO/DAOの標準的な作法を極限まで突き詰めること。基礎を無視した最適化は、ただの「場当たり的な延命」に過ぎない。

この知識を武器に、貴殿が管理するAccessシステムが、10年後もなお静かに、かつ確実に動き続けることを期待する。

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