【入門編】ADOのDisconnected Recordsetを活用した、ネットワーク負荷を最小化する「オフライン編集」アーキテクチャ – Access VBA解析バイブル

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

ネットワークの壁を越える:ADO Disconnected Recordsetによる「オフライン編集」の極意

こんにちは。Access VBAの深淵へようこそ。

「マクロの記録」でボタン一つ動かせるようになった。次は「コードを書いて、少し複雑な処理ができるようになった」。そんなステップを歩んでいるあなたなら、そろそろこんな壁にぶつかっているはずです。

「ネットワーク越しにデータを扱うと、動作が重い……」
「通信が不安定なとき、Accessがフリーズしたりエラーで落ちたりする……」

これは、あなたが「データの持ち方」と「通信のタイミング」という、エンジニアとして最も重要なアーキテクチャ(設計思想)の入り口に立った証拠です。

今日は、多くの開発者が陥る「常にサーバーと繋ぎっぱなしにする」という非効率なスタイルから脱却し、メモリ上でスマートにデータを操る「Disconnected Recordset(切断型レコードセット)」という魔法を伝授しましょう。ここをマスターすれば、あなたの作るシステムは劇的にプロフェッショナルなものに変わります。

1. なぜ「繋ぎっぱなし」ではいけないのか?

まず、私たちが普段やりがちな「標準的な接続」をイメージしてみましょう。

通常の接続(Connected模式)のイメージ

1. サーバーに「接続」の電話をかける。
2. 「データをください」と頼む。
3. 電話を切らずに、 データを一行ずつ眺めながら書き換える。
4. 終わったら「切ります」と言って電話を切る。

この「電話を切らずに待ち続ける時間」こそが、ネットワーク負荷の正体です。データ量が増え、ユーザーが増えると、サーバーは「電話を繋ぎっぱなしにしている人」で溢れかえり、通信の遅延(レイテンシ)や、最悪の場合は接続切れによる強制終了を引き起こします。

Disconnected Recordset(切断型)のイメージ

1. サーバーに「接続」の電話をかける。
2. 「データをまとめて送ってください」と頼む。
3. データを受け取ったら、即座に電話を切る。
4. 手元のメモ(メモリ上)で、じっくりとデータを書き換える。
5. 編集が終わったら、再び一瞬だけ電話をかけ、「書き換えた分だけまとめて送ります」と報告する。

いかがでしょうか? この「一度切断する」というステップこそが、ネットワークの負荷を最小限に抑える鍵なのです。

2. DAOとADO:道具の使い分けを知る

Access VBAには、データを扱うための「道具」が主に2つあります。

特徴 DAO (Data Access Objects) ADO (ActiveX Data Objects)
得意分野 Access内のテーブル操作 SQL Serverなどの外部DBとの連携
接続スタイル 基本的に「繋ぎっぱなし」 「切断(Disconnected)」が可能
パフォーマンス ローカル操作なら最速 ネットワーク越しに強い

今回私たちが使うのは ADO です。ADOには「クライアントサイド・カーソル」という仕組みがあり、これを使うことでデータを自分のPCのメモリ内に「コピー」して持ち歩くことができるのです。

3. 実践:Disconnected Recordsetの実装

それでは、実際に「データをメモリに読み込み、オフラインで編集して、最後に一括反映する」コードを見ていきましょう。

このコードの最大のポイントは、`CursorLocation = adUseClient` という一行です。これが「データを手元に持ってくる」という魔法の呪文になります。

Option Compare Database
Option Explicit

' 参照設定: "Microsoft ActiveX Data Objects x.x Library" を有効にしてください
' (プロジェクト > 参照設定 からチェックを入れる)

Sub DisconnectedEditExample()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim strConn As String
    Dim strSQL As String
    
    ' 1. 接続文字列の設定 (ここではAccessファイルを例にしますが、SQL Server等でも同様)
    ' ※本来は外部データベースへの接続文字列をここに記述します
    strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & CurrentProject.FullName & ";"
    
    ' 2. SQL文の準備
    strSQL = "SELECT ID, UserName, UserEmail FROM T_Users WHERE Status = 'Active'"
    
    On Error GoTo ErrorHandler

    ' --- 【フェーズ1:データの取得と切断】 ---
    Set cn = New ADODB.Connection
    cn.Open strConn
    
    Set rs = New ADODB.Recordset
    
    ' ★重要★ クライアントサイドカーソルを指定することで、メモリ上にデータを展開可能にする
    rs.CursorLocation = adUseClient
    
    ' データを取得
    rs.Open strSQL, cn, adOpenStatic, adLockOptimistic
    
    ' ★重要★ データを取得し終えたら、すぐにサーバーとの接続を切る!
    cn.Close
    Set cn = Nothing
    Debug.Print "サーバーとの接続を終了しました。現在はメモリ上で作業中です。"

    ' --- 【フェーズ2:メモリ上での編集(オフライン編集)】 ---
    ' ここでは、ネットワークが切れていても、サーバーが重くても、
    ' ユーザーはサクサクと編集作業を続けられます。
    
    If Not rs.EOF Then
        ' 例として、最初のレコードの名前を変更してみる
        rs.Fields("UserName").Value = "Updated Name"
        rs.Fields("UserEmail").Value = "updated@example.com"
        
        ' 変更をレコードセット内に確定させる
        rs.Update
        Debug.Print "メモリ上での編集が完了しました。"
    End If

    ' --- 【フェーズ3:一括同期(再接続と反映)】 ---
    ' 編集が終わったら、再び接続して「差分」だけをサーバーに送ります
    
    Set cn = New ADODB.Connection
    cn.Open strConn
    
    ' 再び接続したConnectionを紐付け直す
    ' これにより、rsが持つ変更内容をサーバーへ流し込める状態になる
    rs.ActiveConnection = cn
    
    ' 変更内容をサーバーへ一括反映
    rs.UpdateBatch ' もしくは rs.Update (設定により異なります)
    
    Debug.Print "サーバーへの同期が完了しました!"

CleanUp:
    ' 後片付け
    If Not rs Is Nothing Then
        If rs.State = adStateOpen Then rs.Close
        Set rs = Nothing
    End If
    If Not cn Is Nothing Then
        If cn.State = adStateOpen Then cn.Close
        Set cn = Nothing
    End If
    Exit Sub

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

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

1. `rs.CursorLocation = adUseClient`
これを忘れると、データはサーバー上に置かれたままになります。つまり「繋ぎっぱなし」のままです。必ず `Open` する前に記述してください。
2. `cn.Close` のタイミング
`rs.Open` の直後に `cn.Close` をしています。これが「切断」の瞬間です。これにより、ネットワークの瞬断に怯えることなく、ユーザーはメモリ上のデータを自由に扱えます。
3. `rs.ActiveConnection = cn`
同期の際、一度切れた `rs`(レコードセット)に、新しく作り直した `cn`(接続)を「君の新しい連絡先はここだよ」と教えてあげる作業です。これによって、メモリ上の変更がサーバーへ届けられます。

4. 陥りやすいエラーとプロの回避術

この高度な手法を使う際、初心者が必ずと言っていいほど踏む地雷があります。

地雷①:`CursorLocation` の設定忘れ

`adUseClient` を指定せずに `cn.Close` を行うと、「操作中のレコードセットが閉じられています」といったエラー、あるいは「サーバーへの接続が必要です」というエラーで即死します。

地雷②:トランザクションの欠如

「一括同期」の際、10件中5件だけ成功して残りの5件が失敗したらどうなるでしょうか? データが中途半端に壊れてしまいます。
実務では、同期処理の前後を `cn.BeginTrans` と `cn.CommitTrans` で囲み、「全部成功するか、全部失敗するか」を保証する設計にしてください。

地雷③:メモリ不足

Disconnected Recordsetは「データをメモリにコピーする」手法です。数百万件のデータを一度に読み込もうとすると、ユーザーのPCのメモリを食いつぶし、Accessがクラッシュします。
「必要な分だけ(WHERE句で絞り込んで)持ってくる」。これは鉄則です。

最後に:エンジニアへの道

いかがでしたか?
「ただデータを読み書きする」だけなら、マクロの記録でも十分かもしれません。しかし、「ネットワークの負荷を考え、オブジェクトのライフサイクルを制御し、ユーザーにストレスを与えない設計をする」こと。これこそが、エンジニアリングです。

最初は難しく感じるかもしれません。でも、この「切断型」の考え方が身につけば、あなたの作るアプリケーションの格は、一気にプロの領域へと昇華します。

一歩ずつ、確実に。また次のステップでお会いしましょう!

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