Power Automateを使ってDataverseのデータを更新するとき、「もしフローの途中でエラーが起きたら、書き込み済みのデータをどうするか」という問題は常に付きまとう。
Power Automateには『変更セット要求を実行する(Changeset)』アクションがあるから大丈夫、と思ってたけど、意外とできることが少なかった。
そこで今回は、Power Automateの「変更セット要求を実行する」アクションを詳しく調査してみたので、その結果の紹介と、このアクションを使ってもよい場面とプラグイン(Pro Code)を使うべき場面を考察してみる。
トランザクションについて
改めて「トランザクション」とは「一連の処理を『全部やる』か『全部やらない』か、どっちかにする仕組み」のこと。
わかりやすい例が「銀行振込」で、
・Aさんの口座から1万円引く
・Bさんの口座に1万円足す
もし「1」だけ成功して、システムエラーで「2」が失敗したら、Aさんの1万円は消えてしまう。
だから、途中で何かが失敗したら、最初から何もなかったことにして(ロールバックして)、Aさんの口座残高を元に戻す。 これが「トランザクション処理」。
トランザクションの実現「変更セット要求を実行する」アクション


もし3つ目の処理でエラーが起きたら、1つ目と2つ目の書き込みも「なかったこと」にしてくれるので(ロールバックされる)、中途半端なデータ残りとかを防げる。
動作確認
まずは簡単な動作確認。






※注文明細の個数は1以上となるようDataverse側で設定済み






ということで、失敗時にしっかりロールバックされるので、トランザクションが効いていることが確認できる。
「変更セット要求の実行」内でリレーション(親子関係)をつくる
「変更セット要求の実行」内で、リレーション(親子関係)を持ったレコードの作成を行う場合は、ひと工夫が必要。




そのため、「親→子」の順にスコープに入れれば、親が作られた後に、その親レコードのGUIDを使用して子レコードをリレーション込みで作成することができる。
ODataの仕様 (OData v4.0 Part 1, 11.7.4):
“Requests within a change set MUST be executed sequentially.” (変更セット内のリクエストは、順次実行されなければならない。)
もちろん「子→親」の順にスコープに入れると、トランザクションは失敗する。
トラブルシューティング:変更セット要求でInternalServerErrorが起きる場合は「アクション名」に注意

※変更セット要求はBad Gatewayエラーになる。
※ただし、なぜかレコードは作成される。
そこで、変更セット要求内のアクションは、英名に変えること。
こちらのサイトを参考にさせていただきました。
Power Automate「変更セット要求」の難しい点と使い所
最後、実際に動作検証を行った結果見えてきた、「変更セット要求」アクションの難しい点を2つと、使っても大丈夫な場面を考察してみる。
1. 実行タイミングの壁
1つ目は「フロー内で実行する必要がある(アクションだから当たり前だけど)」ための実行タイミングについて。
キャンバスアプリなら「ボタン押下時」にフローを呼べばいいけど、モデル駆動型アプリから呼ぶ場合は、どうしても「対象データの保存(トリガー)」が起点になってしまう。
※リボンメニューからフローを呼ぶことも一応できるけど…
そのため、もしフロー側の処理(トランザクション)が失敗した場合、トリガーとして既に保存されてしまったデータを自前で削除(ロールバック)しなければならない。
この「後始末」の実装が意外とめんどくさい。
2.ロジックの壁(条件分岐・ループ不可)
アクションの仕様上、「変更セット要求」スコープの中にはループ(Apply to each)も条件分岐(If)も配置できない。
つまり、「書き込んだ結果を見て、次の処理を変える」といった動的なトランザクションは組めない。
それでも「変更セット要求」が使える場面
以下の条件をすべて満たすなら、手軽な変更セット要求がおすすめ。
- 厳密な「排他制御」までは不要
- トランザクション内で複雑な処理(If/Loop)をしない
- Dataverse内だけで完結する処理である
典型的な成功パターン:
「注文」ヘッダーと「注文明細」を同時に作成する、といった親子関係の登録処理。
ただし、ここに「在庫の引き当て」や「条件による保存ブロック」が入ってくるなら、プラグインの検討が必要になる。
プラグイン(C# / Power Fx)を選ぶべき理由
変更セットの要求ではなく、プラグインを実装するメリットは以下の4つがある。
「保存前(Pre-Operation)」で止められる
モデル駆動アプリで「データを保存する」操作を行う場合も、Pre-Operationで直前に検証し、実際にデータを保存する前に処理をキャンセルできる。
よって、「ゴミデータの削除処理(補償トランザクション)」が不要になる。
複雑なロジックを含めたトランザクション
プラグイン(C#またはローコード)の中であればIfもループも使用できるので、書き込みながら判断する、みたいな処理の実現も可能。
Etag(RowVersion)を使用した厳密な排他制御
標準フローでは実装困難なEtag(RowVersion)を使用した排他制御も、プラグインなら実装可能。
「誰かが編集中のデータを上書きしてしまう」事故を防ぐなら、この方法が最も良いかと。
※ただし、「モデル駆動型アプリ」の「標準の保存機能」と、この「排他」を共存させるのはかなり大変らしい。これについては別記事で書いてみる。
即時のエラーフィードバック(ユーザー画面にアラートを出せる)
フローの場合、失敗通知は「メール」などになりがちだけど、プラグインなら画面上に赤帯のアラート(ビジネスプロセスエラー)を即座に出せる。
ユーザー体験(UX)の差はかなり大きくなる。
まとめ
ということで、Power Automateの「変更セット要求」アクションは気軽に使えるけど、使いどころを選ぶ機能だった。
そのうち、プラグインについても詳しく調査してみて、本当にこれらが実現可能かを見ていきたいなと。
Tips:「変更セット要求」アクションの内部的な仕組み:ODataのBatchリクエスト
「変更セット要求」アクションの裏側はWeb APIの標準仕様である「OData Batch」を使用しているらしい。
普通にアクションを並べると、Power Automateは Dataverse に対して「1行作って」→(完了待ち)→「次も1行作って」という感じで、毎回通信する。
でも、変更セットを使うと、枠の中にあるリクエストを一度にまとめて送りつけるので、受け取ったDataverse側は、全部メモリ上で処理して、問題なければ一気にコミットする。
だから「全部OK」か「全部NG」かが保証される。

コメント