【入門編】DAO.RecordsetのCloneとBookmarkで実現する、非連結フォームでの高速検索UI – Access VBA解析バイブル

スポンサーリンク

こんにちは! Access VBAの開発現場で、日夜データベースと格闘お疲れ様です。

マクロの記録から一歩抜け出し、「自分の手で自由自在にフォームをコントロールしたい!」という熱意を持つあなたへ。今日は、Access開発において避けて通れない、しかしここさえ押さえれば一気にプロの仲間入りができる「極限の検索UIテクニック」を伝授します。

「フォームで検索をかけるたびに、画面がチラついたり、レコードの移動が重くなったりする……」
そんなストレスを感じたことはありませんか?

今回は、DAOの `Clone` と `Bookmark` という、Access VBAが持つ隠し味のような強力な機能を使い、「画面の表示速度を落とさずに、裏側で爆速検索を行う非連結/連結ハイブリッドUI」の設計パターンを解説します。

ここをクリアすれば、あなたの作るAccessアプリは見違えるほど軽快になりますよ。さあ、一緒に本質をマスターしていきましょう!

1. なぜ「そのままの検索」では遅いのか?

Accessフォームでよくあるアンチパターンがこれです。

  • テキストボックスに入力するたび(`Change` イベントなど)に、フォームの `RecordSource`(レコードソース)のSQL文を書き換える。
  • `Me.Requery` を連発する。

これをやると、何が起きるでしょうか?
Accessはテキストが1文字変わるたびに、ディスク(またはネットワーク上のバックエンド)へアクセスし、クエリを再実行し、画面の描画を最初からやり直します。結果、画面はカクつき、入力はもたつき、ユーザーはイライラ……。

解決の鍵:DAOの「Clone(クローン)」と「Bookmark(ブックマーク)」

ここで登場するのが、DAO(Data Access Objects)のレコードセットクローンです。

イメージしてください。

  • メインフォームは、ユーザーに見せるための「ショーウィンドウ」。
  • レコードセットのクローンは、裏のバックヤードで高速に棚卸しをする「台帳のコピー」。

バックヤードの台帳(Clone)側で素早く目的のデータを探し出し、見つかった瞬間に「あ、お客さん、お探しの商品はこれですよ!」と、ショーウィンドウ(フォーム)の `Bookmark`(しおり)をパッとその場所にワープさせる。

この仕組みを使えば、画面の無駄な再描画や重いクエリの再実行を最小限に抑え、驚くほど滑らかで高速な検索UIが実現できるのです。

2. 全体像とアーキテクチャ

今回の設計パターンでは、以下のステップで処理を行います。

1. フォームが読み込まれたとき、フォームのレコードセットの「クローン」をメモリ上に確保する。
2. ユーザーが検索ボックスにキーワードを入力する。
3. 裏側のクローン(`Recordset`)に対して `FindFirst` メソッドで高速検索を行う。
4. ヒットしたら、フォームの `Bookmark` プロパティにクローンの `Bookmark` を代入する。
5. フォームが一瞬でそのレコードへジャンプする。

図解するならこうです。

[ ユーザーの入力 ]

[ フォーム (画面) ] –( Bookmarkの同期 )–> [ DAO Recordset Clone (メモリ上の裏台帳) ]

( FindFirstで爆速検索 )

3. 実装コード:これコピペで動く実戦的VBA

それでは、実際のフォームモジュールに記述するコードを見ていきましょう。
今回は、顧客テーブル(`T_顧客`)から、顧客名(`CustomerName`)をリアルタイムで部分一致検索するシーンを想定します。

Option Compare Database
Option Explicit

‘ メモリ上に保持するレコードセットのクローン変数
Private rsClone As DAO.Recordset

Private Sub Form_Load()
‘ 【1. フォームの初期化】
‘ フォームが持つレコードセットのクローンをメモリ上に作成します。
‘ これにより、画面描画と独立して高速なデータ操作が可能になります。
On Error GoTo ErrorHandler

Set rsClone = Me.Recordset.Clone
Exit Sub

ErrorHandler:
MsgBox “初期化エラーが発生しました: ” & Err.Description, vbCritical
End Sub

Private Sub Form_Unload(Cancel As Integer)
‘ 【2. 終了時のクリーンアップ】
‘ オブジェクト変数はメモリリークを防ぐために必ず解放する。これがプロの流儀です。
If Not rsClone Is Nothing Then
rsClone.Close
Set rsClone = Nothing
End If
End Sub

Private Sub txtSearchBox_Change()
‘ 【3. リアルタイム検索の核心】
‘ 検索テキストボックスの値が変わるたびに呼び出されます(Changeイベント)。
Dim keyword As String

‘ コントロールのTextプロパティから現在の入力文字を取得
keyword = Me.txtSearchBox.Text

‘ 未入力の場合は検索を行わない
If Len(keyword) = 0 Then Exit Sub

On Error GoTo SearchError

‘ DAOのFindFirstメソッドを使用し、部分一致(keyword)で検索
‘ ※注意:AccessのDAOにおける文字列検索はワイルドカードに “” を使います
rsClone.FindFirst “CustomerName LIKE ‘” & Replace(keyword, “‘”, “””) & “‘”

‘ 該当データが見つかった場合
If Not rsClone.NoMatch Then
‘ フォームのBookmarkをクローンのBookmarkに同期させることで、
‘ 画面を再読み込みすることなく、一瞬で該当レコードにジャンプする!
Me.Bookmark = rsClone.Bookmark
End If

Exit Sub

SearchError:
‘ 検索中の予期せぬエラー(特殊文字の入力など)をハンドリング
‘ ここであまりメッセージを出しすぎると入力の邪魔になるのでログに留めるかスルーします
End Sub

4. コードの解説と「初心者がハマりやすい罠」

このコードには、実務で絶対に知っておくべき重要なポイントが詰まっています。

① `.Text` プロパティと `.Value` プロパティの罠

`txtSearchBox.Text` と書いているところに注目してください。
ここをうっかり `Me.txtSearchBox`(省略形=`.Value`)にしてしまうと、「1文字入力するごとにフォーカスを失うと値が確定する」という仕様のせいで、リアルタイム検索になりません。
キーボードでタイピング中の生の文字列をリアルタイムで拾うには、必ず `.Text` プロパティを使用してください。(※ただし、`.Text` を使うときはコントロールにフォーカスがあることが前提となります)

② SQLインジェクションならぬ「シングルクォーテーション対策」

検索キーワードの中に `O’Brien` のようなシングルクォーテーションが含まれていると、VBAのSQL文が構文エラーを起こして爆発します。
そのため、コード内では `Replace(keyword, “‘”, “””)` というおまじないを使い、シングルクォーテーションをエスケープしています。こういう細かな配慮が、現場で「壊れないアプリ」を作ります。

③ メモリのライフサイクル管理(極めて重要)

`Form_Load` で作成した `rsClone` は、フォームが開いている間ずっとメモリ上に常駐します。そして `Form_Unload` で確実に `.Close` し、`Set rsClone = Nothing` で解放しています。
この後始末を怠ると、Accessのメモリリークを引き起こし、アプリ全体の動作が重くなったり、最悪の場合はファイルが破損する原因になります。

5. さらにワンランク上のエンジニアを目指すあなたへ

今回の `Clone` と `Bookmark` を使った手法は、Access VBAのパフォーマンスチューニングの基本にして奥義です。

「ただ動くだけのコード」から、「大規模なデータでもサクサク動く、洗練されたアーキテクチャ」へ。このパターンの引き出しを持っているだけで、周囲からの見る目がガラリと変わるはずです。

ここをクリアしたあなたなら、もうマクロの記録の呪縛からは完全に解放されています。ぜひ、実際の業務フォームにこのテクニックを組み込んで、その「爆速の快感」を体感してみてください。

それでは、次のステージでお会いしましょう!

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