【テクニカル・上級編】DAO.Recordsetの「Clone」メソッドでフォームと同期したデータ操作を行う – Access VBA解析バイブル

スポンサーリンク

覚醒するDAO:Recordset.Clone が司る「UIとデータの完全同期」

数多のレガシーシステムが、なぜ今なおAccessというプラットフォーム上で生き残り続けているのか。その理由は、この「DAO(Data Access Objects)」という極めて洗練された、メモリ直結型のオブジェクトモデルにある。

特に、`Recordset.Clone` メソッド。これほどまでに誤解され、かつ過小評価されているメソッドも珍しい。多くのエンジニアは、単に「データのコピーを作るもの」としか認識していない。しかし、真のシニアエンジニアにとって、`Clone` とは「フォームの視覚的状態を破壊することなく、背後のデータ空間を自在に操作するための次元の門」に他ならない。

今回は、フォームとデータの同期における極限の最適化、そしてWindows APIを用いたUI制御を組み合わせた、現場で即戦力となるアーキテクチャを解説する。

1. なぜ「Clone」なのか? ――ポインタの共有と独立性の等価交換

Accessフォーム(Bound Form)は、内部的に一つの `Recordset` を保持している。我々が `Me.Recordset` に直接 `FindFirst` をかけるとき、それはユーザーの目の前でカレントレコードが強制的に移動することを意味する。これは、ユーザーのUXを著しく損なう。

一方で、`CurrentDb.OpenRecordset` で新しいレコードセットを開くのは、コストが高すぎる。それは物理的なデータベース接続をもう一つ確立し、メモリ上に新たなバッファを確保することを意味するからだ。

ここで `Recordset.Clone` の出番だ。
`Clone` は、「同一のメモリバッファ(データセット)を参照しつつ、カレントレコードのポインタだけを独立させた複製」を生成する。

  • 低負荷: データの再ロードが発生しない。
  • 同期性: Clone側で行った更新は、即座にオリジナル(フォーム側)に反映される。
  • 安全性: 検索に失敗しても、フォームのカレントレコードは微動だにしない。

2. 実践:UIを凍結し、バックグラウンドで高速検索を行う

以下に示すコードは、単なる検索ではない。Windows API `SendMessage` を使用して描画を抑制し、`RecordsetClone` を用いて「見つかった場合のみ、瞬間的に移動する」という、極めて堅牢な実装例だ。

Option Compare Database
Option Explicit

‘ Windows API: 描画制御によるパフォーマンス最適化
Private Declare PtrSafe Function SendMessage Lib “user32” Alias “SendMessageA” ( _
ByVal hWnd As LongPtr, _
ByVal wMsg As Long, _
ByVal wParam As LongPtr, _
lParam As Any) As LongPtr

Private Const WM_SETREDRAW As Long = &HB

”’

”’ 高速なレコード検索とフォーム同期の実行
”’

”’ 検索対象のプライマリキー Public Sub SilentSearchAndMove(targetID As Long)
Dim rs As DAO.Recordset
Dim strCriteria As String

‘ 1. オブジェクトのライフサイクル管理:フォームのRecordsetCloneを取得
‘ Me.RecordsetClone は、フォームが閉じられるまで生存する特殊なクローンを返す
Set rs = Me.RecordsetClone

strCriteria = “[ID] = ” & targetID

‘ 2. バックグラウンドでの検索実行
‘ この時点では、ユーザーの画面(フォーム)は一切動かない
rs.FindFirst strCriteria

If rs.NoMatch Then
MsgBox “対象のレコードは見つかりませんでした。”, vbInformation, “System”
Else
‘ 3. ヒットした場合のみ、UIの同期を行う
‘ UIの描画を停止させ、ちらつきを防止(シニアのこだわり)
Call SendMessage(Me.hWnd, WM_SETREDRAW, 0, ByVal 0&)

On Error GoTo Error_Handler

‘ Bookmarkの受け渡し:これがDAOにおける「同一レコードへの同期」の正体
‘ rs.Bookmark は内部的なポインタであり、これをフォームのBookmarkに代入することで
‘ フォームのカレントレコードが瞬時に移動する
Me.Bookmark = rs.Bookmark

End If

Clean_Up:
‘ 4. メモリ解放の鉄則
‘ DAOオブジェクトは明示的にNothingを代入し、COMの参照カウントを下げること
‘ これを怠ると、LDBファイルのロック競合やメモリリークの原因となる
If Not rs Is Nothing Then Set rs = Nothing

‘ 描画再開
Call SendMessage(Me.hWnd, WM_SETREDRAW, 1, ByVal 0&)
Me.Repaint
Exit Sub

Error_Handler:
Debug.Print “Error: ” & Err.Number & ” – ” & Err.Description
Resume Clean_Up
End Sub

3. 深淵なる知見:なぜ `Me.RecordsetClone` を使うのか?

上記のコードで `Me.Recordset.Clone` ではなく `Me.RecordsetClone`(プロパティ)を使用している点に注目してほしい。

1. `Me.Recordset.Clone`: 呼び出すたびに新しいクローンオブジェクトをインスタンス化する。明示的な `Close` と `Set Nothing` が必須。
2. `Me.RecordsetClone`: フォームが既に内部で持っているクローンへの参照を返す。非常に高速であり、フォームとライフサイクルを共にするため、管理が容易。

シニアエンジニアは、状況に応じてこれらを使い分ける。動的にSQLを組み立ててフィルタリングを行う場合は `Recordset.Clone` を、単なる検索と同期であれば `RecordsetClone` プロパティを選択するのがベストプラクティスだ。

4. システム間連携と保守の観点

レガシーなAccessシステムをモダンなSQL Server backend(ODBC接続)へ移行した際、この `Clone` メソッドの挙動はさらに重要性を増す。

`Requery` を乱発する設計は、ネットワークトラフィックを増大させ、パフォーマンスを劇的に低下させる。しかし、`Clone` を利用した「メモリ上のポインタ移動」を主軸に置くことで、サーバーへの再問い合わせを最小限に抑えることが可能となる。

また、`Bookmark` は `Recordset` オブジェクトが異なれば(たとえ同じSQLでも)互換性がない。しかし、`Clone` によって生成された個体間では、Bookmarkは完全な互換性を持つ。この特性こそが、複雑なサブフォーム連携や、ポップアップ検索画面からの親画面制御において、バグの混入を防ぐ最強の武器となる。

5. 結論:アーキテクトとしての矜持

VBAは「古い言語」ではない。そのオブジェクトモデルをどれだけ深く理解し、WindowsというOSの仕組み(API)と同期させられるか。それによって、Accessはエンタープライズ級のフロントエンドツールへと昇華する。

`Recordset.Clone` を単なるコピーと見なすか、それとも「UIとデータを切り離すための抽象化レイヤー」と見なすか。その視点の差が、凡庸なプログラマと、システムの命運を託されるチーフアーキテクトの境界線である。

メモリを制し、ポインタを操れ。それが、Access VBAという広大な迷宮を掌握する唯一の道だ。

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