エラー処理
注
この記事で説明する動作は、設定 > 近日公開の機能 > プレビューを通じて数式レベルのエラー管理プレビュー機能がオンになっている場合にのみ使用できます。 詳細情報: 有効にする機能を制御する
エラーは発生するものです。 ネットワークはダウンするものであり、ストレージがいっぱいになることも、予期しない値が入力されることもあります。 潜在的な問題に直面した場合でも、ロジックが適切に機能し続けることが重要です。
既定では、エラーはアプリの数式を通過し、アプリのエンド ユーザーに報告されます。 このようにして、エンド ユーザーには予期しない状況が発生したことがわかるので、別の入力を使用して問題を自分で修正したり、アプリの所有者に問題を報告したりできます。
アプリ開発者は、アプリのエラーを制御できます。
- エラーの検出と処理。 エラーが発生する可能性がある場合は、エラー条件を検出して操作を再試行するようにアプリの数式を記述できます。 エンド ユーザーはエラーが発生したことを心配する必要はありません。作成者がその可能性を考慮しているからです。 これは、数式の中で IfError、IsError、IsErrorOrBlank 関数を使用して行われます。
- エラーの報告。 エラーが発生した数式でエラーが処理されない場合、エラーは App.OnError ハンドラーにバブルアップされます。 ここでは、エラーは既に発生しており、数式計算の一部となっているため、エラーを置き換えることはできません。 しかし、App.OnError を使用して、エラー報告を一斉に抑制するなど、エラーがエンド ユーザーに報告される方法を制御できます。 App.OnError は、アプリ全体のエラー レポート用の共通チョーク ポイントする も提供します。
- エラーの作成と再スロー。 最後に、アプリ固有の条件であるエラー条件を独自のロジックで検出できます。 カスタム エラーを作成するには、Error 関数を使用します。 IfError や App.OnError 内で調べた後で、Error 関数を使用してエラーを再スローすることもできます。
開始する
簡単な例から始めましょう。
- Power Apps キャンバス アプリで新しい画面を作成します。
- TextInput コントロールを挿入します。 既定では、TextInput1 という名前になります。
- Label コントロールを挿入します。
- Label コントロールの Text プロパティを以下の数式に設定します
1/Value( TextInput1.Text )
TextInput コントロールの既定のテキストは "Text input"
であり、数値に変換できないため、エラーが発生します。 既定では、これは問題ありません。エンド ユーザーは、アプリで何かが期待どおりに機能していないという通知を受け取ります。
明らかに、ユーザーがこのアプリを起動するたびにエラーが発生することは望ましくありません。 おそらく、"Text input"
はテキスト入力ボックスに対して正しい既定値ではありません。 これを解決するには、TextInput コントロールの Default プロパティを次のように変更します。
Blank()
別のエラーが発生しました。 空白を含む数学演算 (除算など) は、空白値を強制的にゼロにします。 そして、それが 0 による除算エラーを引き起こしています。 これを修正するには、このアプリのこの状況に適した動作を決定する必要があります。 テキスト入力が空白のときには空白を表示することが答えの可能性があります。 IfError 関数で数式をラップすることで、これを実現できます。
IfError( 1/Value( TextInput1.Text ), Blank() )
これで、エラーは有効な値に置き換えられ、エラー バナーは表示されなくなりました。 しかし、過剰に反応する可能性があり、使用した IfError は、"hello"
などの不適切な値の入力を含むすべてのエラーをカバーします。 これに対処するには、0 による除算のケースのみを処理し、他のすべてのエラーを再スローするように IfError を調整します。
IfError( 1/Value( TextInput1.Text ),
If( FirstError.Kind = ErrorKind.Div0, Blank(), Error( FirstError ) ) )
それでは、アプリを実行して、いくつかの異なる値を試してみましょう。
アプリの起動時など、値がない場合は、既定値が空白であるため回答は表示されませんが、IfError によって 0 による除算エラーが置き換えられるため、エラーは表示されません。
「4」を入力すると、期待される結果 (0.25) が得られます。
また、hello
のように不正な内容を入力すると、エラー バナーが表示されます。
これは簡単な紹介例です。 エラー処理は、アプリのニーズに応じてさまざまな方法で実行できます。
- エラー バナーの代わりに、数式を使用してラベル コントロールに "#Error" を表示することもできます。 IfError の最初の引数と互換性のある置換の型を維持するには、Text 関数を使用して数値の結果をテキスト文字列に明示的に変換する必要があります。
IfError( Text( 1/Value( TextInput1.Text ) ), If( FirstError.Kind = ErrorKind.Div0, Blank(), "#Error" )
- この特定のインスタンスを IfError でラップする代わりに、一元化された App.OnError ハンドラーを作成できます。 エラーは既に発生しており、App.OnError は報告を制御するためにのみ提供されているため、表示されている文字列を "#Error" に置き換えることはできません。
If( FirstError.Kind <> ErrorKind.Div0, Error( FirstError ) )
エラーの伝播
エラーは、Excel の場合と同じように数式を通過します。 たとえば、Excel では、セル A1
に数式 =1/0
がある場合、A1 にはエラー値 #DIV0!
が表示されます。
セル A2
が =A1*2
などの数式で A1
を参照する場合、エラーはその数式にも伝播されます。
エラーは、計算されるはずだった値を置き換えます。 ゼル A2
の乗算の結果はなく、A1
の除算によるエラーのみがあります。
Power Fx は同じように動作します。 一般に、エラーが関数または演算子に引数として渡された場合、演算は行われず、演算の結果として入力エラーが流れます。 たとえば、Mid( Text( 1/0 ), 1, 1 )
では、最も内側のエラーが Text 関数と Mid 関数を通過するため、0 による除算エラーが返されます。
通常、エラーは Power Apps コントロール プロパティを通過しません。 最初のラベルの Text
プロパティがエラー状態である場合に表示するコントロールを追加して、前の例を拡張しましょう。
システムはすべてのコントロール プロパティへの入力でエラーを確認するため、エラーがコントロールを通じて伝播されないことに問題はありません。 エラーは失われません。
ほとんどの関数と演算子は "エラー イン、エラー アウト" の規則に従いますが、いくつかの例外があります。 関数 IsError、IsErrorOrBlank、IfError はエラーを処理するように設計されているため、エラーを渡されてもエラーを返さない場合があります。
エラーの確認
エラーは、その値が使用されるまで確認されません。
その結果、If 関数と Select 関数も、エラーを渡されてもエラーを返さない場合があります。 数式 If( false, 1/0, 3 )
を考えてみましょう。 この数式には 0 による除算エラーがありますが、false
が原因で If
はその分岐をとらないため、Power Fx と Power Apps はエラーを報告しません
エラーのある Set 関数を使用しても、エラーが変数に挿入された時点ではエラーは報告されません。 たとえば Power Apps で、0 による除算エラーを変数 x
に挿入する App.OnStart の数式を次に示します。
x
が参照されていないため、エラーは報告されません。 ただし、ラベル コントロールを追加し、その Text プロパティを x
に設定した瞬間、エラーが表示されます。
IfError、IsError、IsErrorOrBlank 関数を使用して、数式内のエラーを確認できます。 これらの関数を使用すると、別の値を返すこと、別のアクションを実行すること、またはエラーを確認して報告する前にエラーを修正することができます。
エラーの報告
エラーが確認されたら、次のステップはエンド ユーザーにエラーを報告することです。
Excel とは異なり、エラー結果を表示する便利な場所が常にあるとは限りません。数式の結果によってコントロールの X 座標や Y 座標などのプロパティが駆動される場合がありますが、これにはテキストを表示する便利な場所がないためです。 各 Power Fx ホストは、エラーが最終的にエンド ユーザーにどのように表示されるかと、作成者がこのプロセスをどの程度制御できるかを制御します。 Power Apps ではエラー バナーが表示され、App.OnError を使用してエラーの報告方法が制御されます。
App.OnError は、IfError でできるのと同じ方法ではエラーを置換できないことに注意してください。 App.OnError が実行された時点で、エラーは既に発生しており、結果は他の数式を通じて伝播されています。 App.OnError は、エラーがエンド ユーザーに報告される方法のみを制御し、必要に応じてメーカーがエラーをログに記録するためのフックを提供します。
スコープ変数 FirstError と AllErrors は、1 つまたは複数のエラーに関するコンテキスト情報を提供します。 これにより、エラーの種類、エラーの発生場所、エラーが確認された場所に関する情報が提供されます。
エラー後の停止
動作の数式では、アクションの実行、データベースの変更、状態の変更がサポートされます。 これらの数式では、;
チェーン演算子 (ロケールによっては ;;
) を使用して、複数のアクションを順番に実行できます。
この場合、たとえばグリッド コントロールは T
テーブルの内容を示しています。 ボタンを選択するたびに、2 つの Patch 呼び出しによってこのテーブルの状態が変更されます。
連鎖した動作の数式では、アクションは最初のエラーの後も停止しません。 最初の Patch 呼び出しで無効なインデックス番号を渡すように例を変更してみましょう。 2 番目の Patch は、この前のエラーにもかかわらず続行されます。 最初のエラーはエンド ユーザーに報告され、Studio のコントロールにエラーとして表示されます。
IfError を使用すると、エラー発生後に実行を停止できます。 If 関数と同様に、この関数の 3 番目の引数は、エラーがない場合にのみ実行するアクションの配置場所を指定します。
ForAll の反復のいずれかでエラーが発生した場合、残りの反復は停止しません。 ForAll は各反復を独立して実行するように設計されており、並列実行が可能です。 ForAll が完了すると、(IfError または App.OnError で AllErrors を調べることにより) 発生したすべてのエラーを含むエラーが返されます。
たとえば、次の式では、ForAll は 2 つのエラー (0 の Value
に対する 0 による除算が 2 回) を返し、Collection
には 3 つのレコード ([1, 2, 3]
) が含まれます (Value
が 0 でない場合について)。
Clear( Collection );
ForAll( [1,0,2,0,3], If( 1/Value > 0, Collect( Collection, Value ) ) );
複数のエラーの操作
動作の数式では複数のアクションを実行できるので、複数のエラーが発生する可能性もあります。
既定では、最初のエラーがエンド ユーザーに報告されます。 この例では、両方の Patch 呼び出しが失敗し、2 番目の呼び出しでは 0 による除算エラーが発生します。 最初のエラー (インデックスに関するもの) だけがユーザーに表示されます。
IfError 関数と App.OnError は、AllErrors スコープ変数で発生したすべてのエラーにアクセスできます。 この場合、これをグローバル変数に設定して、発生した両方のエラーを調べることができます。 それらは、検出されたのと同じ順序でテーブルに表示されます。
動作の数式以外でも複数のエラーが返される可能性があります。 たとえば、更新するレコードのバッチで Patch 関数を使用すると、複数のエラー (失敗したレコードごとに 1 つずつ) が返される場合があります。
テーブルのエラー
前に見たように、エラーは変数に格納できます。 エラーは、テーブルなどのデータ構造にも含まれることがあります。 これは、1 つのレコードのエラーによってテーブル全体が無効にならないようにするために重要です。
たとえば、Power Apps の次のデータ テーブル コントロールについて考えてみます。
AddColumns の計算で、値の 1 つに 0 による除算エラーが発生しました。 その 1 つのレコードでは、Reciprocal 列にエラー値 (0 による除算) がありますが、他のレコードにはエラー値がなく、問題ありません。 IsError( Index( output, 2 ) )
falseを返し、 IsError( Index( output, 2 ).Value )
trueを返します。
テーブルのフィルター処理中にエラーが発生した場合、レコード全体がエラーになりますが、結果には返されるため、エンド ユーザーにはそこに何かがあり、問題があることがわかります。
この例を見てみましょう。 ここで、元のテーブルにはエラーがありませんが、Value が 0 に等しい場合は常に、フィルター処理によってエラーが発生します。
値 -5 と -3 は適切にフィルターで除外されます。値が 0 の場合、フィルターの処理でエラーになるため、レコードを結果に含める必要があるかどうかは不明です。 エンド ユーザーの透明性を最大化し、作成者のデバッグを支援するために、元のレコードの代わりにエラー レコードを含めます。 この場合、IsError( Index( output, 2 ) )
は true を返します。
データ ソース エラー
Patch、Collect、Remove、RemoveIf、Update、UpdateIf、SubmitForm など、データ ソース内のデータを変更する関数は、2 つの方法でエラーを報告します。
- これらの各関数は、演算の結果としてエラー値を返します。 エラーは IsError で検出でき、通常どおり IfError と App.OnError で置換または抑制できます。
- 演算の後、Errors 関数は以前の演算のエラーも返します。 これは、状態変数でエラーをキャプチャする必要なしに、フォーム画面にエラー メッセージを表示するのに役立つ可能性があります。
たとえば、次の式は Collect からのエラーをチェックし、カスタム エラー メッセージを表示します。
IfError( Collect( Names, { Name: "duplicate" } ),
Notify( $"OOPS: { FirstError.Message }", NotificationType.Warning ) )
Errors 関数は、ランタイム操作中の過去のエラーに関する情報も返します。 状態変数でエラーをキャプチャする必要なしに、フォーム画面にエラーを表示するのに役立つ可能性があります。
エラーの再スロー
潜在的なエラーが予想されるものの、無視しても問題ない場合があります。 IfError と App.OnError の内部で、次の上位のハンドラーに渡す必要のあるエラーが検出された場合、Error( AllErrors )
を使用して再スローできます。
独自のエラーの作成
Error 関数を使用して独自のエラーを作成することもできます。
独自のエラーを作成する場合は、将来のシステム エラー値との潜在的な競合を避けるために、1000 より大きい値を使用することをお勧めします。
ErrorKind 列挙値
ErrorKind 列挙型 | 値 | 説明 |
---|---|---|
AnalysisError | 18 | システム エラー。 コンパイラ分析で問題が発生しました。 |
BadLanguageCode | 14 | 無効または認識されていない言語コードが使用されました。 |
BadRegex | 15 | 正規表現が無効です。 IsMatch、Match、または MatchAll 関数で使用される構文を確認してください。 |
Conflict | 6 | 更新中のレコードはソースで既に変更されており、競合を解決する必要があります。 一般的な解決策は、ローカルの変更を保存し、レコードを更新して、変更を再適用することです。 |
ConstraintViolated | 8 | レコードはサーバーでの制約チェックに合格しませんでした。 |
CreatePermission | 3 | ユーザーには、データ ソースのレコード作成のアクセス許可がありません。 たとえば、Collect 関数が呼び出されました。 |
DeletePermissions | 5 | ユーザーには、データ ソースのレコード削除のアクセス許可がありません。 たとえば、Remove 関数が呼び出されました。 |
Div0 | 13 | 0 による除算。 |
EditPermissions | 4 | ユーザーには、データ ソースのレコード作成のアクセス許可がありません。 たとえば、Patch 関数が呼び出されました。 |
GeneratedValue | 9 | サーバーによって自動的に計算されるフィールドの値が、誤ってサーバーに渡されました。 |
InvalidFunctionUsage | 16 | 関数の使用法が間違っています。 多くの場合、関数への引数の 1 つ以上が正しくないか、無効な方法で使用されています。 |
FileNotFound | 17 | SaveData ストレージが見つかりませんでした。 |
InsufficientMemory | 21 | 操作を行うのに十分なメモリまたはストレージがデバイスにありません。 |
InvalidArgument | 25 | 関数に無効な引数が渡されました。 |
Internal | 26 | システム エラー。 関数の 1 つに内部的な問題がありました。 |
MissingRequired | 2 | レコードの必須フィールドに値がありませんでした。 |
Network | 23 | ネットワーク通信に関する問題が発生しました。 |
None | 0 | システム エラー。 エラーはありません。 |
NotApplicable | 27 | 使用できる値はありません。 数値計算でゼロとして扱うことができる空白値と、その値が使用された場合に潜在的な問題としてフラグを立てる必要がある空白値を区別するのに役立ちます。 |
NotFound | 7 | レコードが見つかりませんでした。 たとえば、Patch 関数で変更されるレコードなどです。 |
NotSupported | 20 | このプレーヤーまたはデバイスでは操作がサポートされていません。 |
Numeric | 24 | 数値関数が不適切な方法で使用されました。 たとえば、-1 が指定された Sqrt などです。 |
QuotaExceeded | 22 | ストレージ クォータを超えています。 |
ReadOnlyValue | 10 | 列は読み取り専用であり、変更できません。 |
ReadPermission | 19 | ユーザーには、データ ソースのレコード読み取りのアクセス許可がありません。 |
Sync | 1 | データ ソースによってエラーが報告されました。 詳細については、Message 列を確認してください。 |
Unknown | 12 | エラーが発生しましたが、種類が不明です。 |
Validation | 11 | レコードは検証チェックに合格しませんでした。 |