Project VBAを掌握する極限の知見:SQL Serverトランザクションログと同期する堅牢なプロジェクト保存・ロールバック設計
開発現場において、Microsoft Projectのデータ管理ほど頭を悩ませるものはない。
「ローカルの`.mpp`ファイルには保存されたが、進捗管理用のSQL Server側への書き込みでコケた」
「逆にDB側だけ更新され、肝心のファイル保存がディスク容量不足で失敗した」
この「ファイルとRDBの二重管理」が生む不整合は、業務システムの信頼性を根底から破壊する。片方だけが成功した状態(ダーティデータ)を放置すれば、翌日にはプロジェクトマネージャーからの冷徹な追及が待っているだろう。
今回は、Project VBAとSQL Serverのトランザクションログを高度に連携させ、「全か無か(All or Nothing)」を完全に担保する堅牢なロールバック機構の設計思想と実装を伝授する。
—
1. なぜ「普通のVBAコード」では破綻するのか?
多くの初級・中級プログラマが書くコードはこうだ。
‘ 【アンチパターン】絶対に真似してはいけない実装
Sub NaiveSaveProcess()
‘ 1. Projectファイルの保存
ActiveProject.SaveAs “C:\Projects\Target.mpp”
‘ 2. SQL Serverへの書き込み
Dim cn As Object
Set cn = CreateObject(“ADODB.Connection”)
cn.Open “Provider=SQLOLEDB;…”
cn.Execute “UPDATE ProjectStatus SET Progress = 100 WHERE…”
‘ 破綻ポイント:
‘ もし2番目のSQL実行時エラーで落ちたら?
‘ -> ファイルは上書き保存されたのに、DBは古いまま取り残される。
End Sub
このアプローチが非効率かつ危険な理由は明白である。
1. トランザクションの分離: ファイルシステム(OS)とRDB(SQL Server)という、全く異なるコンテキストの書き込みを直列に並べているだけで、不可分(原子性)の保証がない。
2. ロールバックの欠如: 途中で例外が発生した際、既に変更されたファイルを元の状態に戻す(あるいはDB側を差し戻す)ための補償トランザクションが考慮されていない。
真にプロフェッショナルな設計とは、「SQL Server側のトランザクションログ(Transaction Log)を主導権(マスタ)とし、VBA側でファイル操作の成否を監視して全体をロールバック・コミットする仕組み」である。
—
2. 堅牢なロールバック設計のアーキテクチャ
今回構築するシステムでは、以下のライフサイクルでデータの整合性を守る。
1. 事前バックアップ: 操作対象の`.mpp`ファイルを一時領域へ安全に退避(VBA側)。
2. DBトランザクション開始: `BEGIN TRANSACTION`により、SQL Server側で変更の隔離領域を確保。
3. DB更新処理: 進捗やメタデータをSQL Serverへ書き込み(ログに記録)。
4. Projectファイル保存: `ActiveProject.Save`を実行。
5. 判定とコミット/ロールバック:
- 成功時: `COMMIT TRANSACTION`を発行し、一時ファイルを破棄。
- 失敗時(トラップ発動): `ROLLBACK TRANSACTION`でDBを復元し、さらに退避させておいた一時ファイルで元の`.mpp`を上書き復元する。
この「二重の安全弁」があって初めて、エンタープライズ環境に耐えうるツールと言える。
—
3. 【プロダクションコード】完全同期・ロールバック実装
以下のコードは、エラーハンドリングとADOトランザクション、そしてファイルシステムの物理復元を組み合わせた実用コードである。標準モジュールに貼り付けて利用してほしい。
Option Explicit
‘==============================================================================
‘ プロジェクトファイルとSQL Serverトランザクションの同期保存・ロールバック処理
‘==============================================================================
Public Sub SaveProjectWithSQLTransaction()
Dim cn As Object
Dim targetFilePath As String
Dim backupFilePath As String
Dim fso As Object
Dim isTransStarted As Boolean
‘ ターゲットファイルパスの取得
If ActiveProject.Path = “” Then
MsgBox “プロジェクトファイルが一度も保存されていません。先に手動で保存してください。”, vbCritical, “致命的エラー”
Exit Sub
End If
targetFilePath = ActiveProject.FullName
backupFilePath = Environ(“TEMP”) & “\” & ActiveProject.Name & “.bak”
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set cn = CreateObject(“ADODB.Connection”)
On Error GoTo ErrorHandler
‘ —————————————————-
‘ Step 1: 物理ファイルの事前バックアップ(ロールバック用)
‘ —————————————————-
If fso.FileExists(targetFilePath) Then
fso.CopyFile targetFilePath, backupFilePath, True
End If
‘ —————————————————-
‘ Step 2: SQL Server接続とトランザクション開始
‘ —————————————————-
‘ ※実際の環境に合わせて接続文字列を変更してください
cn.Open “Provider=MSOLEDBSQL;Server=myServerAddress;Database=myDatabase;Trusted_Connection=yes;”
cn.BeginTrans
isTransStarted = True
‘ —————————————————-
‘ Step 3: DB側の更新処理(例:プロジェクトメトリクスの記録)
‘ —————————————————-
Dim sql As String
sql = “UPDATE dbo.ProjectMaster SET LastSaved = GETDATE(), Status = ‘Locked’ WHERE ProjectCode = ‘” & ActiveProject.Code & “‘;”
cn.Execute sql
‘ —————————————————-
‘ Step 4: Projectファイルの保存実行
‘ —————————————————-
ActiveProject.Save
‘ —————————————————-
‘ Step 5: コミット(全処理成功)
‘ —————————————————-
cn.CommitTrans
isTransStarted = False
‘ バックアップ一時ファイルの削除
If fso.FileExists(backupFilePath) Then fso.DeleteFile backupFilePath, True
MsgBox “プロジェクトの保存とデータベースの同期が正常に完了しました。”, vbInformation, “成功”
GoTo CleanUp
ErrorHandler:
‘ —————————————————-
‘ 例外発生時のロールバック処理
‘ —————————————————-
Dim errDesc As String
errDesc = Err.Description
‘ DBトランザクションのロールバック
If isTransStarted Then
On Error Resume Next
cn.RollbackTrans
On Error GoTo 0
End If
‘ ファイルのロールバック(バックアップから復元)
If fso.FileExists(backupFilePath) Then
On Error Resume Next
fso.CopyFile backupFilePath, targetFilePath, True
‘ バックアップ削除
fso.DeleteFile backupFilePath, True
On Error GoTo 0
End If
MsgBox “エラーが発生したため、すべての変更をロールバックしました。” & vbCrLf & _
“詳細: ” & errDesc, vbCritical, “トランザクション中断”
CleanUp:
‘ 接続の解放
If Not cn Is Nothing Then
If cn.State = 1 Then cn.Close
Set cn = Nothing
End If
Set fso = Nothing
End Sub
—
4. チーフアーキテクトが教える実装上の極意・注意点
このコードを現場に導入する際、以下のポイントを怠ると予期せぬトラブルシューティングに追われることになる。
① 接続プロバイダの選定
コード内では `MSOLEDBSQL` (Microsoft OLE DB Driver for SQL Server)を指定している。古い `SQLOLEDB` は既に非推奨であり、SQL Serverのモダンなセキュリティ機能(TLS 1.2/1.3等)に対応していないため、必ず最新のプロバイダを使用すること。
② ロック競合の考慮(ISOLATION LEVEL)
SQL Server側で複数ユーザーが同時にプロジェクトデータを参照・更新している場合、トランザクションの競合(デッドロック)が発生する可能性がある。必要に応じて、ADO接続直後に以下のようなクエリを発行し、トランザクション分離レベルを調整する設計も視野に入れること。
cn.Execute “SET TRANSACTION ISOLATION LEVEL READ COMMITTED;”
③ ファイルシステム操作の遅延(I/Oレイテンシ)
ネットワークドライブ上に`.mpp`が存在する場合、`ActiveProject.Save` や `FSO.CopyFile` の完了をOSが検知する前に次の処理へ進み、ファイルハンドルが解放しきれずにエラーになるケースがある。大規模なプロジェクトファイルを扱う場合は、エラーハンドラ内でのわずか数ミリ秒のウェイト(`DoEvents`の活用など)が必要になることもある。
—
総括
VBAは「おもちゃのマクロ言語」ではない。適切なアーキテクチャとRDBのトランザクション理論を融合させれば、基幹システムに匹敵する堅牢なデータ整合性を担保できる。
「ファイルが壊れた」「DBとズレた」という現場の悲鳴を根絶するためにも、単なる`.Save`の呼び出しから脱却し、「トランザクションログ駆動型のセキュアな保存ルーチン」をあなたのプロジェクトに標準装備してほしい。
