はじめに
2/19(土)にこちらの勉強会に参加させていただきました。
Power Apps オンライン勉強会 ~つまづきポイント対策会~ - connpass
そのときにSPOリストでの委任問題について触れられていましたので、SPOリストでの委任問題の回避方法を纏めようと思います。
使用するデータ
今回の検証には以下のようなSPOリストを利用します。
アイテム数が2,500件もあるユーザ情報が格納されたリストです。
なお、ここで表示されているアイテムは自動生成されたテストデータであり、実在の人物とは一切関係がないのでご注意ください。
委任問題とは?
そもそも委任問題ってなんぞや?という方もおられると思いますので簡単に触れておきます。
SPOリストでの委任問題とは、Power AppsからSPOリストのデータを取得する際に複雑な式をSPOリストに対して渡した際に発生する警告です。
この警告が発生すると、数式が正常に動作せず期待通りの結果を得られない可能性があります。
より詳しく知りたい方は、公式docsの委任問題に関する記載を参照してください。
docs.microsoft.com
例えばSearch関数をSPOリストからアイテムを取得しようとした際などに発生します。
困りますね。。。
回避方法
データをコレクションに格納する
一番簡単なやり方?ですかね。
SPOリストのアイテムをコレクションに格納して、そのコレクションに対してフィルタなどを行う方法です。
// アイテムをコレクションに格納 ClearCollect( SPOData, 委任問題 )
// 特定のアイテムを取得 Search(SPOData, NameTxt.Text, "Name")
これで委任問題はでなくなりました。
ただ1点問題があります。
このやり方ですとデータ行の制限事項にもろに引っかかってしまいます。
まず、Power Appsでは「データ行の制限」という制限があります。
これは、
設定 > 全般 > データ行の制限
から確認することができ、デフォルトでは500件に設定されています。
これによりなにが起きるか?というと、例えば上でSPOリストの値をコレクションに格納しましたが、ここで取得できる件数に影響がでます。
CountRows(SPOData)
で実際に取得できた件数を確認してみましょう。
その結果としては以下のように500という数値が得られるかと思います。
次に「データ行の制限」を1000に変更して、コレクションを再取得してみましょう。
そうすると、今度は1,000件のアイテムが取得できたかと思います。
続いて、Search関数を設定しているわけですので、テキストボックスに値を入力してどのようなアイテムが取得できるのか確認してみましょう。
Search関数は完全一致ではなく、部分一致での検索が可能なので「菊」という値で部分一致検索をしてみます。
ちなみにExcelで元データに対してフィルタを行った場合は、20レコード取得することができました。
これをPower Appsで実行すると以下のような結果になります。
8件しか取得できてないですね。
これはそもそもPower Apps側でコレクションしたアイテムが1,000件しかなく、そのアイテムに対してフィルタ処理を行っているので結果に差異が生まれてしまっているのです。
つまり取得できなかった1,500件のアイテムが完全に抜け落ちてしまっている。ということになります。
では、「データ行の制限」の値を9999999とかに設定すれば、実質制限なしでできるのでは?と考えてしまうかもしれませんが、そう甘くはありません。
ここに設定できる数は2,000までです。
なので今回の検証のような2,500件ものアイテムがあるようなリストですと、正確なアイテム操作ができないのです。
また、Power Appsにデータを一度すべて持ってしまいますので、スペックの低いPCやネットワークが弱い環境で実施すると、アプリの性能に影響が出てしまうので注意が必要です。
纏めると、コレクション格納により委任問題を回避する際は、
- データ行の制限に気を付ける
- アプリの性能が落ちてしまう可能性があることに留意する
という問題に注意する必要があります。
With関数を利用する
次に試すのはWith関数を利用する方法です。
Docsの引用になりますが、With関数を使用すると、自己完結型で理解しやすく、宣言式のコンテキストで使用できるため、コンテキスト変数やグローバル変数よりも使用が推奨されているようです。
フィルタを行う式には以下のように記載します。
With( {tmpData:委任問題}, Search(tmpData, NameTxt.Text, "Name") )
次に先ほどと同様にこの式で「菊」という文字でフィルタしてみます。
(データ行の制限は先ほど最後に試した1,000で行っています。今後も1,000で実施します。)
その結果として、先ほどと同じ8件のデータを取得することができました。
これは何故か?というとWith関数もコレクションした場合と同じで
- アイテムをPower Apps側に取得
- 「1」で取得したアイテムに対してフィルタ処理
という順序になるので、同様のデータ行の制限が課せられてしまうのです。
ただ、With関数はグルーバル変数やコンテキスト変数よりも推奨されているようですので、リストのアイテムを保持してもここでしか使わない。(他のところでの利用予定はない)という場合はWith関数を利用するようにしたほうがパフォーマンス面を考慮するとよいかもしれませんね。
* パフォーマンスの検証はしてないです。
ForAll関数を利用する
次に試すのはForAll関数を利用する方法です。
ForAll関数では、簡単にいいますと第一引数に設定したテーブルに対してループ処理のようなことを行うことができます。
以下のようにフィルタします。
Filter( ForAll( 委任問題, If( NameTxt.Text in ThisRecord.Name, ThisRecord ) ), // 条件に合致していないレコードはBlankなのでIsBlank関数で弾く !IsBlank(ThisRecord) )
こちらもこれまで同様、ForAllの第一引数でまずはアイテムを取得してその後その取得したアイテムに対して処理をする。
という流れになるので、データ行の制限に引っかかってしまいます。
AddColumns関数を利用する
次はAddColumns関数を利用する方法です。
やり方としては、表示 / 非表示 を判断する列を追加してフィルタを行う方法です。
式にすると以下のようになります。
Filter( AddColumns( 委任問題, "isView", NameTxt.Text in Name ), isView )
こちらもまずAddColumnsで取得できる件数がデータ行の制限に引っかかってしまいますので、厳密なフィルタ処理はできません。
おわりに
色々やり方まとめましたが、SPOリストの委任問題を解決する際はデータ行の制限にも気を付ける必要があることが分かってもらえたかと思います。
ただ、こんなにたくさんのデータ量を使用するなら素直にDataverseや他DBの利用を検討するようにしたほうが運用や開発面では楽になるかもしれません。
そこはプロジェクトの予算などと応相談ですね。