SDK for .NET を使用したテーブル行の更新と削除

この記事では、遅延バインドと事前バインドの両方のプログラミング形式を使用する例を紹介します。 詳細: .NET 用 SDK を使用した事前バインドおよび遅延バインド プログラミング

それぞれの例では、IOrganizationServiceインターフェイスのメソッドを実装するクラスのインスタンスを表す svc 変数を使用しています。 このインターフェイスのサポートの詳細については、 IOrganizationService インターフェイスを参照してください。

重要

テーブルの行を更新するときは、変更する列のみを含めてください。 以前に取得したテーブル行の列を更新するだけで、値が変更されていなくても各列が更新されます。 これにより、値が実際に変化したことを予期するビジネス ロジックをトリガーすることができる、システム イベントを発生させます。 これにより、実際には変更されていないが、監査データで列が更新されたように見える場合もあります。

新しい Entity インスタンスを作成し、id 属性と変更する属性値を設定し、そのエンティティ インスタンスを使用してテーブルの行を更新する必要があります。

注意

列定義には、RequiredLevel プロパティが含まれます。 これが SystemRequired に設定されている場合、これらの列を null 値に設定することはできません。 これを試みると、メッセージ Attribute: <attribute name> cannot be set to NULL とともにエラー コード -2147220989 を受け取ります。

詳細: 列 (属性) の要件レベル

基本的な更新

以下の両方の例では、 IOrganizationService.Update メソッド を使って、以前に取得したテーブル行の列値を設定します。

Entity.Id プロパティ を使用して、取得した行の一意識別子を、更新操作を実行するために使用されるエンティティ インスタンスに移動します。

注意

主キー値なしで行を更新しようとすると、エラー: Entity Id must be specified for Update が発生します。

主キーの値がない場合は、代替キーを使用して行を更新することもできます。 詳細: 代替キーで更新する

次の例は、[エンティティ クラス](xref:Microsoft.Xrm.Sdk.Entity] を使用して、IOrganizationService.Update メソッド を使用したアカウントを作成する方法を示しています。

var retrievedAccount = new Entity("account", new Guid("a976763a-ba1c-e811-a954-000d3af451d6"));

//Use Entity class with entity logical name
var account = new Entity("account");
account.Id = retrievedAccount.Id;
// set attribute values
// Boolean (Two option)
account["creditonhold"] = true;
// DateTime
account["lastonholdtime"] = DateTime.Now;
// Double
account["address1_latitude"] = 47.642311;
account["address1_longitude"] = -122.136841;
// Int
account["numberofemployees"] = 400;
// Money
account["revenue"] = new Money(new Decimal(2000000.00));
// Picklist (Option set)
account["accountcategorycode"] = new OptionSetValue(2); //Standard customer

//Update the account
svc.Update(account);

UpdateRequest クラスを使用

IOrganizationService.Update メソッドを使用する代わりに、エンティティ クラスをUpdateRequest.Target プロパティに設定してから、IOrganizationService.Execute メソッド を使用することにより、遅延バインド エンティティ クラス または生成されたエンティティ インスタンスを UpdateRequest.Target プロパティ に使用できます。

注意

UpdateResponse クラス にはプロパティがありません。 IOrganizationService.Execute メソッドによって返されますが、それを参照する必要はありません。

var request = new UpdateRequest()
{ Target = account };
svc.Execute(request);

UpdateRequest クラスを使用する場合

オプション パラメーターを渡す場合は、UpdateRequest クラスを使用する必要があります。 特殊なパラメーターを必要とする場合が 2 つあります。

オプティミスティック同時実行の動作を指定する場合は、UpdateRequestクラスも使用する必要があります。 詳細: オプティミスティック同時実行の動作

UpdateMultipleRequest クラスを使用する

UpdateMultipleRequest クラス は、単一のリクエストで複数のレコードを更新する最もパフォーマンスの高い方法です。 詳細: 一括操作メッセージ

1 回の操作で関連するテーブル行を作成 できる方法と同じように、関連するテーブル行を更新することもできます。

関連するテーブル行を更新するには、ID 値にアクセスできるように、関連する行を含む行を取得する必要があります。 詳細情報: 関連行で取得する

重要

行の更新は特定の順序で行われます。 最初に、プライマリ テーブルの行が処理され、次に関連するテーブルの行が処理されます。 ルックアップまたは関連する行の列のプライマリ行によって変更が行われた後、関連する行が同じ列を更新する場合、関連する行の値は保持されます。 一般に、ルックアップ列の値と、同じリレーションシップの Entity.ManyEntities 内の同等の値を同時に使用しないでください。

var account = new Entity("account");
account.Id = retrievedAccount.Id;

//Define relationships
var primaryContactRelationship = new Relationship("account_primary_contact");
var AccountTasksRelationship = new Relationship("Account_Tasks");

//Update the account name
account["name"] = "New Account name";

//Update the email address for the primary contact of the account
var contact = new Entity("contact");
contact.Id = retrievedAccount.RelatedEntities[primaryContactRelationship]
.Entities.FirstOrDefault().Id;
contact["emailaddress1"] = "someone_a@example.com";

List<Entity> primaryContacts = new List<Entity>();
primaryContacts.Add(contact);  
account.RelatedEntities.Add(primaryContactRelationship, new EntityCollection(primaryContacts));

// Find related Tasks that need to be updated
List<Entity> tasksToUpdate = retrievedAccount
.RelatedEntities[AccountTasksRelationship].Entities
.Where(t => t["subject"].Equals("Example Task")).ToList();

// A list to put the updated tasks
List<Entity> updatedTasks = new List<Entity>();

//Fill the list of updated tasks based on the tasks that need to but updated
tasksToUpdate.ForEach(t => {
var updatedTask = new Entity("task");
updatedTask.Id = t.Id;
updatedTask["subject"] = "Updated Subject";

updatedTasks.Add(updatedTask);
});

//Set the updated tasks to the collection
account.RelatedEntities.Add(AccountTasksRelationship, new EntityCollection(updatedTasks));

//Update the account and related contact and tasks
svc.Update(account);

重複レコードの確認

テーブルの行を更新するときに、その行が別の行の複製を表すように値を変更できます。 詳細: .NET 用 SDK を使用した重複データの検出

代替キーで更新する

テーブルに代替キーが定義されている場合は、主キーの代わりにそれを使用して行を更新できます。 事前バインド型クラスを使用して代替キーを指定できません。 代替キーを指定するには Entity(文字列, KeyAttributeCollection) コンストラクターを使用する必要があります。

事前バインド型クラスを使用する場合は、Entity.ToEntity<T> メソッドを使用して Entity を事前バインド型クラスに変換できます。

次の例は、accountnumber列 (属性) に対して定義された代替キーを使用して Account を更新する方法を示しています。

重要

ビジネス データのほとんどのテーブルには、代替キーが定義されていません。 このメソッドは、テーブルの代替キーを定義するように環境が構成されている場合にのみ使用できます。

var accountNumberKey = new KeyAttributeCollection();
accountNumberKey.Add(new KeyValuePair<string, object>("accountnumber", "123456"));

Account exampleAccount = new Entity("account", accountNumberKey).ToEntity<Account>();
exampleAccount.Name = "New Account Name";
svc.Update(exampleAccount);

詳細情報:

エラスティック テーブル内のレコードを更新、削除する

パーティションに格納されているエラスティック テーブルデータを更新または削除する場合は、そのデータにアクセスするときに必ずパーティションキーを指定してください。 詳細情報: パーティション分割と水平スケーリング

upsert の使用

通常、データ統合シナリオでは、他のソースから Dataverse にデータを作成または更新する必要があります。 Dataverse には、既に一意識別子と同じレコードが存在する可能性があります。これは代替キーでもかまいません。 テーブル行が存在する場合は、それを更新する必要があります。 エンティティ レコードが存在しない場合は、追加するデータがソース データと同期するように作成します。 これは、upsert を使いたいシナリオです。

次の例はUpsertRequestを 2 回使用します。 アカウント行が最初に作成されたとき、および accountnumber 値があるためにアカウント行が 2 回目に更新されたとき、その列 (属性) を使用する代替キーがあります。

どちらの呼び出しでも、UpsertResponse.RecordCreated プロパティ は、操作によって行が作成されたかどうかを示します。

// This environment has an alternate key set for the accountnumber attribute.

//Instantiate account entity with accountnumber value
var account = new Entity("account", "accountnumber", "0003");
account["name"] = "New Account";

//Use Upsert the first time
UpsertRequest request1 = new UpsertRequest() {
Target = account
};

//The new entity is created
var response1 = (UpsertResponse)svc.Execute(request1);
Console.WriteLine("Record Created: {0}",response1.RecordCreated); //true

//Update the name of the existing account entity
account["name"] = "Updated Account";

//Use Upsert for the second time
UpsertRequest request2 = new UpsertRequest()
{
Target = account
};

//The existing entity is updated.
var response2 = (UpsertResponse)svc.Execute(request2);
Console.WriteLine("Record Created: {0}", response2.RecordCreated); //false

詳細: Upsert を使用してレコードを挿入または更新

Delete

IOrganizationService.Delete メソッドには、テーブルの論理名と一意の識別子が必要です。 遅延バインドエンティティ クラスを使用しているのか、生成された事前バインド エンティティ クラスを使用しているのかにかかわらず、Entity.LogicalNameEntity.Id プロパティを渡すことによって、削除操作に次の構文を使用できます。

svc.Delete(retrievedEntity.LogicalName, retrievedEntity.Id);

または、次の値を使用できます。

svc.Delete("account", new Guid("e5fa5509-2582-e811-a95e-000d3af40ae7"));

重要

削除操作は、環境内のリレーションシップに定義されたロジックに応じて、子行を削除してデータの整合性を維持するカスケード操作を開始できます。 詳細: テーブル関係の動作

DeleteRequest クラスの使用

IOrganizationService.Delete メソッド の代わりに DeleteRequest クラスを使用できますが、これはオプティミスティック同時実行動作を指定する場合にのみ必要です。

var retrievedEntity = new Entity("account")
{
    Id = new Guid("c81ffd82-cd82-e811-a95c-000d3af49bf8"),
    RowVersion = "986335"

};

var request = new DeleteRequest()
{
    Target = retrievedEntity.ToEntityReference(),
    ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches
};

svc.Execute(request);

オプティミスティック同時実行の動作

UpdateRequestまたは DeleteRequestクラスのConcurrencyBehavior プロパティを設定すると、操作のためのオプティミスティック同時実行の動作を指定できます。

行を更新または削除するロジックは、古いデータに基づいている可能性があります。 最新のデータが取得されてから変更されたために異なる場合は、オプティミスティック同時実行によって更新または削除操作を取り消してから、再度取得して現在のデータを使用して続行するかどうかを判断できます。

行が変更されたかどうかを判断するために、すべての値を比較する必要はありません。RowVersion プロパティを使用して変更されたかどうかを確認します。

次の例は、次の場合にのみ成功します。

  • データベース内の行の RowVersion986323 と等しくなります
  • 取引先企業テーブルは、オプティミスティック同時実行 (EntityMetadata.IsOptimisticConcurrencyEnabled プロパティtrue) に対して有効です
  • RowVersion プロパティは、リクエストで渡された行に設定されます。

RowVersion が一致しないと、メッセージ The version of the existing record doesn't match the RowVersion property provided. のエラーが発生します。

var retrievedAccount = new Account()
{   
    Id = new Guid("a976763a-ba1c-e811-a954-000d3af451d6"), 
    RowVersion = "986323" 
};

var account = new Account();
account.Id = retrievedAccount.Id;
account.RowVersion = retrievedAccount.RowVersion;

// set attribute values
account.CreditOnHold = true;

//Update the account
var request = new UpdateRequest()
{ 
    Target = account,
    ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches 
};

try
{
    svc.Execute(request);
}
catch (FaultException<OrganizationServiceFault> ex)
{
    switch (ex.Detail.ErrorCode)
    {
        case -2147088254: // ConcurrencyVersionMismatch 
        case -2147088253: // OptimisticConcurrencyNotEnabled 
            throw new InvalidOperationException(ex.Detail.Message);
        case -2147088243: // ConcurrencyVersionNotProvided
            throw new ArgumentNullException(ex.Detail.Message);
        default:
            throw ex;
    }
}

詳細情報:

従来の更新メッセージ

更新操作を実行する複数の削除され特化されたメッセージです。 以前のバージョンではこれらのメッセージを使用する必要がありましたが、現在は同じ操作で IOrganizationService.Update または UpdateRequest クラスIOrganizationService.Execute メソッドに使用できます。

廃止されたメッセージ要求 更新が必要な属性
AssignRequest <entity>.OwnerId
SetStateRequest <entity>.StateCode
<entity>.StatusCode
SetParentSystemUserRequest SystemUser.ParentSystemUserId
SetParentTeamRequest Team.BusinessUnitId
SetParentBusinessUnitRequest BusinessUnit.ParentBusinessUnitId
SetBusinessEquipmentRequest Equipment.BusinessUnitId
SetBusinessSystemUserRequest SystemUser.BusinessUnitId

<entity> はこの属性を提供する任意のエンティティを参照します。

重要

StateCode 列を更新するときは、常に目的の StatusCode を設定することが重要です。

StateCodeStatusCode には従属値があります。 特定の StateCode 値に対して複数の有効な StatusCode 値がある可能性がありますが、各 StateCode 列には 1 つの DefaultStatus 値が設定されています。 StatusCode を指定せずに StateCode を更新すると、デフォルトのステータス値がシステムによって設定されます。

また、テーブルと StatusCode 列で監査が有効になっている場合、更新操作で指定しない限り、StatusCode 列の変更された値は監査データに取り込まれません。

詳細: 特化された更新操作の動作

参照

.NET 用 SDK を使用したテーブル行の作成
.NET 用 SDK を使用してテーブルの行を取得する
.NET 用 SDK を使用したテーブル行の関連付けと関連付け解除

注意

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

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