【入門編】DAOのRecordsetCloneとフォームの同期:サブフォームのデータ操作を最適化する – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

フォームを動かさずにデータを操る――RecordsetCloneが教える「View」と「Data」の分離術

こんにちは。Access VBAの世界へようこそ。

マクロの記録から一歩踏み出し、「もっとスマートに、もっとプロっぽく動かしたい」と願い始めたあなた。今、あなたは非常に重要な分岐点に立っています。

これまで、フォーム上のデータを書き換えるとき、あなたはこうしていませんでしたか?
「フォームの値を直接書き換える」あるいは「フォームに対して `Requery`(再クエリ)をかける」……。

もちろん、これでも動きます。しかし、これでは「ユーザー体験(UX)」という観点では、まだプロの領域には達していません。大量のデータを更新するたびに画面がチカチカと点滅したり、今見ていたレコードの場所がどこかへ飛んでいってしまったり……。そんな「お作法」のなっていない動きを、ユーザーはストレスに感じます。

今日は、Access VBAの真髄の一つである「RecordsetClone(レコードセット・クローン)」を使い、フォームの表示(View)を一切乱さずに、裏側(Data)で高速かつ正確にデータを操作するテクニックを伝授します。

ここをクリアすれば、あなたの作るツールは「ただ動くもの」から「使い心地のいいプロの道具」へと進化します。準備はいいですか?

1. アーキテクチャの理解:フォームは「窓」、レコードセットは「実体」

まず、設計思想(アーキテクチャ)の話をしましょう。ここを理解せずにコードを書いても、砂上の楼閣です。

Accessにおけるデータ操作には、大きく分けて2つのレイヤーがあります。

1. UIレイヤー(Form): ユーザーが見ている「窓」です。
2. データレイヤー(DAO Recordset): 実際にテーブルに格納されている「実体」です。

多くの初学者は、この2つを混同してしまいます。フォームの値を書き換えるということは、「窓に映っている景色を無理やり書き換える」ようなものです。これでは、元のデータがどうなっているのか、整合性が取れているのかが不透明になりがちです。

プロのエンジニアは、「窓(フォーム)はそのままに、裏側のデータ(Recordset)を直接操作する」という手法を取ります。そのための魔法の杖が `RecordsetClone` なのです。

2. RecordsetCloneとは何か?

`RecordsetClone` とは、一言で言えば「今フォームに表示されているデータセットの、分身(コピー)を作る」機能です。

「分身を作るなら、中身も別物になるのでは?」と思うかもしれません。しかし、ここが巧妙な点です。
`RecordsetClone` で作られるのは、データのコピーではなく、「同じデータソースを指し示している、別のポインタ(指し示す位置)」なのです。

なぜCloneを使うのか?

  • 画面が乱れない: Cloneに対して `MoveFirst` や `MoveNext` を実行しても、ユーザーが見ているフォームのレコード位置は一切動きません。
  • 高速: フォームのコントロール(テキストボックス等)を介さず、メモリ上のレコードセットを直接操作するため、処理が圧倒的に速いです。
  • 安全: フォームの表示状態に依存せず、ロジックに集中できます。

3. 実践:サブフォームのデータをバックグラウンドで一括更新する

では、具体的なシナリオでコードを見てみましょう。
「サブフォームに表示されている『注文明細』の全アイテムに対して、一括で消費税率を適用する」という処理を実装します。

ユーザーがボタンを押したとき、サブフォームがチカチカ動いたり、現在選択している行が勝手に一番上に飛んだりすることなく、静かに、かつ確実に更新を行うコードです。

Option Compare Database
Option Explicit

''' <summary>
''' サブフォーム内の明細データを、画面表示を維持したまま一括更新する
''' </summary>
Public Sub UpdateSubformDataSilently(ByRef subformControl As Access.Subform)
    On Error GoTo ErrorHandler

    Dim rs As DAO.Recordset
    Dim currentBookmark As Variant
    
    ' 1. 現在のフォームの表示位置(ブックマーク)を保存しておく
    ' これを行わないと、処理後にユーザーがどこを見ていたか分からなくなる
    currentBookmark = subformControl.Form.Bookmark

    ' 2. RecordsetCloneを取得(これが「分身」となる)
    ' フォームの表示を動かさずに、裏側でデータを操作するための鍵
    Set rs = subformControl.Form.RecordsetClone

    ' 3. データ操作の開始
    ' 画面更新を止めて、パフォーマンスを向上させる
    DoCmd.Hourglass True ' マウスカーソルを砂時計にする
    
    If Not (rs.EOF And rs.BOF) Then
        rs.MoveFirst ' 分身の先頭から開始
        
        Do While Not rs.EOF
            ' --- ここで実際のデータ操作を行う ---
            ' 例:消費税率を1.1倍にする(フィールド名は実情に合わせて変更してください)
            rs.Edit
            rs!TaxRate = rs!TaxRate * 1.1
            rs.Update
            ' ----------------------------------
            
            rs.MoveNext ' 次のレコードへ
        Loop
    End If

    ' 4. 画面への反映
    ' RecordsetCloneでの変更は実体(テーブル)に反映されているが、
    ' フォームの表示を最新にするために Requery または Refresh を行う
    subformControl.Form.Refresh

    ' 5. ユーザーの視点を元の位置に戻す
    ' 保存しておいたブックマークを使って、見ていたレコードへジャンプさせる
    If Not IsNull(currentBookmark) Then
        subformControl.Form.Bookmark = currentBookmark
    End If

    MsgBox "更新が完了しました。", vbInformation, "完了"

CleanUp:
    DoCmd.Hourglass False
    Set rs = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "エラー"
    Resume CleanUp
End Sub

コードの重要ポイント解説

1. `Bookmark` の保存と復元:
これが「プロの仕事」です。`RecordsetClone` で裏側をいくら操作しても、最後に `Form.Bookmark = currentBookmark` を実行することで、ユーザーは「さっきまで見ていた場所」にパッと戻ることができます。
2. `RecordsetClone` のループ:
`subformControl.Form.Recordset` を直接回すと、ループのたびに画面がスクロールしてしまいますが、`RecordsetClone` なら静寂の中で処理が進みます。
3. `Refresh` と `Requery` の使い分け:

  • `Refresh`: 今見えているレコードの「値」を最新にする(レコードの増減には反応しない)。
  • `Requery`: データを丸ごと読み込み直す(レコードの増減にも対応する)。

今回は値の更新なので、より軽量な `Refresh` を選択しています。

4. 陥りやすい罠:トランザクション処理の重要性

ここまで読んで「完璧だ!」と思ったあなた。一つだけ、伝説のエンジニアとして警告しておかなければならないことがあります。

もし、ループの途中でエラーが起きたらどうなるでしょうか?
「10件中5件目まで更新して、6件目でエラー停止」……。この状態は、データベースにとって「不整合」という名の悪夢です。

実務レベルでは、この処理を Transaction(トランザクション) で囲むべきです。

' 実務におけるトランザクションのイメージ
DBEngine.BeginTrans ' 処理開始!
    ' --- ここでRecordsetCloneのループを行う ---
' もしエラーがなければ
DBEngine.CommitTrans ' 全て確定!
' もしエラーがあれば
DBEngine.Rollback ' 全てなかったことにする(元通り!)

「全部成功するか、さもなくば、最初から何もしていない状態にするか」。この潔さこそが、データの整合性を守る鉄則です。

まとめ:次の一歩へ

いかがでしたか?
`RecordsetClone` を使いこなし、`Bookmark` でユーザーの視点をケアする。これだけで、あなたの作るAccessアプリケーションの格は劇的に上がります。

1. View(フォーム)と Data(レコードセット)を切り離して考える。
2. `RecordsetClone` で「静かな分身」を作る。
3. `Bookmark` でユーザーの視点を守る。

この3点を意識するだけで、あなたはもう「マクロの記録」から完全に脱却しています。

Access VBAは、奥が深く、そして非常に強力な武器です。仕組みを正しく理解すれば、どんな複雑な業務も自動化の波に乗せることができます。

次は、もっと高度な「DAOとADOの使い分け」についても触れていきましょう。あなたのエンジニアとしての旅路を、心から応援しています。

Happy Coding!

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