フォームの「イベント地獄」を卒業せよ:ActiveControlを活用した汎用バリデーション設計の極意
Access開発において、最も生産性を低下させる要因は「コントロール単位でのコード記述」だ。
テキストボックスを10個追加するたびに、同じような「未入力チェック」や「文字数制限」のコードを`BeforeUpdate`にコピペしているようでは、プロフェッショナルとは呼べない。
メンテナンスのたびに10箇所のコードを修正し、漏れが発生してバグを生む。そんな泥沼から脱却し、「フォームのイベントを中央集権的に制御する」アーキテクチャを伝授する。
—
なぜ「個別記述」が地獄への入り口なのか
初心者は、各コントロールのイベントに直接ロジックを書きたがる。しかし、これは以下の理由で「負債」となる。
1. 疎結合の欠如: UI(フォーム)とロジック(バリデーション)が密結合になり、仕様変更時に修正箇所を特定できない。
2. 冗長なコード: 同じロジックが各所に分散し、DRY原則(Don’t Repeat Yourself)に反する。
3. 拡張性の欠如: 新しい入力項目が増えるたび、イベントプロシージャを量産しなければならない。
我々エンジニアが目指すべきは、「コントロールの定義に基づいた動的なバリデーション」である。
—
ActiveControlを活用した「汎用バリデーション」の実装
Accessには、現在フォーカスがあるコントロールを指し示す強力なポインタ `Screen.ActiveControl` が存在する。これを利用し、各コントロールの `BeforeUpdate` イベントを、単なる「バリデーションエンジンへのトリガー」に格下げするのだ。
1. バリデーションエンジン(標準モジュール)
まずは、チェックロジックを一手に引き受ける司令塔を作成する。
‘ 標準モジュール: modValidator
Option Compare Database
Option Explicit
‘ 汎用バリデーション関数
‘ 引数:
‘ ctl: チェック対象のコントロール
‘ msg: エラー時に表示するメッセージ
Public Function ValidateRequired(ByRef ctl As Control, Optional ByVal msg As String = “必須項目です。”) As Boolean
‘ 値がNullまたは空文字ならエラー
If IsNull(ctl.Value) Or Trim(ctl.Value) = “” Then
MsgBox msg, vbExclamation, “入力エラー”
ctl.SetFocus
ValidateRequired = False ‘ 失敗
Exit Function
End If
ValidateRequired = True ‘ 成功
End Function
2. フォーム側での呼び出し(極限まで簡略化)
各コントロールの `BeforeUpdate` には、たった一行のコードしか書かせない。
‘ フォームの各コントロールのイベント
Private Sub txtUserName_BeforeUpdate(Cancel As Integer)
‘ 成功しなければイベントをキャンセル(更新を阻止)
If Not ValidateRequired(Screen.ActiveControl, “氏名を入力してください。”) Then
Cancel = True
End If
End Sub
—
プロダクション環境における「堅牢性」へのこだわり
上記のコードをさらに一段上のレベルへ昇華させるための、伝説的な知見を共有する。
注意点:CurrentDbとオブジェクトのライフサイクル
バリデーション内で `CurrentDb` を多用してテーブルと突き合わせを行う場合、注意が必要だ。`CurrentDb` は呼び出すたびに新しいインスタンスを生成する可能性がある。
パフォーマンスを重視するなら、`DAO.Database` 変数をモジュールレベルで保持し、必要に応じて `Set db = CurrentDb` を行うか、あるいは `OpenRecordset` の際も適切なキャッシュ戦略をとるべきだ。
「タグ」によるメタデータ駆動開発
さらに進んだ手法として、コントロールの「タグ(Tag)」プロパティにバリデーションルールを埋め込む方法がある。
‘ 例: タグに “Required;Numeric” と書いておけば、
‘ 関数側で “Required” を見つけて必須チェック、”Numeric” を見つけて数値チェックを行う
If InStr(ctl.Tag, “Required”) > 0 Then
‘ 必須チェック処理
End If
このように、コントロールのプロパティを「設定ファイル」として扱うことで、VBAのコードを一切書かずにチェックルールを追加・変更できるメタデータ駆動アーキテクチャが完成する。
—
結論:コードを書くほど、システムは脆弱になる
優れたエンジニアは、「いかにして書くコードを減らすか」に心血を注ぐ。
今回紹介した `ActiveControl` を起点としたバリデーションは、その第一歩だ。
- 保守性: チェックロジックは `modValidator` に集約されている。
- 拡張性: タグプロパティを活用すれば、UI側をいじるだけでルールを適用できる。
- 堅牢性: `Cancel = True` による制御で、不正なデータがデータベースに流入するのを確実に防ぐ。
Access開発は、単なる「画面作成」ではない。オブジェクトモデルを掌握し、いかにシステムを構造化するかという「設計の戦い」だ。今日から、そのイベントプロシージャのコピペ作業を卒業し、真のアーキテクトとしての設計を開始してほしい。
