VisioとDBの「絆」を断ち切らないために。ページ削除時に整合性を保つ連動型クリーンアップの極意
こんにちは。技術の深淵へようこそ。
マクロの記録機能を使って、「ボタンを押したら図形が動いた」「ページが消えた」という感動を味わった時期は、誰にでもあります。でも、あなたが今、プロフェッショナルな自動化エンジニアへの階段を登ろうとしているなら、一つの大きな壁にぶつかっているはずです。
それは、「Visioの中だけで完結しない、外部の世界との整合性」という問題です。
例えば、Visioのページが「設計プロジェクトの工程」を表しており、その詳細データがSQL Serverなどのデータベース(DB)で管理されているケース。もし、ユーザーがVisioのページをポチッと削除してしまったら? Visioからは消えても、DBには「幽霊(Orphaned Record)」のようなデータが残り続け、システム全体の整合性が崩れてしまいます。
今日は、そんな「実務で必ず直面する問題」を解決するための、Visio VBAと外部DBを同期させる連動型削除ツールの作り方を伝授しましょう。ここをクリアすれば、あなたは「単なるマクロ使い」から「システム設計ができるエンジニア」へと進化できますよ。
1. 設計思想:なぜ「ただの削除」ではいけないのか?
エンジニアリングにおいて最も恐ろしいのは、「不整合(Inconsistency)」です。
通常の削除処理は、以下のような単発の動作です。
1. `ActivePage.Delete` $\rightarrow$ 完了!
しかし、我々が目指す「連動型削除」は、以下のトランザクション(一連の不可分な処理)として設計しなければなりません。
| ステップ | アクション | 失敗した場合の挙動 |
|---|---|---|
| ① 紐付け確認 | 削除対象のページに「DBのID」があるか? | 処理を中断(エラー) |
| ② DB更新 | SQL Serverの該当レコードを「削除済み」にする | Visioのページは消さない |
| ③ Visio削除 | ページを削除する | DBの更新をロールバックする |
「DBは更新したのに、Visioの削除でエラーが起きてページが残った」
「Visioは消えたのに、DBの更新に失敗してデータが残った」
このような事態を防ぐためのロジックを、これから一緒に組んでいきましょう。
2. 事前準備:ページとDBを繋ぐ「IDカード」
ページとDBを紐付けるには、Visioのページ自体に「このページはDBのどのレコードに対応しているか」という情報を持たせておく必要があります。
最もスマートな方法は、「Shape Data(シェイプデータ)」を活用することです。ページの背景にある透明なシェイプ、あるいはページそのもののプロパティに `DB_ID` という項目を持たせておきましょう。
3. 実装:連動型削除ツールのコード・テンプレート
それでは、核心に迫るコードを見ていきましょう。ここでは、`ADODB`(ActiveX Data Objects)を使用してSQL Serverと通信する、実戦的なコード例を提示します。
※ 事前にVBAエディタの [ツール] $\rightarrow$ [参照設定] から “Microsoft ActiveX Data Objects x.x Library” にチェックを入れておいてください。
Option Explicit
''' <summary>
''' ページ削除とDBレコード更新を同期させるメインルーチン
''' </summary>
Public Sub SynchronizedPageDelete()
Dim targetPage As Visio.Page
Dim dbID As String
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim connectionString As String
' 1. 対象ページの取得(ここでは現在アクティブなページを対象とする)
Set targetPage = ActivePage
' 2. ページに紐付くDB_IDを取得(Shape Dataから取得する例)
' ※あらかじめページ内の特定のシェイプに "DB_ID" プロパティを設定しておく想定
dbID = GetShapeDataValue(targetPage, "DB_ID")
If dbID = "" Then
MsgBox "このページにはDBとの紐付け情報(DB_ID)が見つかりません。削除を中止します。", vbExclamation
Exit Sub
End If
' 確認ダイアログ
If MsgBox("ページを削除し、関連するDBレコードも更新しますか?", vbQuestion + vbYesNo) <> vbYes Then Exit Sub
' 3. DB接続文字列の設定(環境に合わせて書き換えてください)
connectionString = "Provider=SQLOLEDB;Data Source=YOUR_SERVER;Initial Catalog=YOUR_DB;Integrated Security=SSPI;"
On Error GoTo ErrorHandler
' --- トランザクション開始の準備 ---
Set conn = New ADODB.Connection
conn.Open connectionString
' DB側のトランザクション開始
conn.BeginTrans
' 4. DBの更新処理 (DELETE または UPDATE)
' ここではレコードを「論理削除(is_deleted=1)」にする例をとります
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = "UPDATE YourTable SET is_deleted = 1 WHERE RecordID = ?"
.Parameters.Append .CreateParameter("@id", adVarChar, adParamInput, 50, dbID)
.Execute
End With
' 5. Visio側の削除処理
' DBの更新が成功した直後にVisioのページを削除
targetPage.Delete
' 6. 全て成功したらDBの変更を確定(コミット)
conn.CommitTrans
MsgBox "ページとDBの同期削除が完了しました。", vbInformation
CleanUp:
' オブジェクトの解放
If Not conn Is Nothing Then
If conn.State = adStateOpen Then conn.Close
End If
Set conn = Nothing
Set cmd = Nothing
Exit Sub
ErrorHandler:
' エラーが発生した場合は、DBの変更を取り消す(ロールバック)
If Not conn Is Nothing Then
If conn.State = adStateOpen Then
conn.RollbackTrans
MsgBox "エラーが発生したため、DBの更新を取り消しました。Visioのページは保持されています。" & vbCrLf & _
"Error: " & Err.Description, vbCritical
End If
Else
MsgBox "接続エラー: " & Err.Description, vbCritical
End If
Resume CleanUp
End Sub
''' <summary>
''' 指定したページ内のシェイプからShape Dataの値を取得するヘルパー関数
''' </summary>
Private Function GetShapeDataValue(pg As Visio.Page, propName As String) As String
Dim shp As Visio.Shape
' ページ内の最初のシェイプを探索する例(実際は管理用の特定のシェイプを探すのが定石)
For Each shp In pg.Shapes
On Error Resume Next
GetShapeDataValue = shp.Cells("Prop.DB_ID").ResultIU ' Prop.の後にプロパティ名を指定
On Error GoTo 0
If GetShapeDataValue <> "" Then Exit Function
Next shp
End Function
4. 伝説のアーキテクトによる「極限の解説」
コードをただ眺めるだけでは、一生モノのスキルにはなりません。なぜこのような構造にしているのか、その「重み」を理解してください。
① `BeginTrans` と `RollbackTrans` の意味
これがこのコードの心臓部です。`conn.BeginTrans` を呼んだ瞬間、DBに対して「これから一連の作業を始めるから、全部終わるまで確定させないでね」と命令を出しています。
もし `targetPage.Delete` でエラー(例えばページがロックされている等)が起きた場合、`ErrorHandler` に飛び、`conn.RollbackTrans` が実行されます。これにより、「DBだけ更新されて、Visioにはページが残っている」という最悪の不整合を回避しているのです。
② 物理削除ではなく「論理削除」を推奨する理由
コード例では `UPDATE … SET is_deleted = 1` としています。これは「論理削除」と呼ばれる手法です。
実務において、間違えて削除してしまった時のリカバリを考えるなら、データを物理的に `DELETE` するのではなく、フラグを立てるだけで済むように設計するのが、プロの現場の鉄則です。
③ エラーハンドリングの重要性
`On Error GoTo ErrorHandler` を忘れてはいけません。自動化ツールにおいて、エラーは「起こるもの」です。エラーが起きた時に、システムを「安全な状態(整合性が取れた状態)」に引き戻すコードを書くこと。それが、初学者とプロフェッショナルの境界線です。
5. 陥りやすい罠(Pitfalls)
最後に、現場でよくある失敗を共有しておきます。
- 権限不足: VBAを実行するユーザーが、SQL Serverに対して `UPDATE` 権限を持っていないと、当然エラーになります。
- 接続文字列のミス: サーバー名やDB名が1文字違うだけで、コードは動かなくなります。これはテスト環境と本番環境で必ず確認してください。
- Shape Dataの命名規則: `shp.Cells(“Prop.DB_ID”)` のように、Visio内部では `Prop.` という接頭辞が必要です。これを忘れると、値は永遠に取得できません。
結びに
お疲れ様でした。ここまで読み進めたあなたは、もう単なる「マクロの記録」の域を完全に脱しています。
「Visioという図形描画ツールを、巨大な業務システムの一部として制御する」。
この視点を持てたことが、何よりの収穫です。
最初はエラーに苦しむかもしれません。しかし、エラーメッセージの一つひとつは、システムをより堅牢にするための「対話」です。一つずつ潰していけば、必ずあなたは、誰にも真似できない最強の自動化エンジニアになれるはずです。
応援していますよ。次はもっと複雑な、レイヤー操作や非同期処理の世界でお会いしましょう。
