基幹から来る支社コード・課コードは、テキストのまま流せば取り込みは通る。だが、後で階層クエリや集計に使おうとして詰まる。取り込みながら Lookup 関係へ変換する——その判断を先送りにすると、後工程のコストになって返ってくる。
結論から言う。代替キー(Alternate Key)を使えば、内部 GUID なしに Lookup を張れる。 親→子の順序を守り、「変換ジョブが緑(成功)」と「関係が張れた」を別物として確認する。この 3 点で、横長テキストコードは取込時に関係データに変わる。
コードと関係は別物——なぜ後回しにすると詰まるか
Dataverse に支社コード「A001」を文字列として格納しても、その行は「支社テーブルの A001 レコード」を参照していない。文字列の一致と Lookup 関係は別物だ。
文字列のままでは、Dataverse のリレーションシップ機能(階層ナビゲーション・関連レコード展開・ロールアップ集計)が一切使えない。基幹から来る横長コードを「いったんコードのまま流す」設計は、後で Lookup を張り直す移行コストとセットになる。
Microsoft 公式は代替キーを「外部システムとの統合で GUID を保持していない場合に一意識別する仕組み」として定義している(Define alternate keys to reference rows)。つまり、内部 GUID を知らなくても業務コードで関係を張る経路は、公式に用意されている。
代替キーで Lookup を張る——前提条件と実装の骨格
代替キーとは
Dataverse のテーブルは、行を一意に識別する主キーとして内部 GUID を持つ。代替キー(Alternate Key)は、業務コード等の外部識別子を GUID と等価な参照先として登録する仕組みだ。代替キーを定義した列は、Lookup を張る際の解決キーとして使える。
前提条件 3 点
1. 参照先テーブルに代替キーを定義する
Dataflow のマッピング画面で Lookup フィールドが選択できない場合、参照先テーブルに代替キーが未定義であることがほとんどだ。まず親テーブル(支社テーブル、課テーブル等)に対して代替キーを追加し、Dataflow のマッピングを再設定する(Field mapping considerations for standard dataflows)。
2. 代替キーの型は Text 型または Number 型のみ
Dataflow マッピングで利用できる代替キーの型は Text 型または Number 型に限られる。日付型・選択肢型等を代替キーとして定義している場合、Dataflow マッピングでエラーになる。業務コードが日付型フィールドで管理されている場合は Text 型で定義し直す(Field mapping considerations for standard dataflows、コミュニティ報告: Fabric Community)。
3. 対象は単一 Lookup 列
ポリモーフィック Lookup(複数テーブルのいずれかを参照する列)および多段階 Lookup は、現時点で Dataflow では非対応と公式に明記されている(“not currently supported”)。本記事が扱うのは「1 つの Lookup 列が 1 つの親テーブルを参照する」ケースに限る。
SDK と Web API での参照構文(参考)
Dataflow を使わず SDK または Web API でデータを流す場合、代替キーによる Lookup 参照は以下の構文で実現できる(Use an alternate key to reference a record)。
- SDK:
new EntityReference("account", "accountnumber", "A001")のように代替キー名と値を指定してLookup列を設定する。内部で代替キー値を検索し、対応する GUID を DB に保存する。 - Web API:
@odata.bind構文の URL 中に代替キー値を埋め込む(例:accounts(accountnumber='A001'))。
Dataflow のマッピング UI を使う場合は、上記を意識する必要はない。マッピング画面で「参照先テーブルの代替キー列」を選択すれば、同等の解決が内部で行われる。
親→子のロードオーダー——順序を守らないと「緑でも空」になる
単一 Dataflow 内の実行順序は保証されない
Dataflow 内のクエリ実行順序と Dataverse テーブルへのロード順序は、Microsoft 公式が「保証しない」と明記している(“The order of query execution, or loading order to Dataverse tables isn’t guaranteed.” — Mapping fields with relationships in standard dataflows)。
Power BI Premium や Microsoft Fabric のデータフローには「リンクエンティティ」「参照エンティティ」による GUI での依存関係管理機能があるが、Power Platform(Dataverse 向け)Dataflows には現時点でその機能がない。「依存グループを設定すれば順序が制御できる」という情報は、Fabric 側の機能の話であり、Dataverse 向け Dataflows には該当しない。
唯一の正規手順:親→子で別 Dataflow に分ける
公式の推奨手順は「親と子を別々の Dataflow に分け、親 Dataflow を先にリフレッシュする」だ(“We recommend that you separate child and parent tables into two dataflows, and first refresh the dataflow containing [parent artifacts].” — 同上)。1 対多のリレーションシップを持つテーブルは「別々の Dataflow が必要」とも明記されている(Migrate Data Between Dataverse Environments Using the OData Connector)。
支社→課→担当→代理店 という 4 段階のコード体系であれば、Dataflow は 4 つ(または階層ごとにグルーピングした複数)に分け、手動またはスケジューラーで上から順に実行する。自動オーケストレーションが必要なら Power Automate または Azure Data Factory(ADF)を外部スケジューラーとして組み合わせる(コミュニティ推奨: Power Platform Community)。
ロードオーダー設計チェックリスト
| 確認点 | OK の状態 |
|---|---|
| 親テーブルに代替キーが定義されているか | Text 型または Number 型で定義済み |
| 親と子が別 Dataflow に分かれているか | 階層ごとに独立した Dataflow |
| 実行順序が担保されているか | 手動順次実行 / Power Automate / ADF で順序を制御 |
| ソースデータに代替キー値の null がないか | Power Query で事前にフィルタまたは置換 |
「緑=成功」≠「関係が張れた」——確認は件数で行う
Dataflow は行レベルの Lookup 失敗を全体エラーにしない
Dataflow のリフレッシュ結果が緑(成功)でも、個別行の Lookup 列が空(null)になっているケースがある。Dataflow はこの行レベルの失敗をジョブ全体のエラーとして扱わないため、画面上は成功のまま通過する。
「緑で終わった=関係が張れた」と判断した瞬間、データ品質の確認を失う。
Lookup が空になる 4 パターン
| パターン | 再現条件 | 対処 |
|---|---|---|
| ① 親に代替キー未定義 | 参照先テーブルに代替キーが設定されていない | 親テーブルに代替キーを追加して再マッピング |
| ② 代替キーの型が非対応 | Text / Number 型以外(日付型等)で定義 | Text 型で定義し直す |
| ③ 子が親より先に実行 | スケジュールが並列 / 子が先に完了 | 親 Dataflow 完了後に子を実行 |
| ④ ソースのキー値が null | ソースデータに代替キー列が null / 空文字の行あり | Power Query で事前フィルタ / 置換 |
いずれも「Dataflow 全体は緑(成功)、個別行の Lookup はnull」という挙動をとる(Field mapping considerations for standard dataflows)。
確認手順
- RefreshHistory の詳細ログを確認する:Dataflow の更新履歴から行レベルのエラー件数を確認する。全体成功でも行エラーが記録されていることがある。
- 取込後に件数ベースで検証する:子テーブルの総件数と「Lookup 列が null でない行数」を集計し、充足率を確認する。Power Apps / Power Automate から Dataverse テーブルをクエリして
filter(子テーブル, 親lookup列 ne Blank())の件数と全件数を比較するのが最速だ。
つなぎ先が存在しない行は Lookup が空のまま取り込まれる。これは忠実な挙動であり、ソース側のデータ欠損を正直に出している。「なぜ一部の行だけ Lookup が空か」という問いの答えは、Dataverse 側ではなくソースのコード値にある。
意図的に壊して証明する
設計の正しさは、正常系の成功だけでは確認できない。順序を意図的に違反して、Dataflow が正しく「空」を返すことを確かめる。
検証手順:順序違反パターン
- 準備:親テーブル(支社テーブル)と子テーブル(課テーブル)の Dataflow を用意し、課テーブルに支社テーブルへの Lookup 列を設定する。
- 順序違反実行:子(課)の Dataflow を先にリフレッシュし、親(支社)の Dataflow を後に実行する。
- 件数確認:子テーブルの「支社 Lookup 列が null でない行数」を集計する。順序違反で先に流した段階では、支社レコードがまだ存在しないため Lookup 列は全行 null になるはずだ。
- 正規順序で再実行:親(支社)を先にリフレッシュしてから子(課)を再実行する。件数を再集計し、Lookup 充足率が回復することを確認する。
この検証を一度やると、2 つのことが見えてくる。まず、「緑でも Lookup が空になる」がリアルな挙動だと体感できる。次に、「件数確認が唯一の証明手段」であることが理解できる。設計書に「件数確認ステップ」を入れるかどうかは、この体感があるかどうかで変わる。
確認コマンド例(Dataverse OData クエリ)
# 子テーブル全件
GET /api/data/v9.2/cr_courses?$select=cr_courseid,cr_branch_lookup&$count=true
# Lookup が設定されている行のみ
GET /api/data/v9.2/cr_courses?$filter=_cr_branch_lookup_value ne null&$count=true
2 つの件数が一致すれば Lookup 充足率 100%。乖離があれば、上記 4 パターンのいずれかが原因だ。
まとめ
取込時正規化の判断軸は 3 つに絞られる:代替キーを親テーブルに定義する、親→子の順序を別 Dataflow で担保する、「緑=成功」を件数で証明する。この 3 点を設計書に入れるかどうかが、後工程のコストを決める。
次の一歩:まず参照先テーブルに代替キー(Text 型)を定義し、Dataflow のマッピング画面で Lookup フィールドが選択可能になることを確認する。次に親と子を別 Dataflow に分けて順序違反検証を一度やる。
関連記事:
- [Dataverse 代替キーで Upsert を安全にする——キー衝突を制御する設計](リンク予定)
- [Dataverse の Lookup は SQL JOIN ではない——参照解決の仕組みを理解する](リンク予定)
- [Lookup → テキストコード突合への切り替え——外部連携の突合クエリ設計](リンク予定)