図面管理の極北:SQL Server連携によるチェックイン・チェックアウト制御の完全実装
多くのエンジニアが「ファイルサーバーに置けば十分だ」と慢心している。しかし、数百人規模の設計組織において、Windowsの標準的なファイルロック(共有違反)に頼った運用がいかに脆弱であるかは、大規模プロジェクトで不整合な図面が量産された経験がある者なら痛いほど理解しているはずだ。
AutoCAD VBAにおける真の図面管理とは、単にファイルを開閉することではない。「誰が、いつから、どの意図でその図面を独占しているか」という状態を、ファイルシステムから切り離してデータベース(SQL Server)で管理することにある。
本稿では、SQL Serverをバックエンドとしたチェックイン・チェックアウト制御を、AutoCAD VBAで実装するためのアーキテクチャと、メモリリークを許さない極限のコーディング手法を詳解する。
1. システムアーキテクチャの設計
まず、ファイルシステムに依存せず、DB側で「権限」を定義する。
DBテーブル設計(DrawingControl)
最低限、以下のカラムを持つテーブルをSQL Server上に構築せよ。
| カラム名 | 型 | 説明 |
|---|---|---|
| `DrawingID` | INT (PK) | 図面の一意識別子 |
| `FilePath` | NVARCHAR(MAX) | フルパス |
| `LockStatus` | TINYINT | 0: 解放, 1: チェックアウト中 |
| `LockedBy` | NVARCHAR(100) | ユーザー名 (OSユーザーまたは社内ID) |
| `LockTimestamp` | DATETIME | ロック取得日時 |
| `Version` | INT | リビジョン管理用 |
制御フロー
1. Open要求: DBを参照 $\rightarrow$ `LockStatus`が0なら自身を`LockedBy`に書き込み、ReadOnly=Falseでオープン。
2. 競合発生: `LockStatus`が1かつ他者が保持している場合、ReadOnly=Trueでオープンを強制。
3. Save/Close要求: 保存完了後、DBの`LockStatus`を0に更新し、`Version`をインクリメント。
2. 実装:チェックアウト制御(オープン処理)
VBAにおける最大の罠は、COMオブジェクトのライフサイクル管理だ。特にADODB接続を不用意に保持し続けると、AutoCADのプロセスが不安定になる。接続は「短く、速く、確実に」切り離すのが鉄則である。
' --- 参照設定: Microsoft ActiveX Data Objects 6.1 Library ---
Option Explicit
Private Const CONN_STR As String = "Provider=SQLOLEDB;Data Source=YOUR_SERVER;Initial Catalog=DrawingDB;Integrated Security=SSPI;"
''' <summary>
''' 図面をデータベース制御下でオープンする
''' </summary>
''' <param name="dwgPath">図面のフルパス</param>
Public Sub SecureOpenDrawing(ByVal dwgPath As String)
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim isLocked As Boolean
Dim lockedBy As String
Dim currentUser As String
currentUser = Environ("USERNAME") ' Windowsログイン名を取得
On Error GoTo ErrorHandler
' 1. データベース接続 (Scopeを最小限にする)
Set cn = New ADODB.Connection
cn.Open CONN_STR
' 2. 現在のロック状態を確認
Dim sql As String
sql = "SELECT LockStatus, LockedBy FROM DrawingControl WHERE FilePath = '" & Replace(dwgPath, "'", "''") & "'"
Set rs = cn.Execute(sql)
If rs.EOF Then
MsgBox "DBに登録されていない図面です。管理者に連絡してください。", vbCritical
GoTo Cleanup
End If
isLocked = (rs!LockStatus = 1)
lockedBy = Nz(rs!LockedBy, "")
' 3. ロック判定と処理
If isLocked And (lockedBy <> currentUser) Then
' 他者が編集中のため、読み取り専用で開く
MsgBox "この図面は現在 " & lockedBy & " が編集中です。読み取り専用で開きます。", vbInformation
ThisDrawing.Application.Documents.Open dwgPath, True ' ReadOnly = True
Else
' ロック取得処理(チェックアウト)
Dim updateSql As String
updateSql = "UPDATE DrawingControl SET LockStatus = 1, LockedBy = '" & currentUser & "', " & _
"LockTimestamp = GETDATE() WHERE FilePath = '" & Replace(dwgPath, "'", "''") & "'"
cn.Execute updateSql
' 書き込み可能状態で開く
ThisDrawing.Application.Documents.Open dwgPath, False ' ReadOnly = False
End If
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 "Database Error: " & Err.Description, vbCritical
Resume Cleanup
End Sub
' Null回避用ヘルパー関数
Private Function Nz(ByVal value As Variant, ByVal valueIfNull As String) As String
If IsNull(value) Then Nz = valueIfNull Else Nz = CStr(value)
End Function
3. 実装:チェックイン制御(保存・クローズ処理)
AutoCAD VBAには`.NET API`のような強力なイベントハンドラ(`DocumentSaving`等)が不足している。そのため、標準の保存ボタンをバイパスし、独自の「保存&チェックイン」ルーチンを実装させるのがプロのやり方だ。
''' <summary>
''' 保存を実行し、データベースのロックを解除する
''' </summary>
Public Sub SecureSaveAndCheckIn()
Dim doc As AcadDocument
Set doc = ThisDrawing
' 1. 保存されていない変更があるか確認
If doc.Saved = True Then
MsgBox "変更がありません。チェックインを完了します。", vbInformation
Else
' 図面を保存
On Error Resume Next
doc.Save
If Err.Number <> 0 Then
MsgBox "保存に失敗しました。ネットワーク接続を確認してください。", vbCritical
Exit Sub
End If
On Error GoTo 0
End If
' 2. DBのロック解除とバージョン更新
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open CONN_STR
Dim sql As String
' LockStatusを0に戻し、Versionをインクリメントする
sql = "UPDATE DrawingControl SET LockStatus = 0, LockedBy = NULL, Version = Version + 1 " & _
"WHERE FilePath = '" & Replace(doc.Name, "'", "''") & "'"
cn.Execute sql
MsgBox "チェックインが完了し、ロックが解除されました。", vbInformation
cn.Close
Set cn = Nothing
End Sub
4. チーフアーキテクトの極限知見:安定性を担保する3つの要諦
① 「ゴーストロック」への対処(異常終了対策)
AutoCADがクラッシュした場合、DB上の`LockStatus`は`1`のままとなり、永久に誰も編集できない「デッドロック」状態に陥る。
これを防ぐため、チェックアウト時に`LockTimestamp`を記録させ、「ロック取得から24時間経過したものは、管理者権限で強制解除可能にする」というタイムアウトロジックをDBストアドプロシージャ側に実装せよ。
② Windows APIによるファイル実在確認の高速化
DBに問い合わせる前に、物理的にファイルが存在するかを確認すべきだ。VBAの`Dir`関数はネットワークパスにおいて不安定な挙動を示すことがある。`GetFileAttributes` APIを呼び出し、OSレベルでファイルの存在と属性を判定することで、無駄なDBコネクションのオーバーヘッドを削減できる。
Private Declare PtrSafe Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
Private Const INVALID_FILE_ATTRIBUTES As Long = -1
Public Function FileExists(ByVal path As String) As Boolean
FileExists = (GetFileAttributes(path) <> INVALID_FILE_ATTRIBUTES)
End Function
③ COMオブジェクトの断片化とメモリ管理
AutoCAD VBAはCOMベースであり、`AcadDocument`や`AcadEntity`などのオブジェクトをループ内で大量に生成すると、メモリの断片化が発生し、最終的に`Out of Memory`で落ちる。
特にDB連携のような外部ライブラリ(ADODB)を併用する場合、`Set obj = Nothing`は単なる作法ではなく、生存期間を制御するための必須命令である。
また、`ThisDrawing`への過度な参照を避け、必要な時だけローカル変数に代入して利用すること。
結びに代えて
本システムを導入することで、図面の「上書き保存による先祖返り」という、設計現場における最悪の事故を根絶できる。
だが、忘れるな。ツールは手段に過ぎない。重要なのは、DBによる厳格な制御と、それを運用する設計者の規律である。
エンジニアとして、単に「動くコード」を書くのではなく、「壊れないシステム」を設計せよ。それがプロフェッショナルの矜持である。
