Project VBAを掌握する:SQL Server連携における「非同期」の幻想と「同期」の真髄
Project VBAを扱うことは、単なるマクロ記述ではない。それは、プロジェクトの「時間」という四次元のデータを、リレーショナル・データベースという静的な二次元構造にマッピングする重責を担うことだ。
多くのジュニアエンジニアがADO(ActiveX Data Objects)を用いてSQL Serverと対峙する際、接続文字列を貼り付けてレコードセットを回すだけのコードで満足する。だが、我々のようなアーキテクトにとって、それは「メモリリークへの招待状」に等しい。
今日は、Project VBAとSQL Serverを接続する際の「極限の知見」を共有する。
—
1. 接続の作法:コネクションプーリングを殺さないために
ADO接続において最大の罪は、コネクションの乱立だ。SQL Serverへの接続は高コストであり、`ADODB.Connection`オブジェクトを乱用すれば、接続プールは枯渇し、最終的にサーバー側で接続拒否が起きる。
接続のベストプラクティス
`Connection`オブジェクトは、モジュールレベルで保持し、アプリケーション終了まで使い回すのが鉄則だ。
‘ 接続文字列を定数化し、再利用性を確保する
Private Const CONN_STR As String = “Provider=SQLOLEDB;Data Source=SERVER_NAME;Initial Catalog=DB_NAME;Integrated Security=SSPI;”
Private m_cn As ADODB.Connection
Public Function GetConnection() As ADODB.Connection
If m_cn Is Nothing Then
Set m_cn = New ADODB.Connection
m_cn.ConnectionString = CONN_STR
m_cn.Open
ElseIf m_cn.State = adStateClosed Then
m_cn.Open
End If
Set GetConnection = m_cn
End Function
—
2. データ型マッピングの深淵:Projectの「独自仕様」を殺す
Projectのタスク(`Task`オブジェクト)をSQL Serverに投入する際、最も注意すべきは「Duration(期間)」と「Work(作業時間)」の単位の歪みだ。
- Duration: Project内部では「分」単位の`Long`だが、表示上は「日」や「時間」に変換される。
- Work: プロジェクト設定に依存する「分」単位の数値。
SQL Server側ではこれらを`FLOAT`または`BIGINT`で保持すべきだ。決して`NVARCHAR`で逃げてはならない。後続の集計クエリやBIツールでの可視化において、型変換(`CAST`)を強いるクエリはシステム全体のパフォーマンスを殺す。
—
3. メモリ解放の神学:伝説のアーキテクトは「Nothing」を信じない
VBAのガーベジコレクションは信用するな。特に`Recordset`や`Connection`のようなCOMオブジェクトは、明示的な解放が義務付けられている。
Public Sub SyncTaskToDB(ByVal t As Task)
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = GetConnection()
.CommandText = “INSERT INTO Tasks (TaskUID, TaskName, Duration) VALUES (?, ?, ?)”
.Parameters.Append .CreateParameter(“@UID”, adGUID, adParamInput, , t.Guid)
.Parameters.Append .CreateParameter(“@Name”, adVarWChar, adParamInput, 255, t.Name)
.Parameters.Append .CreateParameter(“@Dur”, adDouble, adParamInput, , t.Duration / 60) ‘ 分を時間に変換
.Execute
End With
‘ ここからがプロの領域。オブジェクトの明示的破棄と参照のクリア
Set cmd = Nothing
‘ ※m_cnはモジュール終了時まで保持
End Sub
極限の知見: `Set obj = Nothing` を呼んだだけでは、循環参照やCOMインターフェースの解放が即時に行われない場合がある。システムが長期間起動し続けるような監視ツールを組む場合は、`Sleep`を挟む、あるいは`Win32 API`の`CoFreeUnusedLibraries`を呼び出すといった「泥臭い防衛策」が必要になる場面もあることを忘れるな。
—
4. レガシー環境における「同期の罠」
Projectのタスク数が増大(数千件超)した場合、単一スレッドでの同期はUIのフリーズを招く。しかし、VBAはシングルスレッドだ。
ここで取るべき戦略は「バッチ処理への転換」である。
1. タスクを`Collection`や`Scripting.Dictionary`にキャッシュする。
2. `Transaction`を使用し、一括でコミットする。
3. `Errors`コレクションを監視し、トランザクションのロールバックを制御する。
m_cn.BeginTrans
‘ ループ内でExecuteを実行
m_cn.CommitTrans
もしエラーが発生した場合は、`m_cn.RollbackTrans`を呼び出す。これを怠れば、部分的なデータのみがDBに残り、Projectファイルとの不整合という「システムの死」を招くことになる。
—
結びに:技術は「信頼」の上に成り立つ
システム間連携において、最も壊れやすいのはコードではなく「データ」だ。
Projectのタスクは常に変化する。その変化をSQL Serverという岩盤に刻み込む際、我々エンジニアがやるべきことは、単にデータを移動させることではない。
「予期せぬ中断が起きても、データの整合性が保たれる仕組み」を設計することだ。
VBAは古い。しかし、その老兵は今もなお、巨大なプロジェクトの心臓部を動かし続けている。諸君もまた、単なるコード書きではなく、データの番人たれ。
健闘を祈る。
