【テクニカル・上級編】【上級】DAO.Recordsetの「Clone」と「Bookmark」で実現する、非連結フォームでの高速検索UI – Access VBA解析バイブル

スポンサーリンク

連結フォームの呪縛を解け:DAO.RecordsetのCloneとBookmarkで構築する「極限の非連結検索」

Access開発において、多くのエンジニアが「連結フォーム」という名の麻薬に溺れている。手軽にCRUDを実現できるその設計は、レコード数が増加した瞬間にメモリ消費とロック競合という名の毒へと変貌する。

大規模な業務システムで、数万件のレコードを軽快に操作させたいのであれば、「連結フォームからの脱却」こそが唯一の解だ。今日は、DAOの`Clone`と`Bookmark`を駆使し、メモリを極限まで効率化しながら爆速の検索UIを構築する技術論を授ける。

1. なぜ連結フォームでは限界が来るのか

連結フォームは、Access内部の`BoundObjectFrame`が裏でレコードセットを常に監視し、同期を試みている。この「同期処理」こそが、ネットワーク負荷とクライアントPCのCPUを喰い潰す元凶だ。

真のシニアエンジニアは、「表示のみを担当するUI」と「データソース」を完全に分離する。検索結果を非連結のリストボックスやサブフォームに流し込み、レコードの移動はブックマークで行う。この設計が、複雑なシステムを安定させる唯一の道である。

2. アーキテクチャの核心:DAO.RecordsetのCloneとBookmark

非連結フォームにおける検索の極意は、データベースから一度だけデータを抽出し、そのポインタ(Recordset)を保持することにある。

`Recordset.Clone`は、レコードセットの複製を作成するが、データそのものは複製しない。あくまでカレントレコードの位置を示す「カーソル」を共有するだけの軽量なオブジェクトだ。これを利用し、UI上のリスト選択と内部レコードセットを同期させる。

実装例:爆速検索コントローラー

以下は、非連結フォームにおいて、検索結果をリストボックスに表示し、選択時にDAOで高速にレコードを特定するコード例だ。

‘ フォームモジュール内で保持するレコードセット
Private m_rs As DAO.Recordset

‘ 検索ボタン押下時の処理
Public Sub ExecuteSearch(strCriteria As String)
‘ 既存のレコードセットを明示的に解放
If Not m_rs Is Nothing Then
m_rs.Close
Set m_rs = Nothing
End If

‘ 非連結のため、スナップショットで高速に読み込む
‘ ロックを避けるためdbOpenSnapshotを指定
Set m_rs = CurrentDb.OpenRecordset(“SELECT FROM T_Master WHERE ” & strCriteria, dbOpenSnapshot)

‘ リストボックスへ値を供給(RowSourceType = “Value List” 運用も可だが、ここでは単純化)
‘ ※実務ではGetRowsを用いて配列で流し込むのが最速
Me.lstResult.RowSource = “” ‘ 実際はここでRecordsetの値をバインドする処理を記述
End Sub

‘ リストボックスのクリック時処理
Private Sub lstResult_Click()
If m_rs Is Nothing Then Exit Sub

‘ Bookmarkを利用してレコードセットのポインタを同期
‘ 連結フォームを使わずとも、データセットは手元にある
m_rs.Bookmark = Me.lstResult.Value

‘ これにより、m_rs.Fields(“FieldName”) で即座に値が取れる
Debug.Print m_rs!CustomerName
End Sub

‘ フォーム終了時の厳格な解放処理
Private Sub Form_Close()
If Not m_rs Is Nothing Then
m_rs.Close
Set m_rs = Nothing
End If
End Sub

3. レガシー環境でのメモリ管理の極致

Access VBAにおいて、`Set rs = Nothing` を怠ることは死を意味する。特にマルチユーザー環境のAccessにおいて、クローズし損ねた`Recordset`は、バックエンドのロックを解放せず、他のユーザーの業務を止める。

  • APIによる監視: 業務が極めてクリティカルな場合、`kernel32.dll`を用いてプロセスのメモリ使用量を監視し、一定値を超えた場合にキャッシュをクリアするコードを実装することもある。
  • 明示的解放の徹底: `Err`ハンドラ内で必ず`Close`と`Nothing`を呼び出す「確実なクリーンアップ」をコードテンプレートとして定着させよ。

4. 伝説のエンジニアへのアドバイス

非連結フォームを採用するということは、Accessが用意した「便利な機能」をすべて自前で実装する覚悟を持つということだ。

  • ページング処理: `Recordset.AbsolutePosition`を使い、数万件のデータを一度にリストボックスに流さず、100件単位で切り出すUIを作れ。
  • 非同期通信: 必要であれば、`WinHTTP`オブジェクトを使って外部APIとJSONでやり取りし、その結果をレコードセットにマッピングする手法も検討せよ。

Accessというツールは、使い手によって「足枷」にも「凶器」にもなる。連結フォームという安易な選択肢を捨て、メモリとポインタを制御下に置いたとき、初めて君はAccessの本当の力を引き出せるはずだ。

コードは嘘をつかない。君が書いた解放処理の数だけ、システムは長生きする。健闘を祈る。

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