Dataverseに新機能「Dataverse Functions」が追加(というか改名)されたらしいので、様々検証してみた。
※旧名は「Instant low-code plug-ins(ローコードプラグイン)」
これは「サーバーサイドの重い処理を、C#じゃなくてPower Fxで書けるようにした」という、かなりありがたい機能。
ただし、中身はゴリゴリの「Dataverseプラグイン」なので、特有の「制限」や「落とし穴」もしっかり継承している…
今回は、基本的なつくり方や使い方から、「トランザクションの挙動」や「処理速度」「再帰処理の限界」など、様々検証。
Dataverse Functionsについて
ざっくり言うと、「Power Fxを使って、サーバー側で動くロジックを作れる機能」のこと。
これまで「プラグイン」って言ったら、C#とかでゴリゴリコード書いてビルドして…っていう「プロ開発者の聖域」だったけど、それを、普段アプリで使ってるPower Fxで書けるようにしたのがこれ。
以前は「Dataverse Accelerator」から作成できる「ローコードプラグイン(Instant low-code plug-ins)」って名前だったけど、「Functions」に改名されて、より作りやすくなった感じ。
以下、Dataverse Acceleratorのローコードプラグインのアーカイブ記事。
Dataverse Functionsの主な使い道
- サーバーサイド実行:
アプリ(クライアント)側じゃなくてサーバーで動くから、大量データを扱う時のパフォーマンスも有利。 - Power Fxで記述:
.NETの知識不要。Canvasアプリの数式感覚で、裏側の処理を作れる。 - 再利用可能:
作ったFunctionは、Power AppsからもPower Automateからも呼び出せる。
一度作れば使い回せる「共通部品」にできるので、ロジックがばらけることを防げる。
「市民開発者でも、サーバーサイドの重たい処理や共通ロジックを、手慣れたPower Fxで作れるようになった」っていうのが嬉しいポイント。
⚠️ Dataverse Functionsの制限事項
このFunctions、裏側では従来の「Dataverseプラグイン」の仕組みで動いてるから、その制約もしっかり継承してるらしい。
1. 「2分」のタイムアウト(The 2-Minute Warning)
Functions(Custom API)は同期処理が基本。呼び出し元(アプリなど)は結果が返ってくるまで待機するんだけど、この待機時間には「最大2分(120秒)」というリミットがある。
処理が2分を超えた場合、サーバー側で処理が強制終了(Timeout Exception)される。
2. 「呼び出しの連鎖」は深度8まで(Depth Limit)
Function A が Function B を呼び、B が C を呼び… という「ネスト(入れ子)」や、データの更新がトリガーで別のロジックが動く連鎖には限界がある。
一般的に深度(Depth)8を超えると、プラットフォームが「無限ループしてない?」と判断してエラーを吐く。
(環境によっては16まで許容されることもあるけど、8で設計するのが鉄則)。
3. Power Fxの「方言」制限
キャンバスアプリで使える関数が全部使えると思ったら大間違い。
- 使えない関数:
Launch()(画面遷移)、Maps()、UI系の関数は全滅。あくまで「データ計算・ロジック」のみ。 - コレクション操作: 複雑なコレクション操作や、大量データの
Collectはメモリ制限に引っかかりやすい。
基本的なつくり方と使い方
それでは、基本的なつくり方と使い方。
Dataverse Functionのつくり方
今回は例として「メールの本文から請求書番号を正規表現で抽出する」関数を作ってみる。

まずは適当なソリューションを作成し、

[新規]→[自動化]→[関数]を選択。

表示名、説明、パラーメータ、計算式(Power Fx)を書いたら、[保存]を押す。

// Match関数を使って全件取得し、JSON形式のテキストにして返す
{
MatchedItems: JSON(
ForAll(MatchAll(InputText, "INV-\d{6}-\d{4}"), FullMatch),
JSONFormat.IndentFour
)
}これで「関数」は完成。編集したいときは種類が[機能]となっているやつを選択すれば、

式の編集が可能。

Dataverse FunctionをPower Automateから使う
作成した関数を、Power Automateから呼ぶときは「バインドしていないアクションを実行する」を使用。

[アクション名]で作成した関数を選んで、引数を設定すれば、

無事、正規表現で請求書番号が抽出できる。

Dataverse FunctionをPower Apps(キャンバス)から使う
作成した関数をキャンバスアプリから呼ぶ場合は、Environmentテーブルをアプリに追加すれば、そこから関数を呼び出すことができる。

他のFunctionsを呼び出すことも可能
作成した関数は他の関数から呼び出すことも可能。
新しい関数を作成し、キャンバスアプリと同様Environment経由で作成済みの関数を呼び出せる。

自己呼び出しも可能 = 再帰処理が実現できる!と思ったらできなかった話
一度保存してしまえば、関数から自分自身を呼び出すことも可能。
なので、こんな書き方で階乗を求める再帰処理も構築することは(一応)可能。

ただしこの関数、nが8以下(画像では5)までなら動くんだけど、

nをそれ以上大きくすると、

エラーが発生する。

Plugin Factorial failed with: CustomAPI parameter $result failed with error Error: Error attempting Invoke: new_Factorial. This low-code plugin’s execution was cancelled because the plugin logic caused an inifinite loop. Correct the plugin logic and try again.;;;;;;
これは「制限事項」に書いた「ネストの制限」に引っかかってるから。
最大8(一応16)なので、フォルダを掘る、みたいな再帰処理をつくるのは現実的ではない。
※そんなに使い道もないし。
Dataverse Functionsはトランザクションとして機能するか
色々なドキュメントを呼んでいると、Dataverse Functionsはトランザクションとして機能するらしいので、実験してみた。
例えばこんな感じでChildテーブルとParentテーブルにレコードを追加するだけの関数を作成。
※なぜPatchを使わないのかは後述。

これを呼び出すと、無事成功する。


では、Childを作った後、0除算で無理やり関数をこけさせてみると、


Parentはもちろん、Childも作成されていない。

ということで、動作を見てみると、トランザクションとして機能していそう。
※ほんとにCUD全部にトランザクションが効くかは詳しい検証が必要。
Tips1:Power Apps(キャンバス)で同じ処理を動かすと
ちなみに同じこと(途中でエラー)をキャンバスで実行すると、

なんと、Parentのレコード追加(エラー後の追加処理)が成功してしまう。これはこれで詳しい検証が必要そう。

Tips2:Patchでレコードを追加しようとすると関数の保存ができない
現時点でFunctionsに「Patchによるデータの追加」を入れると、保存されない問題が発生する。
そのため、データを追加する場合はCollect関数を使用すると必要がある。
※Defaults関数はFunctionsで非対応のため、Patchの第2引数を指定することもできない。
※Patchでのレコードの「更新」は可能

An unexpected error occurred while updating Function: Dependency check failed
一括更新の検証(キャンバス側 で呼ぶのと、Functions側でやるのと)
最後は「処理速度」の比較。
以下の記事に書いた通り、キャンバスアプリからデータの一括更新を行う場合は、Patchを使うのが早かった。
Functionsからやる場合はPatchで一括更新自体が書きにくい(UIないし、UpdateIfも安定して動かないし)ので、ForAllで回すことになると思うんだけど、

なんとPatchをループで500回実行しても13秒。

With({records:Sample500},
ForAll(records As record,
Patch(Sample500 , record, {str:"a"});
)
);これはクライアントからのリクエストが1回で済んで、通信のオーバーヘッドが少ないため。
ループで細かく制御しながら大量のデータを更新する場合は、Functions側に持たせるのがよさそう。
まとめ
Dataverse Functionsはまだプレビューだからいろいろ制限あるけど、今後使う機会が増えていきそうな便利な機能だった。
公式:


コメント