【テクニカル・上級編】フォームの「BeforeUpdate」イベントで実装する、複雑な入力値妥当性チェック – Access VBA解析バイブル

スポンサーリンク

フォームの「BeforeUpdate」を制する者こそが、Accessの真の支配者である

Access開発において、初心者は「更新後処理(AfterUpdate)」で制御を試みるが、それは素人の所業だ。データがテーブルに書き込まれた後に「やり直し」を命じるのは、メモリとトランザクションの無駄であり、整合性の崩壊を招く。

真のエンジニアは、「BeforeUpdate」イベントを唯一の防波堤とする。 ここでCancel = Trueを叩き込むことは、物理的な破壊を防ぐ唯一の作法である。本稿では、レガシー環境を支配し、堅牢なシステムを構築するための極限の知見を授ける。

1. BeforeUpdateの本質:未確定状態の「揺らぎ」を封殺する

`BeforeUpdate`イベントは、AccessのフォームがDirty(変更)状態からClean状態へ遷移する直前にのみ発生する。この「書き込み直前」という刹那において、我々はメモリ上のバッファを監視し、業務ロジックの不整合を叩き落とさなければならない。

実装の鉄則:オブジェクトのスコープと解放

複雑な妥当性チェックを行う際、DAOやADOのRecordsetを不用意に開いてはならない。メモリリークを誘発するようなコードは、長期間稼働する業務システムにとって致命的な毒となる。

Private Sub Form_BeforeUpdate(Cancel As Integer)
‘ メモリリークを許さない。オブジェクト変数は必ず局所化し、明示的に解放する
Dim db As DAO.Database
Dim rs As DAO.Recordset

‘ 複雑な妥当性チェック用のビジネスロジック関数を呼び出す
If Not ValidateBusinessRules(Me) Then
‘ ユーザーへの通知とキャンセル処理
MsgBox “入力データに致命的な不整合があります。”, vbCritical, “システム整合性エラー”
Cancel = True ‘ ここで書き込みを強制停止する
Me.Undo ‘ 変更を破棄してクリーンな状態へ戻す
End If

‘ 終了処理:Set Nothingは儀式ではない、防衛的プログラミングの要である
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set db = Nothing
End Sub

2. 複数フィールドにまたがる「クロスチェック」の極意

単一項目のチェックはUIのバリデーションに任せればよい。我々が扱うのは「フィールドAとBの相関関係」や「外部システムとの連携整合性」といった、データベース設計の奥深くに沈む制約だ。

ここで重要なのは、「APIを叩く」あるいは「複雑なクエリを投げる」際に、メインスレッドを停止させないことである。Windows APIを活用し、必要であれば非同期的な挙動をシミュレートする。

高度な妥当性チェックの実装例

Private Function ValidateBusinessRules(frm As Form) As Boolean
‘ 業務ルール:開始日と終了日の整合性、および在庫チェック
‘ ここではあえて CurrentDb を使わず、接続プールを意識した設計にする
Dim sql As String

‘ 複雑な演算はVBAで書かず、SQLの集合演算に任せる(Accessのエンジンを信じろ)
sql = “SELECT Count() FROM T_Inventory WHERE ItemID = ” & frm!ItemID & _
” AND StockCount < " & frm!RequiredQty ' DAO.Databaseを使い回さず、CurrentDbを評価して利用する If DCount("", "T_Inventory", "ItemID=" & frm!ItemID & " AND StockCount < " & frm!RequiredQty) > 0 Then
ValidateBusinessRules = False
Exit Function
End If

ValidateBusinessRules = True
End Function

3. レガシー環境を生き抜くための「防御的コーディング」

Accessはマルチユーザー環境において、楽観的排他制御(Optimistic Concurrency)を行う。しかし、BeforeUpdateでのチェックが甘ければ、競合したデータが「保存されてしまう」。

守護神としてのWindows API

長時間処理が発生する場合、フォームが「応答なし」と見なされるのを防ぐため、`DoEvents`の乱用は避け、Windows APIで強制的にメッセージループを処理せよ。

‘ API宣言(標準モジュールに配置)
Private Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)

‘ 妥当性チェックの最中にUIをフリーズさせない工夫
Public Sub ForceUIUpdate()
DoEvents
Sleep 10 ‘ CPU負荷を抑えつつ描画を更新する
End Sub

4. チーフアーキテクトからの提言

Access開発において最も愚かなことは、「フォームに全てのコードを書くこと」だ。
BeforeUpdateに記述すべきは「チェックのトリガー」と「キャンセル処理」のみである。真のバリデーションロジックは必ず「クラスモジュール」にカプセル化せよ。

  • インターフェースを意識せよ: 妥当性チェックは `IValidator` のようなインターフェースを想定した設計にすべきだ。
  • 例外処理を隠蔽するな: `On Error GoTo 0` で逃げず、エラーをスタックトレースとして記録する仕組みを構築せよ。
  • メモリ解放の徹底: `Set Object = Nothing` を書かないエンジニアに、大規模システムを触らせる資格はない。

Accessは「おもちゃ」ではない。適切に制御されたAccessは、どんな高価なWebフレームワークよりも速く、そして確実に現場の業務を支える。このBeforeUpdateの防波堤を盤石にすることこそが、システム全体を「プロフェッショナルな領域」へと昇華させる唯一の道である。

コードは嘘をつかない。書いた人間の品格が、そのままシステムの安定性に直結するのだ。

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