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

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

データベースが設計する「真の世代管理」:AutoCAD VBAによるSQL Server連携型リビジョン制御の実装

図面管理を「ファイル名に手動で枝番をつける作業」だと思っているなら、今すぐその思考を捨ててほしい。それはエンジニアリングではなく、単なる「作業」だ。

設計変更のたびに、誰かがファイル名に `_Rev01`、`_Rev02` と打ち込む。その過程で必ず発生するのが、枝番の重複、更新漏れ、そして「どれが最新の正本か分からない」という混沌である。

プロフェッショナルが構築すべきは、「図面ファイル」と「データベース(SQL Server)」をアトミック(不可分)に同期させる、自律型世代管理システムだ。

本記事では、AutoCAD VBAを起点とし、SQL Server上の履歴テーブルと連動して、保存時に自動でリビジョンをインクリメントし、ファイル名へ反映させる堅牢なソリューションの設計思想と実装を伝授する。

1. 設計思想:Single Source of Truth (信頼できる唯一の情報源)

多くの開発者が陥る罠は、「ファイル名がリビジョンを規定している」という設計だ。これでは、ファイルがコピーされた瞬間に管理系が崩壊する。

真に堅牢なシステムでは、「SQL Serverがリビジョンを決定し、ファイルはその指示に従って名前を変える」という一方向の依存関係を構築する。

アーキテクチャの要件

1. DB主導の決定: 保存実行時、VBAはまずDBへ「この図面の現在の最新リビジョンは何番か?」を問い合わせる。
2. アトミックな更新: 「新しいファイル名の生成」→「図面の保存(SaveAs)」→「DBのリビジョン更新」というプロセスを一つのトランザクションとして扱う。
3. エラーハンドリングの徹底: ファイルの保存に失敗した(ディスクフルや権限エラー)場合、DBのリビジョンだけが進んでしまうという「データの不整合」を絶対に許さない。

2. データベース設計(SQL Server)

まずは、管理の基盤となるテーブルを定義する。単なるファイル名リストではなく、メタデータ(作成者、更新日時、リビジョン番号)を保持できる構造にする。

CREATE TABLE DrawingHistory (
    DrawingID INT IDENTITY(1,1) PRIMARY KEY,
    BaseFileName NVARCHAR(255) NOT NULL, -- 枝番を除いた元のファイル名
    CurrentRevision INT NOT NULL DEFAULT 0,
    LastUpdatedBy NVARCHAR(100),
    LastUpdatedAt DATETIME DEFAULT GETDATE(),
    FilePath NVARCHAR(500) NOT NULL,
    CONSTRAINT UQ_BaseFileName UNIQUE (BaseFileName)
);

3. プロダクション級の実装コード

ここからは、AutoCAD VBAからの実装だ。ここでは、ADODB(ActiveX Data Objects)を使用してSQL Serverと通信する。

注意: 参照設定で `Microsoft ActiveX Data Objects x.x Library` にチェックを入れていることを前提とする。

モジュール構成:`modRevisionManager`

Option Explicit

' --- 定数定義 ---
Private Const DB_CONN_STR As String = "Provider=SQLOLEDB;Data Source=YOUR_SERVER;Initial Catalog=YOUR_DB;User ID=YOUR_USER;Password=YOUR_PASSWORD;"

''' <summary>
''' 保存プロセスを実行するメインルーチン
''' </summary>
Public Sub ExecuteAutoRevisionSave()
    Dim acadDoc As AcadDocument
    Set acadDoc = ThisDrawing
    
    Dim baseName As String
    Dim currentPath As String
    Dim newFileName As String
    Dim newRev As Integer
    Dim connection As ADODB.Connection
    
    On Error GoTo ErrorHandler

    ' 1. 基本情報の取得
    ' 現在のフルパスから、枝番を除いた「ベース名」を抽出するロジックが必要
    ' ここでは簡易的に、現在のファイル名が「Drawing_Rev01.dwg」なら「Drawing」をベースとする
    baseName = GetBaseFileName(acadDoc.Name)
    currentPath = acadDoc.Path
    If currentPath = "" Then
        MsgBox "図面が一度も保存されていません。まず手動で保存してください。", vbCritical
        Exit Sub
    End If

    ' 2. DB接続
    Set connection = New ADODB.Connection
    connection.Open DB_CONN_STR

    ' 3. DBから現在のリビジョンを取得し、次のリビジョンを決定
    ' ここで「SELECT ... FOR UPDATE」的な排他制御を検討すべきだが、VBA単体では
    ' 取得と更新の間に隙間ができるため、トランザクションを利用する
    connection.BeginTrans
    
    newRev = GetNextRevisionFromDB(connection, baseName)
    
    ' 4. 新しいファイル名の構築 (例: Drawing_Rev02.dwg)
    newFileName = currentPath & "\" & baseName & "_Rev" & Format(newRev, "00") & ".dwg"

    ' 5. AutoCAD図面の保存実行 (SaveAs)
    ' ※重要: ファイル保存が成功しない限り、DBの更新へ進まない
    acadDoc.SaveAs newFileName
    
    ' 6. DBのリビジョンとメタデータの更新
    UpdateDBRevision connection, baseName, newRev, acadDoc.Name
    
    ' 7. トランザクション完了
    connection.CommitTrans
    
    MsgBox "リビジョンアップ完了: " & vbCrLf & newFileName, vbInformation, "Success"

CleanUp:
    If Not connection Is Nothing Then
        If connection.State = adStateOpen Then connection.Close
    End If
    Set connection = Nothing
    Exit Sub

ErrorHandler:
    If Not connection Is Nothing Then connection.RollbackTrans
    MsgBox "致命的なエラーが発生しました。リビジョンは更新されていません。" & vbCrLf & _
           "Error: " & Err.Description, vbCritical, "System Error"
    Resume CleanUp
End Sub

''' <summary>
''' DBから次のリビジョン番号を取得する
''' </summary>
Private Function GetNextRevisionFromDB(conn As ADODB.Connection, baseName As String) As Integer
    Dim rs As ADODB.Recordset
    Dim sql As String
    
    ' ベース名が存在しなければ新規登録(Rev00)、存在すれば現在のRev + 1を返す
    sql = "SELECT CurrentRevision FROM DrawingHistory WHERE BaseFileName = '" & baseName & "'"
    Set rs = New ADODB.Recordset
    rs.Open sql, conn, adOpenStatic, adLockReadOnly
    
    If rs.EOF Then
        ' 新規登録用の初期SQLを別途用意するか、ここでINSERTを検討
        ' 今回は簡略化のため、既存レコードがある前提とする
        GetNextRevisionFromDB = 1
    Else
        GetNextRevisionFromDB = rs!CurrentRevision + 1
    End If
    
    rs.Close
    Set rs = Nothing
End Function

''' <summary>
''' DBの情報を更新する
''' </summary>
Private Sub UpdateDBRevision(conn As ADODB.Connection, baseName As String, newRev As Integer, fullName As String)
    Dim sql As String
    sql = "UPDATE DrawingHistory SET " & _
          "CurrentRevision = " & newRev & ", " & _
          "LastUpdatedAt = GETDATE(), " & _
          "LastUpdatedBy = '" & Environ("USERNAME") & "', " & _
          "FilePath = '" & Replace(fullName, "\", "\\") & "' " & _
          "WHERE BaseFileName = '" & baseName & "'"
    
    conn.Execute sql
End Sub

''' <summary>
''' ファイル名からベース名を取得(枝番 "_RevXX" を除去するロジック)
''' </summary>
Private Function GetBaseFileName(fullName As String) As String
    ' 実務では正規表現(VBScript.RegExp)を使用して、
    ' "_Rev[0-9]{2}" のパターンを正確に除去する設計にすべき
    Dim pos As Integer
    pos = InStrRev(fullName, "_Rev")
    If pos > 0 Then
        GetBaseFileName = Left(fullName, pos - 1)
    Else
        ' 拡張子を除去
        GetBaseFileName = Left(fullName, InStrRev(fullName, ".") - 1)
    End If
End Function

4. チーフアーキテクトの視点:ここが「分かれ目」だ

このコードを単にコピペして終わらせるなら、君はただのプログラマーだ。この設計の背後にある「リスク管理」を理解してこそ、プロフェッショナルと言える。

① トランザクションの境界線(Atomicity)

コード内で `connection.BeginTrans` と `connection.CommitTrans` を使っている理由を理解しているか?
もし、`acadDoc.SaveAs` が成功した後に、ネットワーク瞬断で `UpdateDBRevision` が失敗したらどうなる?
DB上は「Rev01」のままだが、ファイルシステムには「Rev02」が存在する。この「不整合」こそが、自動化ツールにおける最大の敵だ。
「ファイル保存が成功したときのみ、DBを確定させる」。この順序を守ることが、堅牢な設計の鉄則だ。

② パフォーマンスの重み

`GetNextRevisionFromDB` 内で毎回 `Recordset` を開閉しているが、大量の図面をバッチ処理する場合は、Connectionオブジェクトを使い回す(Connection Poolingの概念)設計に昇格させる必要がある。

③ 拡張性:ファイルパスの正規化

`Replace(fullName, “\”, “\\”)` を見逃してはいけない。SQL Serverの文字列リテラルにおいて、バックスラッシュはエスケープ文字として扱われるリスクがある。DBに格納する際は、常にパスの正規化を意識せよ。

④ セキュリティ

本コードでは簡略化のために接続文字列を定数にしているが、実務では `App.config` や環境変数、あるいは暗号化された設定ファイルから取得すべきだ。ソースコードにパスワードをハードコードするのは、プロフェッショナルとして最も恥ずべき行為の一つである。

結びに代えて

自動化とは、単に「楽をするための手段」ではない。「人間が介在することによって発生する不確実性を、排除するためのエンジニアリング」だ。

SQL ServerとAutoCADを同期させるこのシステムは、図面管理の信頼性を劇的に向上させる。しかし、その信頼性は、エラーが起きたときに「システムがどう振る舞うか」を設計段階で決めておくことでしか担保できない。

さあ、次のプロジェクトでは、単なる「便利ツール」ではなく、「壊れないシステム」を構築してほしい。

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