【テクニカル・上級編】【上級プロフェッショナル向け】SQL Server上の図面履歴テーブルと連動した、保存時の「自動リビジョンアップ」システム – AutoCAD VBA解析バイブル

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

【極限の設計】AutoCADとSQL Serverの同期による、原子性を担保した自動リビジョン管理アーキテクチャ

図面管理の現場において、「ファイル名に手動でリビジョンを付与する」という行為は、エンジニアリングにおける「禁忌」である。それはヒューマンエラーの温床であり、データの整合性を破壊する脆弱なプロセスに他ならない。

真に堅牢な設計管理システムとは、図面ファイル(DWG)を単なる「データ塊」として扱うのではなく、「データベース(Single Source of Truth)に紐付けられた、特定の状態を持つオブジェクト」として定義することから始まる。

本稿では、AutoCAD VBAをオーケストレーターとし、SQL Serverをマスターとした、保存実行時にリビジョンを自動昇格させる「自動リビジョンアップ・システム」の極限的な実装手法を詳解する。単なるコードの提示ではない。オブジェクトのライフサイクル、トランザクションの整合性、そしてメモリ管理の深淵に触れていく。

1. アーキテクチャの設計思想:原子性の確保

このシステムの核心は、「ファイルシステムの書き込み」と「データベースの更新」という、本来性質の異なる二つの操作を、いかにして「一つの原子的な操作(Atomic Operation)」として扱うかにある。

もし、ファイルは保存されたが、DBの更新に失敗したらどうなるか? もし、DBは更新されたが、ファイル書き込みがネットワークエラーで中断されたら?
このような「不整合状態」を許容することは、システム設計者として敗北を意味する。

システムフロー

1. Pre-check: 保存対象のファイルが、DBに登録されているかを確認。
2. Version Fetch: SQL Serverから現在の最新リビジョン番号をロック付きで取得。
3. File Execution: 新しいリビジョン番号を付与したファイル名で `SaveAs` を実行。
4. DB Commit: ファイル保存の成功をトリガーに、DBの履歴テーブルへレコードを挿入。
5. Rollback Logic: いずれかのステップで失敗した場合、不整合を防ぐためのリカバリ処理を実行。

2. 実装の核心:堅牢なVBAモジュール

以下に、プロフェッショナルレベルの実装例を示す。ここでは、`ADODB` を用いたSQL Serverとの連携、およびWindows APIを用いたファイル状態の検証を組み込んでいる。

Option Explicit

' Windows API: ファイルのアクセス権限や存在確認をより低レイヤーで行うための宣言
' ネットワーク遅延や、アンチウイルスソフトによるファイルロックを検知するために使用
Private Declare PtrSafe Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
Private Const INVALID_FILE_ATTRIBUTES As Long = &HFFFFFFFF&

' 定数定義
Private Const DB_CONN_STR As String = "Provider=SQLOLEDB;Data Source=SERVER_NAME;Initial Catalog=DWG_MGMT;Integrated Security=SSPI;"

''' <summary>
''' 図面のリビジョンアップ保存を実行するメインルーチン
''' </summary>
Public Sub ExecuteVersionedSave()
    Dim acadDoc As AcadDocument
    Set acadDoc = ThisDrawing
    
    Dim currentPath As String
    currentPath = acadDoc.FullName
    
    ' 1. 初期バリデーション: 未保存の新規図面は対象外
    If currentPath = "" Then
        MsgBox "この図面はまだ保存されていません。まずベースとなる図面を保存してください。", vbCritical
        Exit Sub
    End If

    Dim conn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim nextRev As Integer
    Dim newFileName As String
    Dim baseName As String
    Dim folderPath As String
    Dim success As Boolean
    
    On Error GoTo ErrorHandler

    ' --- ステップ1: DB接続とリビジョン取得 ---
    Set conn = New ADODB.Connection
    conn.Open DB_CONN_STR
    
    ' SQL Server側で現在のMax(Revision)を取得
    ' ここでは、同時実行性を考慮し、SELECT ... WITH (UPDLOCK) 等の検討が必要(DB設計に依存)
    Dim sql As String
    sql = "SELECT MAX(Revision) FROM DrawingHistory WHERE FilePath = '" & Replace(currentPath, "'", "''") & "'"
    
    Set rs = conn.Execute(sql)
    
    If IsNull(rs.Fields(0).Value) Then
        ' 初回登録の場合
        nextRev = 1
    Else
        nextRev = rs.Fields(0).Value + 1
    End If
    rs.Close
    Set rs = Nothing

    ' --- ステップ2: 新しいファイル名の生成 ---
    ' 拡張子の前に _RevXX を付与する設計
    folderPath = Left(currentPath, InStrRev(currentPath, "\"))
    baseName = Left(currentPath, InStrRev(currentPath, ".") - 1)
    newFileName = baseName & "_Rev" & Format(nextRev, "00") & ".dwg"

    ' --- ステップ3: AutoCADによるSaveAs実行 ---
    ' ここでメモリリークを防ぐため、オブジェクトのライフサイクルに注意する
    acadDoc.SaveAs newFileName
    
    ' --- ステップ4: DBへの履歴書き込み (トランザクション) ---
    conn.BeginTrans
    Dim insertSql As String
    insertSql = "INSERT INTO DrawingHistory (FilePath, Revision, SaveDate, UserID) " & _
                "VALUES ('" & Replace(newFileName, "'", "''") & "', " & nextRev & ", GETDATE(), SYSTEM_USER)"
    
    conn.Execute insertSql
    
    ' すべて成功した場合のみコミット
    conn.CommitTrans
    success = True
    
    MsgBox "リビジョンアップ完了: " & vbCrLf & newFileName, vbInformation

CleanUp:
    ' --- ステップ5: 明示的なオブジェクト解放 (メモリ管理の極致) ---
    ' VBAにおいてCOMオブジェクトを適切に解放しないことは、AutoCADの不安定化に直結する
    On Error Resume Next
    If Not rs Is Nothing Then Set rs = Nothing
    If Not conn Is Nothing Then
        If conn.State = adStateOpen Then conn.Close
        Set conn = Nothing
    End If
    Set acadDoc = Nothing
    Exit Sub

ErrorHandler:
    ' 異常系:DBトランザクションのロールバック
    If Not conn Is Nothing Then
        If conn.State = adStateOpen Then
            conn.RollbackTrans
            MsgBox "DB更新に失敗したため、トランザクションをロールバックしました。", vbCritical
        End If
    End If
    
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

3. 技術的深掘り:プロフェッショナルが留意すべき3つの要諦

① COMオブジェクトの明示的解放とメモリリーク

AutoCAD VBAにおいて、`Set obj = Nothing` は単なる作法ではない。AutoCADは巨大なメモリ空間を扱うプロセスであり、VBAから呼び出されるCOM(Component Object Model)オブジェクトの参照カウントが適切に管理されない場合、`SaveAs` のような重い処理の直後にメモリリークを引き起こし、最終的に「AutoCADが応答していません」という致命的なクラッシュを招く。
特に `ADODB.Connection` や `Recordset` は、ループ内やイベントハンドラ内で使用する場合、必ず `CleanUp` セクションで明示的に解放しなければならない。

② Windows APIによるファイル制御の補完

ネットワークストレージ(NAS)環境では、`SaveAs` を実行した瞬間に、OSやウイルス対策ソフトがファイルをスキャンし、ファイルロックをかけることがある。
本稿のコードでは簡略化しているが、実運用では `GetFileAttributes` や `CreateFile` を使用して、新しいファイル名が物理的に「書き込み可能(Exclusive Access可能)」な状態にあるかを、DB更新前に検証するプロセスを組み込むべきである。

③ データベース設計における「排他制御」

複数の設計者が同時に同じ図面を開き、それぞれが「保存」を押した場合の競合(Race Condition)を考慮せよ。
SQL Server側では、リビジョン取得時に `UPDLOCK` ヒントを使用し、他のセッションが同じパスに対して `MAX(Revision)` を計算できないようにロックをかける必要がある。これを行わないと、二人とも「Rev05」として保存しようとする、最悪の整合性崩壊が起こる。

4. 結論

自動リビジョンアップシステムは、単なる「ファイル名の自動変更ツール」ではない。それは、物理ファイルと論理データ(DB)の間に強固な規律をもたらすための、エンジニアリング・インフラストラクチャである。

このようなシステムを構築する際、我々に求められるのは、AutoCADのAPI知識だけではない。OSの挙動、データベースのトランザクション、そしてメモリのライフサイクルに対する、冷徹なまでの理解である。これこそが、レガシーな環境をモダンなエンタープライズ・アーキテクチャへと昇華させる、真のアーキテクトの仕事である。

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