フォームの「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の防波堤を盤石にすることこそが、システム全体を「プロフェッショナルな領域」へと昇華させる唯一の道である。
コードは嘘をつかない。書いた人間の品格が、そのままシステムの安定性に直結するのだ。
