【初心者必見】Access VBAで「レコード保存」を強制!バリデーション漏れを防ぐ実務テクニック
皆さん、Access VBAの世界へようこそ!
今日は、フォームでのデータ入力で「あれ?保存されてない!」なんて経験をしたことがある、そんなあなたのために、とっておきのテクニックをお教えします。
マクロの記録から一歩進んで、VBAで「レコード保存」を確実に実行する方法。これをマスターすれば、あなたのAccess VBAスキルは格段にレベルアップしますよ。
なぜ「レコード保存」を意識する必要があるのか?
フォームでデータを入力して、次のレコードに移動したり、フォームを閉じたりする際、通常は自動的にレコードが保存されます。
しかし、実はこの自動保存、いくつか落とし穴があるんです。
- BeforeUpdateイベントの挙動: レコードが保存される直前に実行される`BeforeUpdate`イベント。ここでバリデーション(入力値のチェック)を行っている場合、ユーザーが意図せず保存をキャンセルしたり、不正な値のまま次のレコードに移動してしまうと、バリデーションが実行されないままデータが確定してしまう可能性があります。
- ユーザーの誤操作: ユーザーが「保存」ボタンを押さずにフォームを閉じてしまう、なんてことも起こりえますよね。
これらの状況を防ぎ、入力されたデータを確実に確定させるために、VBAから明示的に「レコード保存」を指示する方法が有効なのです。
VBAで「レコード保存」を強制!登場するのは「DoCmd.RunCommand」
ここで登場するのが、Access VBAの強力なコマンド、「`DoCmd.RunCommand`」です。
このコマンドは、Accessのメニューコマンドやボタンのクリックなどを、VBAコードから実行できるようにするものです。
まるで、あなたがキーボードやマウスを操作しているかのように、Accessに指示を送ることができるんですね。
どのコマンドを使う?:`acCmdRecordsGoToNext` と `acCmdRecordsGoToPrevious`
レコード保存を強制するためには、主に以下の2つのコマンドを組み合わせるのが効果的です。
- `acCmdRecordsGoToNext`: 次のレコードに移動するコマンド
- `acCmdRecordsGoToPrevious`: 前のレコードに移動するコマンド
「え?なんで移動するコマンドが保存と関係あるの?」と思いますよね。
実は、レコード移動という操作は、その直前に現在編集中のレコードを「確定」させる(保存する)という挙動をするんです。
つまり、次のレコードに移動させることで、強制的に現在のレコードが保存される、という仕組みを利用するわけです。
実際にコードを書いてみよう!
では、具体的なコードを見ていきましょう。
今回は、「保存」ボタンを作成し、それをクリックしたら現在のレコードを保存するというシナリオで解説します。
1. フォームにボタンを配置する
まず、対象となるフォームを開き、デザインビューに切り替えます。
「フォームデザインツール」の「デザイン」タブから、「ボタン」コントロールを選択し、フォーム上に配置します。
「コマンドボタンウィザード」が表示されたら、「キャンセル」をクリックしてください。後でVBAで設定します。
配置したボタンのプロパティシートを開き、「名前」を分かりやすいもの(例: `btnSaveRecord`)に変更しておきましょう。
2. ボタンのクリックイベントにVBAコードを記述する
ボタンのプロパティシートで、「イベント」タブを選択し、「クリック時」の右側にある「…」ボタンをクリックします。
「ビルド」ダイアログが表示されるので、「コードビルダー」を選択して「OK」をクリックします。
これでVBAエディタが開かれ、ボタンのクリックイベントプロシージャが自動生成されます。
Private Sub btnSaveRecord_Click()
‘ ここにレコード保存を強制するコードを記述します
End Sub
3. DoCmd.RunCommand を使ったレコード保存コード
それでは、`btnSaveRecord_Click()` サブルーチンの中に、レコード保存を強制するコードを記述してみましょう。
Private Sub btnSaveRecord_Click()
‘ — レコード保存を強制するテクニック —
‘ 現在のレコードを確実に保存するために、
‘ 次のレコードへの移動を試みます。
‘ この操作により、現在のレコードの変更が確定(保存)されます。
On Error Resume Next ‘ エラーが発生しても処理を続行する
DoCmd.RunCommand acCmdRecordsGoToNext
On Error GoTo 0 ‘ エラーハンドリングを元に戻す
‘ もし、レコードが1件しかない場合や、
‘ acCmdRecordsGoToNext がエラーになった場合のために、
‘ 前のレコードへの移動も試みます。
‘ こちらも同様に、現在のレコードを保存します。
On Error Resume Next
DoCmd.RunCommand acCmdRecordsGoToPrevious
On Error GoTo 0
‘ — ここまでがレコード保存の強制 —
‘ 保存が成功した後に、ユーザーにメッセージを表示することもできます(任意)
‘ MsgBox “レコードが正常に保存されました。”, vbInformation
End Sub
コードの解説:
- `On Error Resume Next`: この行は、エラーが発生してもプログラムの実行を停止させずに、次の行に進むように指示します。なぜこれが必要かというと、例えばレコードが1件しかない場合などに、`acCmdRecordsGoToNext` を実行するとエラーが発生する可能性があるからです。エラーを無視して処理を続行し、次の `acCmdRecordsGoToPrevious` で保存を試みる、という保険をかけているわけです。
- `DoCmd.RunCommand acCmdRecordsGoToNext`: これが、現在のレコードを保存するための主要なコマンドです。次のレコードへ移動しようとすることで、現在のレコードの変更が確定されます。
- `On Error GoTo 0`: `On Error Resume Next` で有効になったエラーハンドリングを、通常の動作に戻します。これ以降のエラーは、通常通り処理されます。
- `DoCmd.RunCommand acCmdRecordsGoToPrevious`: 上記の `acCmdRecordsGoToNext` が何らかの理由で実行できなかった場合(例えば、レコードが1件しかない場合など)に、代わりに前のレコードへの移動を試みます。これも同様に、現在のレコードを保存する効果があります。
フォームビューで試してみよう!
コードを記述したら、フォームを「フォームビュー」に切り替えて、作成した「保存」ボタンをクリックしてみてください。
何かデータを入力してボタンを押すと、そのデータが確実にデータベースに保存されているはずです。
BeforeUpdateイベントとの連携:バリデーション漏れを防ぐ!
この`DoCmd.RunCommand`のテクニックは、`BeforeUpdate`イベントと組み合わせることで、その真価を発揮します。
例えば、フォームの特定のテキストボックス(例: `txtPrice`)に、必ず数値が入力されているかチェックする`BeforeUpdate`イベントがあるとします。
Private Sub txtPrice_BeforeUpdate()
‘ 入力値が数値かどうかをチェック
If Not IsNumeric(Me.txtPrice.Value) Then
MsgBox “価格には数値を入力してください。”, vbExclamation, “入力エラー”
Me.txtPrice.Undo ‘ 入力値を元に戻す
Me.txtPrice.SetFocus ‘ エラー箇所にフォーカスを移動
‘ ここでレコード保存が強制されると、エラーメッセージが表示された後、
‘ ユーザーは修正する機会を得られます。
Else
‘ 数値であれば、そのまま保存処理に進む
‘ (DoCmd.RunCommand で保存が保証されるので、ここでは特に何もしない)
End If
End Sub
もしユーザーが `txtPrice` に文字列などを入力し、そのまま次のレコードに移動しようとした場合、`acCmdRecordsGoToNext` が `txtPrice_BeforeUpdate` イベントを発火させます。
`txtPrice_BeforeUpdate` イベント内でエラーが検出された場合、`MsgBox` が表示され、`Me.txtPrice.Undo` で入力値が元に戻されます。
そして、`DoCmd.RunCommand` によるレコード移動(保存)処理が `BeforeUpdate` イベントの後に再度実行されるため、不正な値のまま保存されることを防ぎつつ、最終的にレコードの確定(保存)が行われるのです。
陥りやすいエラーと回避策
1. `On Error Resume Next` の乱用
`On Error Resume Next` は便利な反面、予期せぬエラーを見逃してしまうリスクもあります。
今回のケースのように、特定のコマンド実行時のみエラーを無視したい場合は、そのコマンドの前後で `On Error Resume Next` と `On Error GoTo 0` を適切に配置することが重要です。
2. レコードがない場合のエラー
前述の通り、レコードが1件もない、あるいは最後のレコードを編集中の場合などに、`acCmdRecordsGoToNext` や `acCmdRecordsGoToPrevious` でエラーが発生する可能性があります。
`On Error Resume Next` を使用することで、このエラーを回避し、確実な保存処理につなげることができます。
3. フォームのロック
フォーム全体がロックされている場合、`DoCmd.RunCommand` が意図通りに動作しないことがあります。
もし問題が発生する場合は、フォームのプロパティで「データ入力」が「はい」になっているか、また、特定のコントロールがロックされていないか確認してみてください。
まとめ:Access VBAで信頼性を高める第一歩
いかがでしたか?
今日は、`DoCmd.RunCommand` を使ってレコードの「保存」を強制する方法を学びました。
このテクニックを習得することで、
- `BeforeUpdate` イベントでのバリデーションを確実に実行できる
- ユーザーの誤操作によるデータ不整合を防げる
- フォームからのデータ入力の信頼性が格段に向上する
といったメリットがあります。
Access VBAは、このようにちょっとした工夫で、より堅牢で使いやすいアプリケーションを作成できるのが魅力です。
今回学んだ `DoCmd.RunCommand` の活用法は、Access VBAの基本でありながら、実務で非常に役立つテクニックです。
ぜひ、あなたの開発に活かしてみてください。
ここをクリアすれば、Access VBAの基本、特にイベント処理とオブジェクトモデルの連携に関する理解がグッと深まりますよ。
これからも、皆さんのAccess VBAスキルアップを応援していきます!
