【実務・中級編】【上級プロ向け】外部データベース(SQL Server / Excel)と連動した図面自動生成・型番駆動型ファミリーチューブ – SolidWorks VBA解析バイブル

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

脱・マクロ職人:外部DB連動型「型番駆動ファミリーチューブ」構築の設計思想

「マクロを作りました。これで作業は一瞬で終わります」

もし君が、クライアントや上司にそう報告しようとしているのなら、今すぐその言葉を飲み込むべきだ。それは「自動化」ではない。ただの「不安定な自動記録」に過ぎない。

真のエンタープライズ・オートメーションとは、「データが変化しても、システムが自律的に整合性を保ち、エラーを自己検知し、完遂する」ことを指す。

今回扱うテーマは、SQL ServerやExcelといった外部データベース(Single Source of Truth: 信頼できる唯一の情報源)から製品仕様を吸い上げ、SolidWorksのコンフィギュレーションを切り替え、それに対応する図面を生成・配置・PDF化・自動仕分けまで行う、いわゆる「型番駆動型ファミリーチューブ」の構築だ。

この記事では、単なるコードの書き方ではなく、プロフェッショナルが実践する「破綻しない設計」と「APIの極限制御」について伝授する。

1. アーキテクチャ設計:関心の分離(Separation of Concerns)

初心者は、一つのプロシージャの中に「DB接続」「SolidWorks操作」「ファイル保存」をすべて書き込む。これは設計として最悪だ。DBの仕様が変わっただけで、SolidWorksの操作ロジックまで壊れることになる。

堅牢なシステムを構築するには、以下の3つのレイヤーに分離せよ。

1. Data Access Layer (DAL): 外部DB(SQL/Excel)から、設計パラメータ(型番、寸法、構成要素)を「純粋なデータ」として取得する。
2. Business Logic Layer (BLL): 取得したデータに基づき、「どのモデルの、どのコンフィギュレーションを、どのテンプレートで展開すべきか」という意思決定を行う。
3. Automation/Driver Layer (AL): SolidWorks APIを叩き、実際にモデルを動かし、図面を生成する。

この分離により、テストが容易になり、保守性が劇的に向上する。

2. 実装の急所:SolidWorks APIを掌握する

図面自動生成において、多くの開発者が陥る罠が3つある。

① コンフィギュレーションの同期不全

モデルのコンフィギュレーションを切り替えた後、図面ビューがその変更を正しく認識していないケースだ。図面ビューの `ReferencedConfiguration` プロパティを明示的に制御しなければ、図面は「古い構成」を表示し続ける。

② ビュー配置の座標計算

「なんとなく」でビューを置くのではない。テンプレート図面のシートフォーマットに基づき、基準点(Origin)からの相対座標を計算して配置せよ。

③ リビルドのコスト管理

`ForceRebuild3` は強力だが、重い。ループ内で不必要に呼び出すと、処理時間は指数関数的に増大する。必要なタイミング、必要なオブジェクトに対してのみ実行するのがプロの作法だ。

3. プロダクション・コード・テンプレート

以下に、実務レベルでそのまま構造として利用できる、堅牢なVBAコードの設計例を示す。ここでは簡略化のため、DB接続部は概念的な関数としているが、構造はそのまま利用できる。

Option Explicit

' ==============================================================================
' プロジェクト: Model-Driven Drawing Automation
' 役割: 型番駆動による図面一括生成エンジン
' 著者: Chief Architect
' ==============================================================================

' 定数定義:マジックナンバーを排除し、保守性を高める
Private Const DRAWING_TEMPLATE_PATH As String = "C:\Standard\Templates\Drawing_A3_ISO.drwdot"
Private Const OUTPUT_ROOT_DIR As String = "C:\Output\Project_Alpha\"

' 列挙型:状態管理を明確にする
Enum ProcessStatus
    Status_Success = 0
    Status_Error_DB = 1
    Status_Error_SW_Model = 2
    Status_Error_SW_Drawing = 3
    Status_Error_IO = 4
End Enum

''' <summary>
''' メインコントローラー:全体のオーケストレーションを担当
''' </summary>
Public Sub ExecuteBatchProcess()
    Dim swApp As SldWorks.SldWorks
    Set swApp = Application.SldWorks
    
    Dim targetList As Collection
    Set targetList = FetchTargetConfigurationsFromDB() ' DAL層の呼び出し
    
    Dim item As Variant
    Dim currentStatus As ProcessStatus
    
    Debug.Print "--- Batch Process Started: " & Now & " ---"
    
    ' ループ内でのエラーハンドリング:一つの失敗で全体を止めない
    For Each item In targetList
        ' itemはDictionary形式を想定 (Key: PartPath, Value: ConfigName)
        currentStatus = ProcessSingleUnit(swApp, item)
        
        If currentStatus <> Status_Success Then
            Debug.Print "FAILED: " & item("PartName") & " | Error Code: " & currentStatus
            ' ここでエラーログをDBやファイルに書き出す設計にせよ
        Else
            Debug.Print "SUCCESS: " & item("PartName")
        End If
    Next item
    
    Debug.Print "--- Batch Process Completed ---"
End Sub

''' <summary>
''' 単一ユニットの処理:BLL層のロジック
''' </summary>
Private Function ProcessSingleUnit(swApp As SldWorks.SldWorks, data As Object) As ProcessStatus
    On Error GoTo ErrorHandler
    
    Dim modelPath As String: modelPath = data("Path")
    Dim configName As String: configName = data("Config")
    Dim partName As String: partName = data("PartName")
    
    ' 1. モデルのロードとコンフィギュレーション切り替え
    Dim swModel As SldWorks.ModelDoc2
    Set swModel = swApp.OpenDoc6(modelPath, swDocPART, swOpenDocOptions_Silent, "", 0, 0)
    
    If swModel Is Nothing Then GoTo Err_Model
    
    ' コンフィギュレーションの切り替え
    Dim swConfMgr As SldWorks.ConfigurationManager
    Set swConfMgr = swModel.ConfigurationManager
    Dim swConf As SldWorks.Configuration
    Set swConf = swConfMgr.ActiveConfiguration
    
    ' 重要:コンフィギュレーションの強制切り替え
    Dim res As Boolean
    res = swModel.ShowConfiguration2(configName)
    If Not res Then GoTo Err_Model
    swModel.ForceRebuild3 True
    
    ' 2. 図面の生成
    Dim swDrawing As SldWorks.DrawingDoc
    Set swDrawing = swApp.NewDocument(DRAWING_TEMPLATE_PATH, 0, 0, 0)
    If swDrawing Is Nothing Then GoTo Err_Drawing
    
    ' 3. ビューの配置(プロのテクニック:座標指定)
    ' ここでは例として、正面図を(0.1, 0.1)に配置
    Dim swView As SldWorks.View
    Set swView = swDrawing.CreateDrawViewFromModelView3(modelPath, "*Front", 0.1, 0.1, 0)
    
    If Not swView Is Nothing Then
        ' 重要:図面ビューが参照するコンフィギュレーションを明示的に指定
        swView.ReferencedConfiguration = configName
        swDrawing.ForceRebuild3 True
    Else
        GoTo Err_Drawing
    End If
    
    ' 4. PDF出力とファイル仕分け
    Dim saveDir As String: saveDir = OUTPUT_ROOT_DIR & partName & "\"
    Call EnsureDirectoryExists(saveDir)
    
    Dim pdfPath As String: pdfPath = saveDir & partName & "_" & configName & ".pdf"
    Dim swExportData As SldWorks.ExportPdfData
    Set swExportData = swDrawing.CreateExportPdfData
    
    ' PDF保存実行
    Dim swDrawExt As SldWorks.ModelDocExtension
    Set swDrawExt = swDrawing.Extension
    Dim boolStatus As Boolean
    boolStatus = swDrawExt.SaveAs(pdfPath, swSaveAsCurrentVersion, swSaveAsOptions_Silent, swExportData, 0, 0)
    
    If Not boolStatus Then GoTo Err_IO
    
    ' クリーンアップ
    swApp.CloseDoc swDrawing.GetTitle
    swApp.CloseDoc swModel.GetTitle
    
    ProcessSingleUnit = Status_Success
    Exit Function

Err_Model:
    ProcessSingleUnit = Status_Error_SW_Model
    Exit Function
Err_Drawing:
    ProcessSingleUnit = Status_Error_SW_Drawing
    Exit Function
Err_IO:
    ProcessSingleUnit = Status_Error_IO
    Exit Function
ErrorHandler:
    Debug.Print "Unexpected Error: " & Err.Description
    ProcessSingleUnit = Status_Error_IO
End Function

' --- 以下、ユーティリティ関数(DAL/IO層) ---

Private Function FetchTargetConfigurationsFromDB() As Collection
    ' 本来はここを ADODB.Connection を用いて SQL Server へ接続する
    ' ここではデモ用に静的なコレクションを返す
    Dim col As New Collection
    Dim dict As Object
    
    ' Mock Data 1
    Set dict = CreateObject("Scripting.Dictionary")
    dict.Add "Path", "C:\Models\BasePart.SLDPRT"
    dict.Add "Config", "Small_Size"
    dict.Add "PartName", "BasePart_S"
    col.Add dict
    
    ' Mock Data 2
    Set dict = CreateObject("Scripting.Dictionary")
    dict.Add "Path", "C:\Models\BasePart.SLDPRT"
    dict.Add "Config", "Large_Size"
    dict.Add "PartName", "BasePart_L"
    col.Add dict
    
    Set FetchTargetConfigurationsFromDB = col
End Function

Private Sub EnsureDirectoryExists(ByVal folderPath As String)
    ' フォルダが存在しなければ作成する(WinAPIまたはFileSystemObjectを使用)
    If Dir(folderPath, vbDirectory) = "" Then
        Dim fso As Object
        Set fso = CreateObject("Scripting.FileSystemObject")
        ' 再帰的に作成する場合は、さらに高度なロジックが必要
        ' ここでは簡易的に作成
        MsgBox "Directory Creation Logic Required: " & folderPath
    End If
End Sub

4. エンタープライズ運用における「鉄則」

このコードをベースに、実務へ投入する際は以下の3点を必ず検討せよ。

1. ログの永続化

`Debug.Print` は開発用だ。本番環境では、処理結果(成功・失敗、エラー内容、実行時間)を必ずCSVまたはSQL Serverのログテーブルに書き出せ。これがないと、夜間に回した自動化が失敗した際、原因究明に丸一日を費やすことになる。

2. ネットワーク・レイテンシへの配慮

DBやモデルファイルがネットワークドライブ上にある場合、`OpenDoc6` の速度は劇的に低下する。大量のファイルを処理する場合、一度ローカルの高速なSSDに同期(キャッシュ)してから処理を開始する設計にせよ。

3. 「例外」の定義

「モデルファイルはあるが、指定したコンフィギュレーションが存在しない」
「図面テンプレートが移動している」
「ネットワークが一時的に切断された」
これらは「バグ」ではなく「想定される例外」だ。例外が発生した際に、システムを「停止」させるのか、「スキップして次へ進む」のか。このポリシーを設計段階で決定しておくこと。

結論

自動化エンジニアの価値は、コードの行数ではなく、「そのシステムがいかに堅牢で、いかにビジネスの変更に強いか」で決まる。

単なるマクロの書き手で終わるな。データとモデルのライフサイクルを制御する、アーキテクトであれ。

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