CreateMultiple と UpdateMultiple のプラグインを書き込む

注意

CreateMultipleUpdateMultiple メッセージが展開されています。 Create および Update をサポートするすべてのテーブルは、CreateMultiple および UpdateMultiple を最終的にサポートしますが、一部のテーブルはまだサポートしない可能性があります。 一括操作メッセージの詳細情報

レコードを一括して作成、更新する必要があるテーブルや、大量のレコードを作成、更新する際のパフォーマンスが重要な場合は、CreateMultiple メッセージや UpdateMultiple メッセージのプラグインを作成する必要があります。 ビジネス データを保存するほぼすべてのテーブルは、一括で作成、または更新する必要がある場合があります。

このようなテーブルの CreateUpdate メッセージ用のプラグインを既にお持ちの場合は、代わりに CreateMultipleUpdateMultiple を使用するように移行してください。

プラグインの更新は必要ですか?

プラグインを移行して、CreateMultiple および UpdateMultipleCreate および Update の代わりに使用する必要はありません。 アプリケーションが CreateMultiple または UpdateMultiple を使用する場合、ロジックは引き続き適用されます。 Dataverse メッセージ処理パイプラインは、これらのメッセージの単一バージョンまたは複数バージョンのいずれかに対して書き込まれた プラグインのロジックをマージするので、プラグインを移行する必要はありません。

ただし、パフォーマンスが大幅に向上するのは、これらのメッセージの複数のバージョン用に作成されたプラグインのみです。 時間の経過とともに、より多くの開発者が、CreateMultiple そして UpdateMultiple メッセージを処理するために、複数の操作用のプラグインを作成することが標準になると予想されます。 単一操作用に作成されたプラグインは例外となります。

何が違うのですか?

以下は、CreateMultiple および UpdateMultiple メッセージへプラグインを移行する場合に管理する必要がある相違点の一部です。

ターゲットではなくターゲット

これらのメッセージの複数のバージョンには、 Targets パラメーター EbtityCollection ではなく Target 単一のパラメータ Entity があります。 プラグイン コードは、コレクション内のエンティティをループし、それぞれにロジックを適用する必要があります。

エンティティ イメージ

プラグインのステップ登録で構成されたエンティティ イメージは、EntityImageCollection の配列です。 これらのエンティティ イメージは、PreEntityImagesCollectionPostEntityImagesCollection のプロパティを提供する IPluginExecutionContext4 Interface を使用する場合にのみ利用可能です。 これらの配列は、EntityCollection と同期されている配列内の同じエンティティ イメージへのアクセスを提供します。

Power Platform Tools を使用してプラグイン プロジェクトを初期化する場合の標準である PluginBase クラスを使用する場合、次に PluginBase.cs ファイルでIPluginExecutionContextIPluginExecutionContext4 に置き換える必要がある場合、これらのエンティティ イメージ全体はプラグインで利用可能です。

重要

CreateMultiple および UpdateMultiple のプラグインの手順のエンティティ イメージを構成する場合、どの列データを含めるかを慎重に選択することが重要です。 すべての列の既定オプションを選択しないでください。 このデータは、Targets パラメーターを使用し、サンドボックスに送信されるメッセージの合計サイズに影響します。 メッセージ サイズの制限に達する可能性があります。

属性フィルター

Update または UpdateMultiple に登録されたプラグインの場合、ステップ登録で属性のフィルタリングを指定することができます。

  • Update では、プラグインは、選択した属性のいずれかが更新中の Target エンティティを含む場合実行されます。
  • UpdateMultiple では、選択した属性のいずれかが Targets パラメータの いずれか のエンティティに含まれる場合にプラグインが実行されます。

重要

UpdateMultiple に対して、Targets パラメーターのすべてのエンティティには、フィルタで使用される属性が含まれるとは限りません。

次の例では、Update の基本ロジックを使用した例と、UpdateMultiple のロジックを使用した別の例で、手順に登録されたエンティティ イメージにアクセスします。

この例では、sample_name 値が変更されたかどうかに関する情報を使用して sample_description 属性を更新します。 ステップに登録された example_preimage という名前のエンティティ イメージを指しています。

// Verify input parameters
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity entity)
{

   // Verify expected entity image from step registration
   if (context.PreEntityImages.TryGetValue("example_preimage", out Entity preImage))
   {

      bool entityContainsSampleName = entity.Contains("sample_name");
      bool entityImageContainsSampleName = preImage.Contains("sample_name");
      bool entityImageContainsSampleDescription = preImage.Contains("sample_description");

      if (entityContainsSampleName && entityImageContainsSampleName && entityImageContainsSampleDescription)
      {
            // Verify that the entity 'sample_name' values are different
            if (entity["sample_name"] != preImage["sample_name"])
            {
               string newName = (string)entity["sample_name"];
               string oldName = (string)preImage["sample_name"];
               string message = $"\\r\\n - 'sample_name' changed from '{oldName}' to '{newName}'.";

               // If the 'sample_description' is included in the update, do not overwrite it, just append to it.
               if (entity.Contains("sample_description"))
               {

                  entity["sample_description"] = entity["sample_description"] += message;

               }
               else // The sample description is not included in the update, overwrite with current value + addition.
               {
                  entity["sample_description"] = preImage["sample_description"] += message;
               }

               // Success:
               localPluginContext.Trace($"Appended to 'sample_description': \"{message}\" ");
            }
            else
            {
               localPluginContext.Trace($"Expected entity and preImage 'sample_name' values to be different. Both are {entity["sample_name"]}");
            }
      }
      else
      {
            if (!entityContainsSampleName)
               localPluginContext.Trace("Expected entity sample_name attribute not found.");
            if (!entityImageContainsSampleName)
               localPluginContext.Trace("Expected preImage entity sample_name attribute not found.");
            if (!entityImageContainsSampleDescription)
               localPluginContext.Trace("Expected preImage entity sample_description attribute not found.");
      }
   }
   else
   {
      localPluginContext.Trace($"Expected PreEntityImage: 'example_preimage' not found.");
   }
}
else
{
   if (!context.InputParameters.Contains("Target"))
      localPluginContext.Trace($"Expected InputParameter: 'Target' not found.");
   if (!(context.InputParameters["Target"] is Entity))
      localPluginContext.Trace($"Expected InputParameter: 'Target' is not Entity.");
}

例外処理

プラグイン内で発生するすべてのエラーは、InvalidPluginExecutionException を使用して返される必要があります。 CreateMultiple および UpdateMultiple メッセージに登録されたステップに対してプラグインが例外をスローする場合は、プラグインが失敗した原因となったレコードを指定する必要があります。 この情報を取得するためには、これらのコンストラクターのいずれかを使用する必要があります:

これらのコンストラクターを使用すると、InvalidPluginExecutionException.ExceptionDetails プロパティに値を追加できますが、このプロパティは直接設定できません。

コンストラクターの Dictionary<String,String> exceptionDetails パラメータを使用して、失敗したレコードに関する情報およびその他の関連情報を含めます。

例外の詳細を設定する

UpdateMultiple メッセージの場合、コードは EntityCollection Targets プロパティを繰り返し、各 エンティティ にロジックを適用しています。 失敗した場合、次の方法でレコードの IdInvalidPluginExecutionException コンストラクターに渡すことができます。

// in plugin code
foreach (Entity entity in Targets)
{
   // [...] When an error occurs:
   var exceptionDetails = new Dictionary<string, string>();
   exceptionDetails.Add("failedRecordId", (string)entity.Id);
   throw new InvalidPluginExecutionException("This is an error message.", exceptionDetails);
}

失敗に関連するその他の情報を文字列のキーと値のペアとして exceptionDetails パラメーターに追加します。

CreateMultiple の場合は、各レコードの主キー値を設定しないことをお勧めします。 ほとんどの場合、システムが生成する値は最高のパフォーマンスを発揮するように最適化されているため、システムによる主キー値の設定を許可する必要があります。

主キー値が設定されていない場合、他にユニークな識別子がない場合は、EntityCollection Targets パラメーターに失敗したレコードのインデックスを返すか、失敗したレコードを一意に識別する何らかの値の組み合わせが必要になる場合があります。 たとえば、EntityCollection の中のレコードの場所を示す failedRecordIndex というキーや、その他の有用なユニークな識別子を exceptionDetails に追加して、障害のトラブルシューティングに役立てることができます。

例外の詳細を取得する

InvalidPluginExecutionException.ExceptionDetails プロパティに失敗した操作の詳細を含める場合、クライアント アプリケーションは OrganizationServiceFault.ErrorDetails プロパティから FaultException<OrganizationServiceFault>.Detail プロパティを通じてこれらの詳細を取得することができます。 次のコードで方法を示しています:


try
{
   // xMultiple request that triggers your plugin
}
catch (FaultException<OrganizationServiceFault> ex)
{
   ex.Detail.ErrorDetails.TryGetValue("failedRecordId", out object failedRecordId);
}

クライアント アプリケーションが Web API を使用している場合は、Prefer: odata.include-annotations="*" リクエストヘッダーを設定して、エラーに関する詳細を取得できます。

ソリューション内の単一操作プラグインを置き換える

ソリューションにプラグイン ステップ登録を展開する場合、ステップ登録を強制的に無効にしたり削除したりする方法はありません。 そのため、ロジックを単一操作から複数操作のプラグインに置き換えるのが困難になります。

Create または Update のプラグイン ステップを置き換える CreateMultiple または UpdateMultiple のソリューションで新しいプラグイン ステップを展開する場合、ロジックまたは重複ロジックが適用されないなら時間を削減できます。 ソリューションをインストールする前または後に、Create または Update の手順を手動で無効にすることができます。 以前に無効にすると、ロジックが適用されない期間が発生します。 以降に無効にすると、重複ロジックが適用される期間が発生します。 いずれの場合も、組織はロジックを一貫して適用するために計画的なダウンタイムを必要とする場合があります。

これらの状態のいずれかの期間を最小限に抑えるには、 Package Deployer を使用して新しいプラグインを展開することによって置き換えられるステップを無効にするロジックを組み込むことをお勧めします。 Package Deployer は、パッケージが環境にインポートされる前、中、後に、カスタム コードを実行する機能を提供します。 このコードを使用して、既存のステップ登録を無効にします。

参照

サンプル: CreateMultiple および UpdateMultiple プラグイン
一括操作メッセージ
サンプル: .NET 用 SDK 一括操作の使用
一括操作で最適化されたパフォーマンス

注意

ドキュメントの言語設定についてお聞かせください。 簡単な調査を行います。 (この調査は英語です)

この調査には約 7 分かかります。 個人データは収集されません (プライバシー ステートメント)。