組織サービスを使用したテーブル行の更新と削除

注意

エンティティとテーブルの違いがわかりませんか? Microsoft Dataverse で「開発者: 用語を理解する」を参照してください。

このトピックでは、遅延バインドと事前バインドの両方のプログラミング形式を使用する例を紹介します。 詳細: 組織サービスを使用した事前バインディングおよび遅延バインディング プログラミング

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

重要

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

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

注意

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

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

基本的な更新

以下の両方の例でIOrganizationServiceUpdateを使用します 以前に取得されたテーブル行の列値を設定するメソッド。

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

注意

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

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

遅延バインド例

次の例は、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);

事前バインドの例

次の例は、作成した Account クラスを使用して、IOrganizationService.Update を使用してアカウント行を更新します。 メソッド。

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

var account = new 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メソッドを使用する代わりに エンティティ インスタンスをTargetプロパティに設定し、次にIOrganizationService .Executeを使用して、UpdateRequestクラスで遅延バインドEntity クラスまたは生成された事前バインド エンティティ クラスのいずれかを使用できます メソッド。

注意

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

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

UpdateRequest クラスを使用する場合

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

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

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

これを行うには、id 値にアクセスできるように、関連する行を含む行を取得する必要があります。 詳細情報: 関連行で取得する

重要

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

遅延バインド例

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);

事前バインドの例

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

//Update the account
account.Name = "New Account name";

//Update the email address for the primary contact of the account
account.account_primary_contact = new Contact
{ Id = retrievedAccount.PrimaryContactId.Id, EMailAddress1 = "someone_a@example.com" };

// Find related Tasks that need to be updated
List<Task> tasksToUpdate = retrievedAccount.Account_Tasks
    .Where(t => t.Subject.Equals("Example Task")).ToList();

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

//Fill the list of updated tasks based on the tasks that need to but updated
tasksToUpdate.ForEach(t =>
{
    updatedTasks
    .Add(new Task() {
        ActivityId = t.ActivityId,
        Subject = "Updated Subject"
    });

});

//Set the updated tasks to the collection
account.Account_Tasks = updatedTasks;

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

重複レコードの確認

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

代替キーで更新する

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

事前バインド型クラスを使用する場合は、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 の使用

通常、データ統合シナリオでは、他のソースから Microsoft 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(request1);
Console.WriteLine("Record Created: {0}", response2.RecordCreated); //false

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

Delete キー

IOrganizationService.Delete メソッドには、テーブルの論理名と一意の識別子が必要です。 遅延バインディング Entity クラスまたは生成された事前バインディング クラスを使用しているかどうかに関係なく、Entity.LogicalName をパスして操作を削除するために次の構文を使用できます。 および Entity.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.IsOptimisticConcurrencyEnabledtrue) が有効になっています
  • 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> はこの属性を提供する任意のエンティティを参照します。

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

関連項目

組織サービスを使用したテーブル行の作成
組織サービスを使用したテーブル行の取得
組織サービスを使用したテーブル行の関連付けと関連付け解除

注意

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

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