#本記事の位置付けについて(2021/04/17更新)
これまで本記事シリーズで取り上げてきた以下3種類の列に対する委任警告
- ユーザー列
- 日付列
- 選択肢列
は、2020/06/19 時点ですべて委任可能となりました。
ご愛顧いただき、ありがとうございました。
本記事は、「へぇ~過去にそんなことがあったんだ。おつかれちゃんだったね」という視点でお読みいただければと思います。
なお、その後も残っていたユーザー列を「本人のみ」にフィルタリングする際によく利用する User() 関数の参照に関する委任警告も2021/04/17時点で委任可能となりましたので、本記事は「委任ってなぁに?」という方にお読みいただければと思います。
(Search関数、Sum関数、Filter関数内のLookUp関数利用など、委任警告自体はまだいくつか発生し得るので、委任について知っておくといつか役に立つかなと思います!)
#はじめに
SharePointのリストをデータソースとして利用すると、フィルタ処理で委任に関する警告にしばしば遭遇します。
その1では、私がこれまで作成したアプリ(※楽器アプリは除く)で必ずと言っていいほど委任問題に遭遇した以下のケース
ケース1:本人のだけ表示させたい(人のフィルタリング)
ケース2:今日のだけ表示させたい(日付のフィルタリング)
について、私が実際に行っている、委任問題のちょっと強引な回避方法について紹介します。
委任とは
PowerAppsでいう"委任"とは、簡単に言うとデータベースの検索処理をデータベース側に"お願い"することを言います。例えば、SharePointのリストから2017年分のデータを抽出する場合、以下の2通りの方法が考えられます。
A. SharePoint側で2017年分のデータを検索し、抽出したデータをPowerAppsが受け取る
B. SharePointからすべてのデータを受け取り、PowerApps側で検索し抽出する
PowerApps的には、Aの方が楽ですし、受け取るデータ量も少ないですよね。PowerAppsでは、このようにデータベース側に検索処理を"委任"することができます。
しかし、この検索内容が高度になると、データベース側では検索処理が行えず、データベース側にお願いできない(=委任できない)ケースが発生します。
これが、委任問題です。
委任できない場合、上記でいう「B. SharePointからすべてのデータを受け取り、PowerApps側で検索し抽出する」処理が必要になります。一旦PowerApps側で全データ(上限あり)を受け取り、PowerApps側で検索を行うため、通信データ量も処理も負荷がかかります。よって、委任できない検索を行う場合は、上記のデータ量を超えない程度の小規模なツールとしての利用に限定されるというデメリットがあります。
といっても、Common Data Serviceは有料でなかなか手が出せませんので、ここではSharePointを利用して委任問題を回避する方法について考えます。
紹介で利用するデータソース
ここでは、以下のSharePointリスト「テストリスト」について考えます。
※列の種類は、リストを新規作成した状態のままの状態です。
#ケース1:本人のだけ表示させたい(人のフィルタリング)
つまり、ユーザー列をフィルタ処理するケースです。
例えば残業申請を管理するアプリで、データソースには全社員の申請を登録し、アプリの画面は常に本人の申請のみを表示させる、などの用途が考えられます。
最初に本記事を執筆した2019年5月時点では、ユーザー列のフィルタ処理は委任できませんでしたが、2019年8月にようやく委任が可能になりました!!
…が、本人限定フィルタリングはやり方によっては別の委任警告に出会うため、ケース1の手順としてはその部分のみ残すことにしました。
ということで早速、ユーザー列"登録者"に対して本人のみに限定するフィルタ処理をGalleryに書いてみます。
ユーザー列のフィルタ処理はユーザーのEmail情報を利用するといいらしい(以下参照)。
https://powerusers.microsoft.com/t5/General-Discussion/Filtering-a-gallery-by-user/td-p/133093
Filter(テストリスト, 登録者.Email = User().Email)
委任警告さん、こんにちは。
ユーザー列を参照している左辺には波線が付いていませんので、ユーザー列の参照は委任できていることが分かります。
しかし、ここでは、本人のEmailを取得するための記載である右辺(User().Email)が委任できないようです。
(User情報を取得するのが高度な検索と認識される模様)
回避方法
1. フィルタ処理書き換え
そこで自社では、User().EmailをFilter関数内で直接利用するのではなく、あらかじめラベルにUser().Emailの値を格納しておくことにしました。
そしてラベルの値をフィルタ処理で利用します。
Filter(テストリスト, 登録者.Email = Label1.Text)
委任警告が消えました。めでたしめでたし。
これで、フィルタ処理の書き換えは完了です。
完成!
以上で、「ケース1:本人のだけ表示させたい」は完成です。
完成イメージ↓
※違いを分かりやすくするため、切り替えスイッチでフィルタ処理を切り替える処理を追加しています。
If(Toggle1.Value = true,
Filter(テストリスト, 登録者.Email = Label1.Text),
テストリスト
)
#【委任可能になったため不要】ケース2:今日のだけ表示させたい(日付のフィルタリング)
※日付のフィルタリングは2020/06/19時点で委任可能となりましたので、本委任警告対策は不要です。
ご興味ある方は、過去の産物として参考程度にお読みください。
つまり、日付列をフィルタ処理するケースです。
直近3日間のものだけ表示したい場合や、○月○日~△月△日の期間のものを表示したい、なんていう要件もあるかと思います。
ここではまず、デフォルトで用意されている日付列"登録日時"に対して、"今日のみ"に限定するフィルタ処理をGalleryに書いてみます。
Today()関数で今日の午前0:00が取れるので、"登録日時が今日の午前0:00以降"を示す式を記述します。
Filter(テストリスト, 登録日時 >= Today())
委任警告さん、こんばんは。
数式の左辺"登録日時"そのものに波線がついているので、どうやらSharePointでは日付列のフィルタ処理は委任できないようです。
回避方法
そこで自社では、日付列でフィルタ処理することを諦め、別途数値列を追加して日付の数字情報を格納し、その数値列でフィルタリングすることにしました。
なお、この数値列には
日付情報を"yyyymmddhhmm"という12桁の数字で格納する
ことにします。
(例:2019年5月1日12:34なら、201905011234)
1. 列の追加
SharePoint側で数値列"登録日時数値"を追加します。
2. フィルタ処理書き換え
フィルタ処理の左辺の列名を、先ほど追加した列名に書き換えます。
また、右辺の日付情報を"yyyymmddhhmm"の数値に変換する式に書き換えます。
変換は、Text()関数を用いてToday()の日付情報を一度上記のテキスト型に置き換え、それを数値型に変換する方法をとります。
Filter(テストリスト, 登録日時数値 >= Value(Text(Today(),"[$-ja]yyyymmddhhmm")))
…あれれ??また委任警告さん登場。
今度は数式の右辺(Value(Text(Today(),"[$-ja]yyyymmddhhmm")))が委任できないようです。
(日付情報を参照すること自体が高度なのか、色々変換する処理が高度なのか、とりあえず高度な検索と認識される模様)
そこで、ケース1でもやったように、右辺をFilter関数内で直接記述するのではなく、あらかじめラベルに右辺の値を格納しておくことにしました。
※ラベルは文字列型なので、数値への変換処理(Value())はフィルタ処理時に行う
このブログを書いているのは2019年5月11日なので、午前0:00の値(201905110000)がきちんと取れています。
そしてラベルの値をフィルタ処理で利用します。
Filter(テストリスト, 登録日時数値 >= Value(Label4.Text))
委任警告が消えました。めでたしめでたし。
これで、フィルタ処理の書き換えは完了です。
3. 追加した数値列へのデータ格納方法
上記の処理だけでは、アイテムを登録しても新しく追加した"登録日時数値"列にデータが入りませんので、フォーム側にも修正を加えます。
なお、日付列と一言で言っても、今回紹介した"登録日時"の他、同じくリスト生成時にデフォルトで用意されている"更新日時"、また"自分で追加した日付列"をフィルタしたい場合もあるかと思います。
追加した数値列へのデータ格納方法は、これら"登録日時"、"更新日時"、"自分で追加した日付列"の3種類の日付列で各々対処が異なるため、分けてご案内します。
3-1. 登録日時列の場合
まずはこれまで説明してきた、デフォルトで用意されている"登録日時列"のケースです。
まずは、追加した"登録日時数値"列のカードをフォームに追加します。
追加した"登録日時数値"カードのプロパティを変更するためにロックを解除し、カードのDefault値を以下に書き換えます。
If(EditForm1.Mode=New,
Value(Text(Now(),"[$-ja]yyyymmddhhmm")),
ThisItem.登録日時数値
)
フォーム コントロールは現在"新規"と"編集"のどちらなのかを状態として持っており、「フォームコントロール名.Mode」でその状態を取得することができます。
モードが New の場合(=新規登録時)は現在時刻を登録し、New でない場合(=編集時)は既に登録された"登録日時数値"をそのまま利用する、とすることで、登録時の時刻が登録される処理を実現しています。
ちなみに、フォームには"登録日時"のカードも追加できるので(下図参照)、Now なんて利用しないで"登録日時"のカードから情報を取れそうな気もしますよね。
でも、この"登録日時"や"更新日時"の列って、データが追加更新されて初めて SharePoint 側で値が書き換わるものなので、残念ながら新規追加時はまだ値が入っておらず、利用することができません。
[注意!]
ここでは処理を分かりやすく(?)するために上記の処理にしましたが、これだとフォームを"開いた時"の時刻が取れるため、フォームを開いてから登録するまでのタイムラグが発生します。
このタイムラグを許容できない場合は、例えば以下のように登録アイコン押下時に現在時刻を変数に格納し利用するなどの工夫が必要です。
① 登録アイコンの OnSelect 処理で現在時刻を変数 NowTime に格納↓
② ①の変数 NowTime を"登録日時数値"カードの Default 値に利用↓
If(EditForm1.Mode=New,
NowTime,
ThisItem.登録日時数値
)
この処理は、あまりスマートではない気がするので、もっと簡素な方法をご存知の方は是非教えてください!
3-2. 更新日時列の場合
続いて、デフォルトで用意されている"更新日時列"のケースです。
先程と同様に、予め SharePoint リストに追加しておいた "更新日時数値"列のカードをフォームに追加し、カードのプロパティのロックを解除し、カードの Default 値を以下に書き換えます。
Value(Text(Now(), "[$-ja]yyyymmddhhmm"))
"登録日時"よりシンプルで、ただ現在時刻を数値にして格納しているだけです。登録日時の時は「編集時に更新されないように」条件分岐しましたが、更新日時は都度最新日時を入れればよいだけなので、処理がシンプルになります。
ただし、こちらもフォームを"開いた時"の時刻が取れるため、フォームを開いてから登録するまでのタイムラグが発生します。実際の更新日時となるべく時間を合わせたい場合は、先程と同様に変数を利用するなど対処が必要です。
3-3. 自分で追加した日時列の場合
最後に、"自分で追加した日時列"のケースです。
予め以下の日時列およびその数値列を SharePoint リストに追加しておき 両列のカードをフォームに追加します。
続いて、数値列のプロパティのロックを解除し、カードの Default 値を以下に書き換えます。
Value(Text(自分で追加した日付列_DataCard1.Update, "[$-ja]yyyymmddhhmm"))
"登録日時"や"更新日時"と違い、自分で追加した日付列は日付コントロールを持っているため、そのコントロールの設定値を参照できるんですね。
この"自分で追加した日付列"カードは、登録時に ①日付、②時、③分 の3種類のコントロールの値を参照して日付型に変換して Update しているので、この Update の値をそのまま数値化して数値列に設定すればよい、ということになります。
完成!
以上で、「ケース2:今日のだけ表示させたい」は完成です。
完成イメージ↓
※違いを分かりやすくするため、切り替えスイッチでフィルタ処理を切り替える処理を追加しています。
#まとめ
ユーザー列と日付列をGalleryでフィルタ処理するために、ワンクッション置いたり、フィルタ処理専用の列を追加して対応したりするという、ちょっと強引な方法についてご紹介しました。
自社ではこの2つの方法を用いて、残業申請や問い合わせ対応案件管理など様々なアプリで人や日付のフィルタ処理を行っています。
本当はそんな列など増やさずにスマートに処理できればよいのですが…もっといい方法が見つかったらまたご紹介したいと思います。
ご参考になれば幸いです。
その2はこちら↓
PowerAppsで遭遇する5つの委任問題とちょっと強引な回避方法(SharePointリスト利用時)その2