PowerAppsモデル駆動型JavaScript APIのツリー構造
PowerApps Model-Driven JavaScript API
Xrm (ルートオブジェクト)
├── FormContext (フォームコンテキスト)
| ├── Attributes (属性:データフィールド操作)
| | ├── getAttribute (メソッド: フィールドにアクセス)
| | | ├── getValue / setValue (メソッド: 値の取得・設定)
| | | | サンプル:
| | | | ```javascript
| | | | var fieldValue = formContext.getAttribute("fieldname").getValue();
| | | | formContext.getAttribute("fieldname").setValue("newValue");
| | | | ```
| | | | 説明: `fieldname` フィールドの現在の値を取得し、続けて新しい値 "newValue" を設定します。
| | | ├── getRequiredLevel / setRequiredLevel (メソッド: 必須設定)
| | | | サンプル:
| | | | ```javascript
| | | | formContext.getAttribute("fieldname").setRequiredLevel("required");
| | | | ```
| | | | 説明: `fieldname` フィールドを必須項目として設定します。
| | | ├── addOnChange / removeOnChange (メソッド: イベントハンドラ追加・削除)
| | | | サンプル:
| | | | ```javascript
| | | | formContext.getAttribute("fieldname").addOnChange(function() {
| | | | console.log("Value changed!");
| | | | });
| | | | ```
| | | | 説明: `fieldname` フィールドの値が変更された際に「Value changed!」というメッセージをコンソールに出力する処理を追加します。
| | | ├── isDirty (プロパティ: フィールドが編集されているかの確認)
| | | | サンプル:
| | | | ```javascript
| | | | var isFieldDirty = formContext.getAttribute("fieldname").isDirty;
| | | | if (isFieldDirty) {
| | | | console.log("Field has unsaved changes.");
| | | | }
| | | | ```
| | | | 説明: `fieldname` フィールドに未保存の変更がある場合、「Field has unsaved changes.」というメッセージをコンソールに表示します。
| ├── Controls (UIコントロール)
| | ├── getControl (メソッド: コントロールにアクセス)
| | | ├── setVisible / getVisible (メソッド: 表示・非表示設定)
| | | | サンプル:
| | | | ```javascript
| | | | formContext.getControl("controlname").setVisible(true);
| | | | ```
| | | | 説明: `controlname` コントロールを表示させます。
| | | ├── setDisabled / getDisabled (メソッド: 有効・無効設定)
| | | | サンプル:
| | | | ```javascript
| | | | formContext.getControl("controlname").setDisabled(false);
| | | | ```
| | | | 説明: `controlname` コントロールを有効にします(ユーザーが編集可能になります)。
| | | ├── setFocus (メソッド: フォーカス設定)
| | | | サンプル:
| | | | ```javascript
| | | | formContext.getControl("controlname").setFocus();
| | | | ```
| | | | 説明: `controlname` コントロールにフォーカスを設定し、ユーザーがすぐに入力できるようにします。
| ├── save (メソッド: フォームのデータ保存)
| | サンプル:
| | ```javascript
| | formContext.data.save().then(
| | function success() { console.log("Data saved"); },
| | function(error) { console.error(error.message); }
| | );
| | ```
| | 説明: フォームの現在のデータを保存し、成功した場合は「Data saved」を、エラーが発生した場合はエラーメッセージをコンソールに出力します。
| ├── refresh (メソッド: データの再読み込み)
| | サンプル:
| | ```javascript
| | formContext.data.refresh().then(
| | function success() { console.log("Data refreshed"); },
| | function(error) { console.error(error.message); }
| | );
| | ```
| | 説明: フォームデータをサーバーから再読み込みし、成功した場合は「Data refreshed」を、エラーが発生した場合はエラーメッセージをコンソールに出力します。
| ├── setFormNotification / clearFormNotification (メソッド: フォームレベルの通知設定・解除)
| | サンプル:
| | ```javascript
| | formContext.ui.setFormNotification("This is a form-level notification", "INFO", "uniqueID");
| | formContext.ui.clearFormNotification("uniqueID");
| | ```
| | 説明: フォーム全体に情報レベルの通知を表示し、その後に `uniqueID` を指定して通知を解除します。
|
└── WebApi (データAPI)
├── retrieveRecord (メソッド: データの取得)
| サンプル:
| ```javascript
| Xrm.WebApi.retrieveRecord("account", "account-id", "?$select=name").then(
| function success(result) { console.log(result.name); },
| function(error) { console.error(error.message); }
| );
| ```
| 説明: `account` エンティティの特定のIDに対応するレコードを取得し、`name` フィールドの値をコンソールに出力します。
├── createRecord (メソッド: データの作成)
| サンプル:
| ```javascript
| var accountData = { name: "New Account" };
| Xrm.WebApi.createRecord("account", accountData).then(
| function success(result) { console.log("ID: " + result.id); },
| function(error) { console.error(error.message); }
| );
| ```
| 説明: 新しい `account` レコードを作成し、作成されたレコードのIDをコンソールに出力します。
├── updateRecord (メソッド: データの更新)
| サンプル:
| ```javascript
| var accountUpdate = { name: "Updated Name" };
| Xrm.WebApi.updateRecord("account", "account-id", accountUpdate).then(
| function success() { console.log("Updated"); },
| function(error) { console.error(error.message); }
| );
| ```
| 説明: `account-id` に対応する `account` レコードを更新し、更新が成功した場合は「Updated」を出力します。
├── deleteRecord (メソッド: データの削除)
| サンプル:
| ```javascript
| Xrm.WebApi.deleteRecord("account", "account-id").then(
| function success() { console.log("Deleted"); },
| function(error) { console.error(error.message); }
| );
| ```
| 説明: `account-id` に対応する `account` レコードを削除し、削除が成功した場合は「Deleted」を出力します。
プラグインの種類とツリー構造
PowerAppsモデル駆動型アプリケーションで利用できるプラグインの種類をツリー構造で整理
PowerApps Model-Driven Plugins
├── Pre-Validation (事前検証プラグイン)
| ├── 説明: エンティティ操作の前にビジネスルールやデータの整合性を検証するために使用されます。
| ├── 主な用途:
| | - カスタムバリデーションの実施
| | - 他のエンティティや関連データの状態を確認
| ├── 実行タイミング: トランザクションの開始前(データベースにアクセスする前)
| └── サンプル処理:
| - サンプル: 新しいアカウントを作成する前に、名前が重複していないか検証
| ```csharp
| if (CheckDuplicateName(accountName)) {
| throw new InvalidPluginExecutionException("Account name already exists.");
| }
| ```
├── Pre-Operation (事前処理プラグイン)
| ├── 説明: データがデータベースに保存される直前に処理を実行するためのプラグインです。
| ├── 主な用途:
| | - データの初期化や加工
| | - 自動で値を設定、またはデータを標準化
| ├── 実行タイミング: データベース更新の直前
| └── サンプル処理:
| - サンプル: アカウントの作成時に「作成日」フィールドを自動設定
| ```csharp
| entity["createdOn"] = DateTime.UtcNow;
| ```
├── Post-Operation (事後処理プラグイン)
| ├── 説明: データが保存された後に追加の処理を行うためのプラグインです。
| ├── 主な用途:
| | - 他のエンティティへのデータ転送や連携
| | - ワークフローや通知のトリガー
| ├── 実行タイミング: データベース更新後(トランザクションの後)
| └── サンプル処理:
| - サンプル: 新規アカウント作成後に、関連する連絡先エンティティを自動作成
| ```csharp
| var contact = new Entity("contact");
| contact["parentcustomerid"] = new EntityReference("account", accountId);
| service.Create(contact);
| ```
├── Asynchronous Plugins (非同期プラグイン)
| ├── 説明: メインの操作後に非同期で実行されるプラグインです。ユーザーの操作に影響を与えないために使用されます。
| ├── 主な用途:
| | - 時間のかかる処理や外部サービスとの連携
| | - 定期的なデータ更新や通知の送信
| ├── 実行タイミング: メインの操作終了後、システムリソースが空いているタイミング
| └── サンプル処理:
| - サンプル: アカウントの更新時に、外部APIを呼び出して顧客データを更新
| ```csharp
| await CallExternalService(accountId);
| ```
├── Synchronous Plugins (同期プラグイン)
| ├── 説明: 操作が完了する前に、トランザクション内で即時に実行されるプラグインです。
| ├── 主な用途:
| | - 即座にデータ検証や変換を行いたい場合
| | - システム内で一貫性を保つためのチェック
| ├── 実行タイミング: メイン操作中にリアルタイムで実行
| └── サンプル処理:
| - サンプル: 新規注文の保存時に在庫数をチェックし、不足している場合エラーメッセージを表示
| ```csharp
| if (!CheckInventory(productId, quantity)) {
| throw new InvalidPluginExecutionException("Insufficient inventory.");
| }
| ```
└── Image Plugins (イメージプラグイン)
├── 説明: プラグインで操作する前後のエンティティデータの「スナップショット」を取得し、変更内容を追跡するために使用します。
├── 主な用途:
| - 更新前と更新後のデータ比較
| - ログの記録や監査目的
├── 実行タイミング: 操作前(Pre-Image)または操作後(Post-Image)で選択可能
└── サンプル処理:
- サンプル: 更新前と更新後の住所データを比較して変更があればログに記録
```csharp
if (preImage["address1_line1"] != postImage["address1_line1"]) {
LogAddressChange(preImage, postImage);
}
```
のクライアントスクリプトの一連の処理の流れ
Power Apps モデル駆動型アプリでのクライアントスクリプトの一連の処理の流れ(詳細版)
Power Apps のモデル駆動型アプリでクライアントスクリプトを使用する際の詳しい処理の流れを解説します。これにより、アプリケーションの動作を深く理解し、効率的な開発を行うことができます。
目次
- ユーザー操作
- クライアントスクリプトの実行
- データの前処理とパッケージング
- データの送信(Web APIへのリクエスト)
- ネットワーク通信とセキュリティ
- Web APIによるデータ受信と処理
- サーバーからの応答(Web APIのレスポンス)
- 応答の受信とクライアントでの処理
- ユーザーへのフィードバック
- 後続処理
- 追加のポイントや考慮事項
- 全体のフロー図(詳細版)
- 補足情報
1. ユーザー操作
ユーザーがモデル駆動型アプリのフォームにデータを入力し、「保存」ボタンをクリックします。
2. クライアントスクリプトの実行
フォームのイベント(例:onSave
、onLoad
、onChange
)に紐づけられたJavaScript関数が実行されます。
- 処理内容:
- フィールドの値の取得と設定
- 入力データの検証(必須項目のチェック、データ形式の確認など)
- ビジネスルールの適用(特定の条件下でフィールドを読み取り専用にするなど)
- 非同期処理の実行(他のデータの取得や外部サービスとの通信)
- 保存のキャンセルやエラーメッセージの表示が可能
サンプルコード:
function onSave(executionContext) { var formContext = executionContext.getFormContext(); var requiredField = formContext.getAttribute("new_requiredfield").getValue(); if (!requiredField) { formContext.ui.setFormNotification("必須フィールドが入力されていません。", "ERROR", "1"); executionContext.getEventArgs().preventDefault(); } }
3. データの前処理とパッケージング
4. データの送信(Web APIへのリクエスト)
- HTTPリクエストを作成
- エンドポイントURL:
- 新規作成:
https://<your_org>.crm.dynamics.com/api/data/v9.2/<entitysetname>
- 更新:
https://<your_org>.crm.dynamics.com/api/data/v9.2/<entitysetname>(<recordId>)
- 新規作成:
サンプルリクエスト:
POST https://your_org.crm.dynamics.com/api/data/v9.2/accounts HTTP/1.1 Authorization: Bearer eyJ0eXAiOiJKV1QiL... Content-Type: application/json; charset=utf-8 { "name": "新しい取引先企業", "telephone1": "03-1234-5678" }
5. ネットワーク通信とセキュリティ
6. Web APIによるデータ受信と処理
- リクエストを受信し、ヘッダーとボディを解析
- 認証情報の検証
- トークンの有効期限やスコープの確認
- データの検証
- 必須フィールドのチェック
- データ型やフォーマットの確認
- 業務ルールの適用
- データベース操作
7. サーバーからの応答(Web APIのレスポンス)
- HTTPステータスコードの設定
- 成功:
200 OK
、201 Created
、204 No Content
- クライアントエラー:
400 Bad Request
、401 Unauthorized
、403 Forbidden
、404 Not Found
- サーバーエラー:
500 Internal Server Error
- 成功:
- レスポンスヘッダーの設定
OData-Version
、Content-Type
など
- レスポンスボディの生成
サンプルレスポンス:
HTTP/1.1 201 Created OData-Version: 4.0 Content-Type: application/json; charset=utf-8 Location: https://your_org.crm.dynamics.com/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) { "@odata.context": "https://your_org.crm.dynamics.com/api/data/v9.2/$metadata#accounts/$entity", "accountid": "00000000-0000-0000-0000-000000000001", "name": "新しい取引先企業", "telephone1": "03-1234-5678" }
8. 応答の受信とクライアントでの処理
- クライアントがHTTPレスポンスを受信
- ステータスコードとレスポンスボディの解析
- 非同期処理の場合、Promiseやコールバックで結果を処理
- エラーの場合は詳細情報を取得し、適切な対処を実施
9. ユーザーへのフィードバック
- 成功時:
- 保存完了のメッセージを表示
- フォームのリセットや別ページへのナビゲーション
- エラー時:
- エラーメッセージの表示(具体的な原因を含める)
- 問題のあるフィールドをハイライト
- 再入力や再試行を促す
10. 後続処理
- 必要に応じて追加のクライアントスクリプトを実行
- 関連レコードの更新
- 外部サービスへの通知
- ワークフローやフローのトリガー
- データの保存後に自動的に実行されるプロセス
11. 追加のポイントや考慮事項
非同期処理の扱い
- クライアントスクリプトでWeb APIを直接呼び出す場合、非同期処理になるため、
Promise
やasync/await
を適切に使用する必要があります。 - フォームの保存処理と同期させたい場合、
Xrm.Utility.promiseEvent
を使用して保存プロセスを制御できます。
エラーハンドリングの強化
- エラー発生時にユーザーが具体的な対処方法を理解できるよう、エラーメッセージを工夫します。
- ネットワークエラーやタイムアウトへの対応も考慮します。
パフォーマンスの最適化
- 不要なフィールドやデータを送信しないようにします。
- クライアントスクリプト内での処理を最小限に抑え、レスポンスを向上させます。
セキュリティの強化
- クライアントサイドで機密情報を扱わないように注意します。
- サーバーサイドでのデータ検証を徹底し、不正なデータの登録を防止します。
デバッグとロギング
プラグインやカスタムワークフローの利用
- 複雑なビジネスロジックやデータ処理が必要な場合、C#でプラグインやカスタムワークフローを作成し、Dataverseに登録します。
- プラグインの登録ステージ(プリバリデーション、プリ操作、ポスト操作)を適切に選択します。
12. 全体のフロー図(詳細版)
以下は、一連の処理の全体的な流れをまとめたフロー図です。
- ユーザー操作
- クライアントスクリプトの実行
- データの前処理とパッケージング
- データの送信(Web APIへのリクエスト)
- ネットワーク通信とセキュリティ
- Web APIによるデータ受信と処理
- サーバーからの応答(Web APIのレスポンス)
- 応答の受信とクライアントでの処理
- ユーザーへのフィードバック
- 後続処理
13. 補足情報
DataverseのWeb APIの活用
- 外部アプリケーションやサービスからもWeb APIを利用してDataverseのデータにアクセスできます。
- Azure Functionsやロジックアプリと組み合わせて、拡張性の高いソリューションを構築できます。
認証と認可の詳細
- Azure Active Directory(Azure AD)を使用した認証が行われます。
- アプリケーション登録や権限の設定が必要な場合があります。
エンティティとフィールドのメタデータ
環境の違いへの対応
- 開発環境、テスト環境、本番環境でエンドポイントや認証情報が異なる場合があります。
- 環境ごとの設定を管理しやすくする工夫が必要です。
まとめ
Power Apps モデル駆動型アプリでクライアントスクリプトを使用する際の一連の処理の流れを詳細に説明しました。クライアントスクリプトはユーザーエクスペリエンスを向上させ、ビジネス要件に合わせた柔軟なカスタマイズを可能にします。正しい理解と実装により、効率的で効果的なアプリケーション開発を実現しましょう。
参考資料
モデル駆動型アプリで「タブの表示制御」を活用しよう
PowerAppsモデル駆動型アプリで「タブの表示制御」を活用しよう
目次
概要
本記事では、PowerAppsモデル駆動型アプリでの「タブの表示制御」を活用する方法について解説します。 タブ表示を役職や権限に応じて制御することで、アプリがより安全で、ユーザーにとって分かりやすい構成になります。 具体的な例として、ユーザーの役職が「マネージャー」の場合のみ、特定のタブを表示する方法を紹介します。
PowerAppsでのタブ表示制御の重要性
PowerAppsでは、表示する内容をユーザーの役職や権限に応じて制御することができます。 特定の役職のみに機密データを表示したり、一般社員には関係のない管理情報を非表示にすることで、操作性やセキュリティを向上させることが可能です。
タブ表示制御のメリット
- アクセス制御: 特定の役職や権限のユーザーのみがデータにアクセス可能になり、セキュリティが向上します。
- UIの簡素化: 必要な情報だけを表示することで、操作しやすく、画面がシンプルになります。
具体例:役職に応じたタブの表示
ここでは、ユーザーが「マネージャー」役職を持っている場合にのみ「manager_tab」を表示する例を紹介します。
データ仕様
- テーブル名:
userRoles
- 列名とデータ型:
roleName
: テキスト(役職名)
実装例とコードの比較
タブ表示制御なしの場合
function onFormLoad(executionContext) {
var formContext = executionContext.getFormContext();
// すべてのユーザーに「manager_tab」を表示
formContext.ui.tabs.get("manager_tab").setVisible(true);
}
問題点: このコードでは、ユーザーの役職に関係なくすべてのユーザーに「manager_tab」が表示されてしまい、情報が制御されていません。
役職に応じたタブの表示制御(async/await
を使用)
async function onFormLoadWithRoleCheck(executionContext) {
var formContext = executionContext.getFormContext();
// ユーザーの役職情報を取得
const userRoles = Xrm.Utility.getGlobalContext().userSettings.roles;
const isManager = userRoles.some(role => role.name === "Manager");
// マネージャーのみ「manager_tab」を表示
formContext.ui.tabs.get("manager_tab").setVisible(isManager);
}
メリット: 非同期処理を使い、役職情報を取得して役職に応じてタブを表示することで、ユーザー体験が向上し、必要な情報だけが見られるようになります。
関連メソッドと構文
タブ表示制御に使用する主なメソッドと構文を解説します。
メソッド一覧
Xrm.Utility.getGlobalContext()
: PowerAppsで現在のユーザー情報や環境情報を取得するメソッドです。
使用例:const context = Xrm.Utility.getGlobalContext();
some
メソッド: 配列の中に条件を満たす要素があるかどうかを判定するメソッドです。
使用例:userRoles.some(role => role.name === "Manager");
これは、userRoles
配列の中に「Manager」という役職があるかを確認します。setVisible
: 特定のUI要素の表示/非表示を設定するメソッドです。
使用例:formContext.ui.tabs.get("manager_tab").setVisible(isManager);
ここで、isManager
がtrueであれば「manager_tab」を表示し、falseであれば非表示にします。
注意点: 非同期処理で`await`を使う場合、必ず`async`関数内でのみ使用できることに注意してください。
技術的な豆知識と制限事項
豆知識
- async/await: 非同期処理を同期的に見せる記法で、コードが読みやすくなります。
制限事項
- PowerAppsのタブ表示制御はクライアント側で行われるため、権限の制御は完全ではありません。セキュリティが特に重要な場合は、サーバー側での制御を検討する必要があります。
実践問題
問題: フォームロード時に「Manager」または「Admin」役職がある場合にのみ特定のタブを表示する関数onFormLoadWithExtendedRoleCheck
を実装してください。
- 条件: 役職情報を非同期で取得し、ManagerまたはAdminの役職がある場合にタブを表示する。
この記事では、PowerAppsモデル駆動型アプリでの「タブの表示制御」の活用について解説しました。タブの表示制御をうまく活用して、必要なユーザーだけがアクセスできるようにし、アプリのセキュリティと使いやすさを向上させましょう。
PowerAppsモデル駆動型アプリで「非同期データ取得」を活用しよう
PowerAppsモデル駆動型アプリで「非同期データ取得」を活用しよう
目次
概要
本記事では、PowerAppsモデル駆動型アプリにおける非同期データ取得とその利点について解説します。 非同期処理を活用することで、ユーザーがデータ取得中もスムーズに操作を続けられるようになり、アプリの使い勝手が向上します。 この記事では、顧客データの非同期取得を具体例として、処理の流れと実装方法について詳しく説明します。
PowerAppsでの非同期データ取得の重要性
PowerAppsでは、サーバーからデータを取得して表示するシーンが頻繁にあります。 もしデータ取得が同期処理で行われると、取得が完了するまでユーザーの操作が一時的に止まり、快適な操作が妨げられます。 非同期処理を利用することで、データ取得の完了を待たずに他の操作が可能になり、アプリの応答性が向上します。
非同期処理のメリット
- 応答性の向上: データ取得中も操作を続けられるため、ユーザーエクスペリエンスが向上します。
- 効率的なリソース利用: 複数のデータ取得を同時に行うことで、リソースを効率的に使用できます。
- エラーハンドリングが容易: 非同期処理では、エラー時の対応が簡素化され、安定性が向上します。
具体例:顧客データの非同期取得
ここでは、顧客データを非同期で取得し、ユーザーがデータ取得完了を待たずに操作を続けられる実装を紹介します。
データ仕様
- テーブル名:
contact
- 列名とデータ型:
fullname
: テキストemail
: メールアドレスphone
: 電話番号
実装例とコードの比較
非同期処理を使わない場合
function getContactDataSync() {
var contactId = "some-contact-id";
var result = Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname,email,phone");
console.log("顧客名:", result.fullname);
console.log("メールアドレス:", result.email);
console.log("電話番号:", result.phone);
}
問題点: このコードはデータ取得が完了するまで操作が止まってしまいます。同期処理では、ユーザーの待機時間が発生し、使い勝手が悪くなります。
非同期処理(async/await
を使用)を使ったコード
async function getContactDataAsync() {
var contactId = "some-contact-id";
try {
const result = await Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname,email,phone");
console.log("顧客名:", result.fullname);
console.log("メールアドレス:", result.email);
console.log("電話番号:", result.phone);
} catch (error) {
console.error("データ取得エラー:", error.message);
}
}
メリット: 非同期でデータ取得が行われ、操作がスムーズに行えるようになります。await
により、データ取得の完了を待ちながらも、他の操作が可能です。
関連メソッドと構文
非同期処理で利用する主なメソッドと構文について説明します。
メソッド一覧
Xrm.WebApi.retrieveRecord
: 指定したテーブルとIDでデータを取得します。
使用例:Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname,email,phone");
async/await
: 非同期関数と、その完了を待つためのキーワード。
注意点: await
はasync
関数内でのみ使用可能です。
技術的な豆知識と制限事項
豆知識
- async/await: 非同期処理を同期的に見せる記法で、コードが読みやすくなります。
制限事項
- 通信が不安定だとデータ取得が遅延する可能性があります。
コード全体の流れ
この記事で使われているコードは、PowerAppsモデル駆動型アプリで、**「顧客データを非同期で取得して表示する」**という内容です。同期と非同期の2つの方法を使って、データの取得がアプリの動作にどう影響するかを説明しています。では、それぞれのコードの流れを順を追って見ていきましょう。
同期処理の流れ:getContactDataSync()
まず、同期処理を使った例について説明します。この関数は、PowerAppsの「Xrm.WebApi.retrieveRecord」メソッドを使ってデータを取得しますが、処理の仕方に問題があります。
処理の流れ
-
関数が呼び出される
getContactDataSync()
関数は、データ取得が必要になったときに呼ばれます。ここで実行が開始されます。 -
変数
contactId
にデータIDを指定
顧客データを取得するためのID(例:"some-contact-id"
)がcontactId
に代入されます。このIDを使って、特定の顧客データをサーバーから引き出します。 -
Xrm.WebApi.retrieveRecord
メソッドでデータを取得Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname,email,phone");
を使ってサーバーからデータを取得します。ここで、「contact」テーブルから、contactId
で指定した顧客の「名前」「メールアドレス」「電話番号」が取り出されます。- ただし、同期的に動作するため、このデータ取得が完了するまで他の処理ができなくなります。
-
データの表示
データが取得できたら、それぞれのフィールド(「名前」「メールアドレス」「電話番号」)をコンソールに出力します。この処理が終わるまで、他の操作は止まったままです。
データの流れ
- まず
contactId
を通じて特定のデータが指定されます。 - 次に、
Xrm.WebApi.retrieveRecord
メソッドがデータベースからこのデータを取得し、結果がresult
に返されます。 - 最後に、取得したデータがコンソールに出力され、処理が終了します。
非同期処理の流れ:getContactDataAsync()
次に、非同期処理を使った方法を見ていきましょう。非同期処理を使うことで、データの取得が終わる前でも他の操作が可能になります。
処理の流れ
-
関数が呼び出される
getContactDataAsync()
関数が呼ばれると、この非同期処理が開始されます。最初に変数の設定や準備を行います。 -
変数
contactId
にデータIDを指定
同期処理と同じように、取得したいデータのID(例:"some-contact-id"
)を変数contactId
に代入します。 -
await
でデータ取得を待つ
次に、await Xrm.WebApi.retrieveRecord("contact", contactId, "?$select=fullname,email,phone");
と書かれた行に進みます。このawait
は、データの取得が終わるのを待つことを指示しています。await
の処理は、データ取得中も他の操作が可能であることを意味しています。つまり、このデータ取得が終わるまで他の処理を中断する必要がありません。
-
エラー処理
try-catch
ブロックでエラー処理も追加しています。データ取得がうまくいかなかった場合、catch
でエラーメッセージが表示されます。 -
データの表示
データが無事に取得できた場合、各フィールドの内容(「名前」「メールアドレス」「電話番号」)をコンソールに出力します。同期処理と異なり、この間にユーザーが他の操作を行っても問題がありません。
データの流れ
- 同期処理と同じく、
contactId
でデータが指定されます。 Xrm.WebApi.retrieveRecord
メソッドがサーバーにリクエストを送信し、データがresult
に返されます。- 結果のデータがコンソールに出力され、処理が終了します。
同期処理と非同期処理の違い
ここで、同期処理と非同期処理の違いを簡単にまとめます。
項目 | 同期処理 | 非同期処理 |
---|---|---|
処理中の操作 | 他の操作が止まる | 他の操作が可能 |
処理の待機 | 取得が終わるまで待機 | 処理中も他の作業が可能 |
ユーザー体験 | 操作が中断される | 操作がスムーズ |
子どもにもわかる例え話
非同期処理を、図書館で本を借りる例にたとえてみましょう。
- 同期処理の場合:本を借りるために図書館に行き、受付で自分の順番が来るまで待ちます。前の人がたくさんの本を借りていると、自分が本を借りられるまで時間がかかってしまいます。
- 非同期処理の場合:図書館に行って本を借りる手続きを始めますが、受付に「準備ができたら連絡してください」とお願いし、自分はほかのことをして待ちます。そうすれば、手続きが完了するまで、時間を無駄にしません。
コードの解説
最後に、コードの中で使われたメソッドについても詳しく説明します。
-
Xrm.WebApi.retrieveRecord
このメソッドは、特定のIDを持つレコードをデータベースから取得するために使います。取得したいテーブルの名前とID、そして取り出したいフィールド(例:fullname
,email
,phone
)を指定します。- 構文:
Xrm.WebApi.retrieveRecord("テーブル名", レコードID, "取得フィールド");
- 構文:
-
async/await
async
関数内で使えるawait
は、特定の非同期処理が終わるまで待機するよう指示するキーワードです。await
が使えるのは、必ずasync
関数内です。非同期処理が完了したら次の処理に進みます。 -
try-catch
ブロックtry-catch
は、エラー処理を行うための構文です。例えば、データ取得がうまくいかなかったとき、catch
内でエラー内容をログに表示させることができます。これにより、エラーが発生してもアプリ全体が停止するのを防ぎます。
まとめ
非同期処理を使うことで、データ取得中も他の操作が可能となり、アプリがスムーズに動作するようになります。このコードの理解を通して、PowerAppsモデル駆動型アプリの開発がより効果的に進むことでしょう。
実践問題
問題: 以下の条件を満たす関数getAccountData
を作成してください。
- 条件: 顧客データを非同期で取得し、取得したデータをコンソールに表示。
この記事では、PowerAppsモデル駆動型アプリでの非同期データ取得の活用について解説しました。非同期処理を理解して、アプリのパフォーマンスを向上させましょう。
ロールアップの使い方
ロールアップフィールドを使用して、関連データを集計する
- 概要: 請求先テーブルを使用して、ロールアップフィールドの作成と活用方法を学びます。
- 目的: 関連する子レコードのデータを親レコードで集計する方法を理解する。
- 例: 各請求先(顧客)の全請求書の合計金額を算出する。
■結果
子レコード
手順:
-
テーブルの確認と準備
-
ロールアップフィールドの作成
-
対象テーブル: 請求先(
account
) -
フィールドの追加:
- 表示名:
合計請求金額
- スキーマ名:
new_totalinvoiceamount
- データ型: ロールアップ(通貨)
- 表示名:
-
-
ロールアップフィールドの設定
-
ロールアップの定義:
- ソーステーブル: 請求書(
invoice
) - 関連フィールド:
顧客
(customerid
) - 集計関数:
合計
(Sum) - 対象フィールド: 請求書の
合計金額
(totalamount
)
- ソーステーブル: 請求書(
-
フィルターの設定(必要に応じて):
- 例: 請求書のステータスが
支払済み
のものだけを集計
- 例: 請求書のステータスが
-
-
フィールドの保存と公開
- ロールアップフィールドの設定を保存し、カスタマイズを公開する。
-
フォームへのフィールド追加
- フォーム: 請求先メインフォーム
- フィールド配置:
合計請求金額
(new_totalinvoiceamount
)をフォーム上にドラッグ&ドロップ。
-
動作確認
- 請求先レコードを開き、
合計請求金額
が正しく表示されていることを確認。 - 注意: ロールアップフィールドの値は即時更新されない場合があります。必要に応じてフィールド横の再計算ボタンを使用。
- 請求先レコードを開き、
データ型=通貨(計算)の例
実装例:フォーム上で入力値に基づいて他のフィールドを自動計算する
シナリオ:
「合計金額」と「消費税率」を入力すると、「税込金額」が自動計算される機能を実装します。
■結果(保存押下後)
■値設定前のフォーム
手順:
-
テーブル(エンティティ)の作成または編集
- テーブル名:
請求書
(スキーマ名:new_invoice
)
- テーブル名:
-
フィールドの追加
-
「税込金額」フィールドの計算式を設定
-
「税込金額」フィールドの設定で、フィールドの種類を「計算」に変更。
-
計算式の編集画面で、以下の数式を設定:
= new_totalamount * (1 + new_taxrate)
-
-
フォームの編集
-
フォーム:
請求書メインフォーム
を開く。 -
フィールド配置:
- 「合計金額」(
new_totalamount
) - 「消費税率」(
new_taxrate
) - 「税込金額」(
new_totalincludingtax
)
- 「合計金額」(
-
これらのフィールドをフォーム上にドラッグ&ドロップ。
-
-
動作確認
- アプリを起動し、新しい請求書レコードを作成。
- 「合計金額」と「消費税率」を入力。
- 「税込金額」が自動的に計算・表示されることを確認。