次の方法で共有


Upsert を使用してレコードを作成または更新

Upsert メッセージを使用すると、データ統合シナリオの複雑さを軽減できます。 一括データ統合シナリオなど、外部システムから Microsoft Dataverse にデータを読み込む場合、Dataverse にレコードが既に存在するかどうかがわかりません。 このような場合、 Update または Create メッセージのどちらを使用するかを決定することはできません。 適切な操作を実行する前に、レコードが存在するかどうかを確認するために、まずレコードを取得する必要があります。 Upsert メッセージを使用すると、この複雑さを軽減してデータをより効率的に Dataverse に読み込むことができます。

UpsertではなくCreateを使用すると、パフォーマンスが低下します。 レコードが存在しないことが確実な場合は、Create を使用します。

ヒント

主キー値は Upsertで使用できますが、一般的なユース ケースはデータ統合シナリオであるため、代替キーを使用することが一般的に予想されます。 詳細については、「 代替キーを使用してレコードを参照する」を参照してください。

エラスティック テーブルのアップサート

Upsertのエラスティック テーブルの動作は、標準テーブルとは異なります。 エラスティック テーブルを使用すると、 Upsert 操作では、レコードが既に存在するかどうかに応じて、 Create または Update メッセージは呼び出されません。 Upsert は、エンティティ内の変更を直接適用します。

  • レコードが存在する場合: 操作は、レコード内のすべてのデータをエンティティ内のデータで上書きします。 Update イベントはありません。
  • レコードが存在しない場合: 操作によって新しいレコードが作成されます。 Create イベントはありません。

この動作は、イベントにビジネス ロジックを適用する場所に影響します。 CreateまたはUpsertを使用して、新しいレコードを作成できます。 レコードは、 Update または Upsertを使用して更新できます。 エラスティック テーブルの CreateUpdate に一貫してロジックを適用する必要がある場合は、そのロジックを Upsert にも含める必要があります。 詳細については、 エラスティック テーブルのレコードのアップサートを参照してください。

標準テーブルのアップサート プロセスを理解する

サーバーは upsert メッセージを処理します。 SDK for .NET クラスでは、サーバーと同じオブジェクトが使用されます。 したがって、次の説明では、SDK for .NET クラスを使用して、サーバーが UpsertRequest クラス インスタンスを処理し、 UpsertResponse クラス インスタンスを返す方法について説明します。

次の手順では、標準テーブルの UpsertRequest を受信したときのサーバー上の処理ロジックについて説明します。

  1. UpsertRequest インスタンスは、または操作のデータを含む Create インスタンスに Updateが設定された状態で到着します。
  2. 存在する場合、Dataverse は、Target プロパティに設定された Entity インスタンスの Entity.Id プロパティを使用してレコードを検索しようとします。 それ以外の場合は、 Entity.KeyAttributes プロパティの代替キー値を使用します。
  3. レコードが存在する場合は、次の手順を実行します。
    1. Target Entity.Id を見つかったレコードの主キー値に設定します。
    2. Target Entity.KeyAttributes コレクションと同じキーを使用するデータを TargetEntity.Attributes コレクションから削除します。
    3. Update を呼び出します。
    4. UpsertResponse.RecordCreated プロパティを false に設定します。
    5. UpsertResponse.Target の値として、Target エンティティから EntityReference を作成します。
    6. UpsertResponse を返します。
  4. レコードが存在しない場合は、次の手順を実行します。
    1. Target Entity.KeyAttributesに存在し、かつTargetEntity.Attributesにまだ存在しない任意のデータをEntity.Attributesコレクションにコピーします。
    2. Create を呼び出します。
    3. UpsertResponse.RecordCreatedtrueに設定します。
    4. エンティティから Target を作成し、id操作のCreate結果を UpsertResponse.Target の値として作成します。
    5. UpsertResponse を返します。

次の図は、 UpsertRequest を受信したときのサーバー上のプロセスを示しています。

Dataverse の標準テーブルのアップサート プロセス フローのスクリーンショット。

リクエスト作成のガイダンス

代替キーを使用してレコードを識別する場合は、保存するデータを表す要求の部分に代替キー データを含めないでください。

Web API を使用していて、SDK for .NET に慣れていない場合は、前に説明したサーバー側のプロセスに従うのが難しい場合があります。 Web API には、前述の説明と図で使用した SDK オブジェクトと同じオブジェクト モデルはありませんが、次の表に示すようにデータをマップできます。

Web API SDK 説明
URL のキー値 Entity.KeyAttributes プロパティ レコードを識別する代替キー データが含まれています。
要求の本文 UpsertRequest.Target プロパティに設定されたエンティティ Create または Update に使用するデータが含まれています。

サーバーは前述のようにこれらの要求を処理しますが、次のように考えることができます。

  • レコードが存在する場合: サーバーは、URL 内の代替キー値に対する要求の本文でデータ セットを削除するため、それを含める意味はありません。 これにより、代替キー値を使用してレコードを識別しているときに、レコードの代替キー値を更新できなくなります。 代替キーの値は、主キーまたは別の代替キーのセットを使用して変更できます。
  • レコードが存在しない場合: サーバーは、URL の代替キーで指定された値と データが異なる場合でも 、要求の本文で設定された代替キー値を使用して新しいレコードを作成します。 要求の本文に代替キー データがない場合、サーバーは URL から要求の本文に代替キー データをコピーします。 URL のキー値と本文の対応するキー値が一致しない状況を回避するには、本文に含めないでください。

Web API の使用

Web API を使用すると、指定したUpsert リソースに HTTP Update要求を送信することで、PATCHEntitySetメッセージを開始できます。 URL 内のキーによってリソースが識別されます。

UpsertUpdateの違いは、If-Match: *要求ヘッダーを含めるかどうかによって異なります。 If-Match: *要求ヘッダーを含め、URL のキー値と一致するリソースがない場合、要求は404 Not Found状態コードを返します。 If-Match: * 要求ヘッダーは、PATCH 要求が Update 操作であることを保証します。

If-Match: *要求ヘッダーを含めない場合、PATCH要求はUpsertのように扱われます。 URL 内のキーに一致するレコードが見つからない場合、要求によって新しいレコードが作成されます。 ただし、SDK とは異なり、応答ではレコードが作成されたかどうかは示されません。 状態の応答は、どちらの場合も 204 No Content です。

Prefer: return=representation要求ヘッダを含める場合、システムは201 CreatedCreateステータスと200 OKUpdateステータスを返します。 このヘッダーを追加すると、追加の Retrieve 操作が追加されるため、パフォーマンスに影響します。 このオプションを使用する場合は、追加する $select クエリ オプションに主キー値のみが含まれていることを確認してください。 詳細については、以下を参照してください:

PATCH要求を使用すると、If-None-Match: *要求ヘッダーを含めて、レコードのみを作成する場合にUpdateをブロックすることもできます。 詳細については、「 アップサート操作の制限」を参照してください。

Web API サンプル コード

次の例は、2 つの代替キー列を持つテーブルを使用した Upsert 操作を示しています。

upsert を使用して作成する

この要求により、レコードが作成されます。

要求:

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: application/json

{ "example_name": "2:2" }

応答:

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2)

upsert を使用して更新する

この要求は、前の要求によって作成されたレコードを更新します。

要求:

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: application/json

{ "example_name": "2:2 Updated" }

応答:

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2)

ヒント

応答は、作成または更新操作で同じです。

upsert と return=representation preference を使用して作成する

Prefer: return=representation ヘッダーを使用すると、応答で別の状態コードを取得して、レコードが作成されたか更新されたかを示すことができます。

次の要求は、新しいレコードを作成し、状態 201 Created を返します。

要求:

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=3,example_key2=3)?$select=example_recordid HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Prefer: return=representation
Content-Type: application/json

{ "example_name": "3:3" }

応答:

HTTP/1.1 201 Created
Content-Type: application/json; odata.metadata=minimal
ETag: W/"71004878"
Preference-Applied: return=representation
OData-Version: 4.0

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#example_records(example_recordid)/$entity",
  "@odata.etag": "W/\"71004878\"",
  "example_recordid": "ef0d112e-d70e-ed11-82e5-00224822577b"
}

Upsert と return=representation の基本設定での更新

この要求は、前の要求によって作成されたレコードを更新し、状態 200 OK を返して、これが更新操作であることを示します。

要求:

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=3,example_key2=3)?$select=example_recordid HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Prefer: return=representation
Content-Type: application/json

{ "example_name": "3:3 Updated" }

応答:

HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal
ETag: W/"71004880"
OData-Version: 4.0

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#example_records(example_recordid)/$entity",
  "@odata.etag": "W/\"71004880\"",
  "example_recordid": "ef0d112e-d70e-ed11-82e5-00224822577b"
}

.NET用SDKを利用する

クライアント アプリケーションでは、IOrganizationService.Execute メソッドを使用し、UpsertRequest インスタンスのTarget プロパティを、または操作のデータを含むEntity インスタンスで設定します。 通常、Entity インスタンスの Entity.KeyAttributes プロパティは、代替キーを使用してレコードを識別するために使用される値で設定します。

UpsertResponse.RecordCreated プロパティは、レコードが作成されたかどうかを示し、UpsertResponse.Target には、作成または更新されたレコードへの参照が含まれています。

SDK for .NET サンプル コード

Upsert サンプルを使用した Insert レコードSampleMethod.cs ファイルには、次のProcessUpsertメソッドが含まれています。 このメソッドは、XML ファイルの内容に UpsertRequest メッセージを適用して、新しいレコードを作成したり、既存のレコードを更新したりします。

public static void ProcessUpsert(CrmServiceClient service, String Filename)
{
    Console.WriteLine("Executing upsert operation.....");
    XmlTextReader tr = new XmlTextReader(Filename);
    XmlDocument xdoc = new XmlDocument();
    xdoc.Load(tr);
    XmlNodeList xnlNodes = xdoc.DocumentElement.SelectNodes("/products/product");

    foreach (XmlNode xndNode in xnlNodes)
    {
        String productCode = xndNode.SelectSingleNode("Code").InnerText;
        String productName = xndNode.SelectSingleNode("Name").InnerText;
        String productCategory = xndNode.SelectSingleNode("Category").InnerText;
        String productMake = xndNode.SelectSingleNode("Make").InnerText;

        //use alternate key for product
        Entity productToCreate = new Entity("sample_product", "sample_productcode", productCode);

        productToCreate["sample_name"] = productName;
        productToCreate["sample_category"] = productCategory;
        productToCreate["sample_make"] = productMake;
        var request = new UpsertRequest()
        {
            Target = productToCreate
        };

        try
        {
            // Execute UpsertRequest and obtain UpsertResponse.
            var response = (UpsertResponse)service.Execute(request);
            if (response.RecordCreated)
                Console.WriteLine("New record {0} is created!", productName);
            else
                Console.WriteLine("Existing record {0} is updated!", productName);
        }

        // Catch any service fault exceptions that Dataverse throws.
        catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
        {
            throw;
        }
    }
}

関連項目

変更の追跡を使用してデータを外部システムに同期
テーブルの代替キーを定義する
代替キーを使用してレコードを参照