基幹から来る支社コード・課コードは、テキストのまま流せば取り込みは通る。だが、後で階層クエリや集計に使おうとして詰まる。取り込みながら 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)。

  • SDKnew 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)。

確認手順

  1. RefreshHistory の詳細ログを確認する:Dataflow の更新履歴から行レベルのエラー件数を確認する。全体成功でも行エラーが記録されていることがある。
  2. 取込後に件数ベースで検証する:子テーブルの総件数と「Lookup 列が null でない行数」を集計し、充足率を確認する。Power Apps / Power Automate から Dataverse テーブルをクエリして filter(子テーブル, 親lookup列 ne Blank()) の件数と全件数を比較するのが最速だ。

つなぎ先が存在しない行は Lookup が空のまま取り込まれる。これは忠実な挙動であり、ソース側のデータ欠損を正直に出している。「なぜ一部の行だけ Lookup が空か」という問いの答えは、Dataverse 側ではなくソースのコード値にある。


意図的に壊して証明する

設計の正しさは、正常系の成功だけでは確認できない。順序を意図的に違反して、Dataflow が正しく「空」を返すことを確かめる。

検証手順:順序違反パターン

  1. 準備:親テーブル(支社テーブル)と子テーブル(課テーブル)の Dataflow を用意し、課テーブルに支社テーブルへの Lookup 列を設定する。
  2. 順序違反実行:子(課)の Dataflow を先にリフレッシュし、親(支社)の Dataflow を後に実行する。
  3. 件数確認:子テーブルの「支社 Lookup 列が null でない行数」を集計する。順序違反で先に流した段階では、支社レコードがまだ存在しないため Lookup 列は全行 null になるはずだ。
  4. 正規順序で再実行:親(支社)を先にリフレッシュしてから子(課)を再実行する。件数を再集計し、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 → テキストコード突合への切り替え——外部連携の突合クエリ設計](リンク予定)

→ 関連記事:Power Platform 個人開発環境の作り方と設計テンプレート蓄積