「勝手に保存された?」を防ぐ!Access VBAでデータの命綱「Dirty」プロパティを完全に乗りこなす方法
こんにちは!いつも業務システムの開発や改善、お疲れ様です。
Accessでフォームを作っているとき、こんなユーザーの悲鳴を聞いたことはありませんか?
「修正するつもりじゃなかったのに、うっかりキーボードに触れてデータが変わっちゃった!」
「入力を途中でやめて画面を閉じたら、中途半端なデータがそのまま保存されてる!」
Excelに慣れているユーザーからすると、「保存ボタンを押していないのに、勝手にデータが保存される」というAccessの挙動は、時に恐怖でしかありません。
実は、Accessには「レコード移動や画面を閉じるタイミングで、変更を自動的に保存する」という強力な仕組み(暗黙の自動保存)が備わっています。これは便利な反面、ユーザーの誤操作によるデータ破損の原因にもなります。
そこで今回は、フォームが「今、編集されて保存されていない状態か」を監視する「Dirty(ダーティ)プロパティ」を使いこなし、未保存データの破棄や保存をスマートにコントロールする設計を学びましょう。
ここをクリアすれば、Access VBAの基本、そしてデータ制御の極意はバッチリマスターできますよ!
—
1. なぜ勝手に保存される?Accessの「自動保存」の仕組み
まずは、Accessが裏側でどのようにデータを保存しているのか、そのライフサイクル(寿命とタイミング)をイメージしてみましょう。
【一般的な編集の流れ】
[1. 表示中] (Dirty = False: きれいな状態)
↓ ユーザーが1文字でも入力する
[2. 編集完了前] (Dirty = True: 汚れた=未保存の状態)
↓
↓ ★以下のイベントが発生すると、Accessは「自動的」に保存処理に走る!
↓ ・別のレコードに移動した
↓ ・フォームを閉じた
↓ ・Access自体を終了した
↓
[3. 自動保存実行] → テーブルへ書き込み (Dirty = False に戻る)
図のように、Accessは「Dirty(汚れた=未保存)」になったデータを、ユーザーが明示的に保存ボタンを押さなくても、特定のタイミングで親切に(お節介に)自動保存してしまいます。
この自動保存が実行される直前に割り込み、「本当に保存していいですか?」とユーザーに問いかけるためのフック(引き金)が、今回紹介するテクニックです。
—
2. 救世主「Dirty」プロパティと「BeforeUpdate」イベント
この問題をエレガントに解決するために、2つの武器を使います。
1. `Me.Dirty` プロパティ
フォームのデータが「変更されていて、まだ保存されていない状態」のときに `True` になります。初期状態や保存直後は `False` です。
2. フォームの `BeforeUpdate`(更新前処理)イベント
データがテーブルに書き込まれる「直前」に発生するイベントです。このイベントの中で「保存するかどうか」を判定し、嫌なら保存をキャンセル(強制割り込み中止)できます。
—
3. 【実践】コピペで使える!未保存データ制御の黄金コード
それでは、実際の現場でそのまま使える美しいコードを見てみましょう。
フォームのプロパティシートを開き、「更新前処理(BeforeUpdate)」イベントに以下のコードを記述します。
Private Sub Form_BeforeUpdate(Cancel As Integer)
‘ ————————————————————————-
‘ 目的: データの変更を検知し、ユーザーに保存の意思確認を行います。
‘ ライフサイクル: レコード保存(移動や閉じる動作含む)の直前に実行されます。
‘ ————————————————————————-
Dim言いたいこと As String
Dim userResponse As VbMsgBoxResult
‘ フォームが「Dirty(編集されて未保存)」状態か確認
‘ ※BeforeUpdateイベントが走っている時点で通常はTrueですが、
‘ 明示的に意識するためにDirtyプロパティの存在を意識しましょう。
If Me.Dirty Then
‘ ユーザーに確認メッセージを表示
userResponse = MsgBox( _
Prompt:=”データが変更されています。変更内容を保存しますか?” & vbCrLf & _
“[はい] : 変更を保存して進みます。” & vbCrLf & _
“[いいえ] : 変更を破棄して元に戻します。” & vbCrLf & _
“[キャンセル] : 編集画面に戻ります。”, _
Buttons:=vbYesNoCancel + vbQuestion + vbDefaultButton1, _
Title:=”変更の確認” _
)
Select Case userResponse
Case vbYes
‘ [はい] の場合:何もしなければ、そのまま保存処理が続行されます。
‘ (Accessが自動で保存を完了してくれます)
Case vbNo
‘ [いいえ] の場合:変更をすべて取り消し、元の状態に戻します。
‘ Undoメソッドを呼び出すことで、入力前の状態に一瞬でロールバックします。
Me.Undo
Case vbCancel
‘ [キャンセル] の場合:保存処理自体を「キャンセル」します。
‘ 引数の Cancel に True (非ゼロ) を代入することで、
‘ 画面遷移や「閉じる」動作をその場でストップさせ、編集状態を維持します。
Cancel = True
End Select
End If
End Sub
コードのここがポイント!
- `Cancel = True` の魔力
`BeforeUpdate` イベントの引数である `Cancel` に `True` を渡すと、Accessは「あ、保存しちゃダメなんだな。今の画面とレコード位置をそのままキープしよう」と理解して、すべての動きをストップします。
- `Me.Undo` のスマートさ
ユーザーが「いいえ(破棄)」を選んだ際、テキストボックスの内容を一つずつ消す必要はありません。`Me.Undo` を1行書くだけで、そのレコードのすべての変更が「無かったこと」になります。
—
4. 初心者が絶対につまずく「3つの罠」と回避策
Dirtyプロパティを扱い始めると、誰もが一度は遭遇する定番のエラーや無限ループがあります。先輩として、あらかじめその回避策を伝授しておきますね。
罠①:「保存ボタン」を自作したときの二重メッセージ
「保存」ボタンをフォームに配置して、そのクリックイベントに `DoCmd.RunCommand acCmdSaveRecord`(レコード保存)などを書いている場合、以下のような流れになります。
1. 保存ボタンを押す ➔ 保存コマンドが走る
2. 保存が走るため、裏で `BeforeUpdate` イベントが呼び出される
3. `BeforeUpdate` 内で「保存しますか?」と聞かれる(1回目)
4. 保存が完了する
5. 画面を閉じようとすると、なぜかまた「保存しますか?」と聞かれる(2回目)
【回避策】
自作の保存ボタンを置く場合、保存処理自体は `BeforeUpdate` イベントに一本化しましょう。保存ボタンのクリックイベントには、単に「レコードを保存するアクション」だけを書くのが、Accessの美しい設計作法です。
‘ 保存ボタンのクリックイベント
Private Sub btnSave_Click()
On Error Resume Next
‘ 単に保存を実行するだけ。実際の「確認」はBeforeUpdateに任せる!
DoCmd.RunCommand acCmdSaveRecord
If Err.Number = 0 Then
MsgBox “保存しました。”, vbInformation, “完了”
End If
End Sub
罠②:VBAコードから `Me.Dirty = False` を呼び出す時のエラー
VBAの中で、強制的にデータを保存させたいときに `Me.Dirty = False` と書くテクニックがあります(DirtyをFalseに書き換える=保存を完了させる、という意味になります)。
しかし、入力ルール(テーブルの「値要求」など)に違反している状態でこれを実行すると、「ランタイムエラー 2101: 入力した値がこのプロパティに対して正しくありません」という不親切なエラーでプログラムが強制終了してしまいます。
【回避策】
コードから強制保存を行う場合は、必ずエラーハンドリング(`On Error`)を行うか、事前に未入力チェックを済ませておきましょう。
罠③:コンボボックスやチェックボックスの「規定値」での誤作動
フォームを開いた瞬間に、VBAコードで初期値を代入(例:`Me.txtDate = Date`)するような設計にしていると、ユーザーが何も触っていないのに最初から `Me.Dirty` が `True` になってしまいます。
【回避策】
初期値を入れたい場合は、コントロールのプロパティにある「既定値(Default Value)」に設定するか、フォームの `Load` イベント等で初期値を代入した後に、明示的に `Me.Undo` をするか、あるいは最初からテーブル側の既定値機能を使うようにしましょう。
—
5. まとめ:Accessの振る舞いをコントロールする快感
お疲れ様でした!
今回学んだ内容をシンプルに整理しましょう。
1. Accessは何かあるとすぐに自動保存しようとする性質がある。
2. それを食い止める防波堤が `BeforeUpdate` イベントである。
3. 編集状態かどうかを判定するセンサーが `Me.Dirty` である。
4. 変更をなかったことにするのが `Me.Undo`、処理を止めるのが `Cancel = True` である。
この4つの関係性を理解できれば、ユーザーが意図しないデータの書き換えや、不完全なデータの保存を100%防ぐことができるようになります。
「Accessって勝手に動いて使いにくいな…」から、「Accessの動きを完全に手のひらで転がしているぞ!」という感覚に変わる瞬間、とてもワクワクしませんか?
一歩ずつコードを書いて、ぜひ手元のフォームで試してみてください。エラーが出たら、この記事の「罠」のセクションを読み返してみてくださいね。
ここをクリアすれば、Access VBAの基本はバッチリですよ!応援しています!
