# API リファレンス: SOrchestrator

`SOrchestrator` は ApexBlueprint の **実行エンジン** です。`SBlueprint` で組み立てた設計図を受け取り、依存関係をトポロジカルソートで解析して、正しい順序で DML insert を実行します。API は意図的に **4 メソッドだけ** に絞られています。

使い方や典型シナリオは [SOrchestrator で依存解決と実 DML 挿入](/ja/apex-stem/docs/apex-blueprint-sorchestrator-guide) を参照してください。

## Static ファクトリ

| メソッド | 用途 |
|---|---|
| `SOrchestrator.start()` | 通常用。内部で標準の DML 実行を使う |
| `SOrchestrator.start(IDmlOperator dmlOperator)` | DML 実行層を差し替える。テストでは `new MockDmlOperator()` を渡して **実 DML を発火させずに挙動を検証** できる |

```apex
// 本番 (実 DML)
SOrchestrator orchestrator = SOrchestrator.start();

// テスト (DML なし、 ApexBlueprint 自身のテストで使うパターン)
SOrchestrator orchestrator = SOrchestrator.start(new MockDmlOperator());
```

`MockDmlOperator` は ApexBlueprint OSS 内部 (`DmlOperators/`) に含まれており、主に **ApexBlueprint 自身のテスト** を書く場面で使います。通常のテストデータ生成用途では `SOrchestrator.start()` (引数なし) を使います。

## 登録と実行

| メソッド | 用途 |
|---|---|
| `add(SBlueprint blueprint)` | 1 つの `SBlueprint` をキューに登録。**追加順は無視される** (内部のトポロジカルソートで insert 順が決定する) |
| `create()` | 登録された全 blueprint を解析し、依存解決後に DML insert を実行。**戻り値は `void`** (一旦 `SOrchestrator` を変数に受けてから `create()` を呼ぶ) |

```apex
SOrchestrator orchestrator = SOrchestrator.start()
    .add(SBlueprint.of(Account.class).alias('parentAccount').template(Blueprints.accBasic()))
    .add(
        SBlueprint.of(Opportunity.class)
            .set('Name', 'Test Opportunity')
            .use('parentAccount', 'Id', 'AccountId')
            .alias('targetOpp')
    );
orchestrator.create();
```

## 結果の取り出し

| メソッド | 用途 |
|---|---|
| `getByAlias(String aliasName)` | `create()` 後、alias で生成済み SObject を取り出す。戻り値は `SObject` (利用側でキャスト) |

存在しない alias を渡すと **`null` が返る** (例外ではない) ため、typo に気付きにくい場合は取り出した直後に `Assert.isNotNull(...)` で守ると安全です。

```apex
Account parent = (Account) orchestrator.getByAlias('parentAccount');
Opportunity opp = (Opportunity) orchestrator.getByAlias('targetOpp');
```

`.times(...)` 付きで量産した blueprint は、alias の `{#}` プレースホルダ展開後の名前で個別に取り出せます (`'con_1'` / `'con_2'` / ...)。`withChildren` でネストした blueprint には `__Account_0_1___Contact_1_1__` のような **自動 alias** が振られるため、取り出す必要があれば必ず `.alias(...)` を明示してください。

## 主な例外 (`create()` 時)

| 状況 | 例外型 / メッセージ (抜粋) |
|---|---|
| 循環依存 (`A.use('B', ...)` と `B.use('A', ...)` が両方成立) | `ApexBlueprintException`: `Circular or invalid reference detected` |
| 同一 blueprint チェーン内で alias 重複 | `ApexBlueprintException`: `Duplicate alias detected` |
| 別の `.add(...)` 間で alias 重複 | `ApexBlueprintException`: `Duplicate alias detected` |
| 存在しない alias を `.use(...)` で参照 | `ApexBlueprintException`: `Circular or invalid reference detected` (内部的に同じ扱い) |
| 子の lookup が複数で `parentIdField` 未指定 | `ApexBlueprintException`: `multiple parent relationships with the same parent object` |
| Apex 標準 DML が失敗する条件 (必須項目欠落 / バリデーション違反 等) | **通常の `DmlException` がそのまま** |

**例外の型が、そのまま原因の切り分けになります。** `ApexBlueprintException` なら宣言のミス (テストコードを直す)、`DmlException` なら org が insert を拒否した (template か org 設定を直す)。

> ⚠️ v2.0.0 の破壊的変更です。それ以前はフレームワークの検証エラーも素の `DmlException` だったため、既存の `catch (DmlException)` では捕まらなくなります。

## 関連ドキュメント

- [SOrchestrator で依存解決と実 DML 挿入](/ja/apex-stem/docs/apex-blueprint-sorchestrator-guide): start / add / create / getByAlias の使い方
- [API リファレンス: SBlueprint](/ja/apex-stem/docs/apex-blueprint-api-sblueprint): `.add(...)` に渡す設計図の API
- [親子・量産・参照のパターン](/ja/apex-stem/docs/apex-blueprint-relations-and-bulk): `withChildren` / `times` / `{P0}` 等の応用
- [ApexBlueprint ガイドへ戻る](/ja/apex-stem/docs/apex-blueprint-guide)
