【Dataverse】Visual StudioによるDataverse Plugin(Post Operation)

accountテーブルのtelephone1に登録後、関連するcontactのtelephone1に値を非同期でコピーする場合の手順は以下の通りです。

クラスファイルはプロジェクト内に2つあっても問題ありません。
1つのAssembly(dllファイル)に2つのPluginが出来上がる形になります。
クラスファイルの中身以外は以前の手順踏襲となります。

  • クラスファイルの編集
    クラス名を変更し、開発を行います。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ServiceModel;
    using Microsoft.Xrm.Sdk;
    using System.Text.RegularExpressions;
    using Microsoft.Xrm.Sdk.Query;
    
    namespace MyDataversePluginVS462
    {
        public class FollowupPlugin3 : IPlugin
        {
            public void Execute(IServiceProvider serviceProvider)
            {
                // プラグイン実行コンテキストの取得
                IPluginExecutionContext context = serviceProvider.GetService(typeof(IPluginExecutionContext)) as IPluginExecutionContext;
                if (context == null)
                {
                    throw new InvalidPluginExecutionException("プラグイン実行コンテキストが取得できませんでした。");
                }
    
                // 組織サービスファクトリの取得
                IOrganizationServiceFactory serviceFactory = serviceProvider.GetService(typeof(IOrganizationServiceFactory)) as IOrganizationServiceFactory;
                if (serviceFactory == null)
                {
                    throw new InvalidOperationException("IOrganizationServiceFactory が取得できませんでした。");
                }
    
                // 組織サービスの取得(データ操作用)
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
    
                // トレーシングサービスの取得
                ITracingService tracingService = serviceProvider.GetService(typeof(ITracingService)) as ITracingService;
                if (tracingService == null)
                {
                    throw new InvalidPluginExecutionException("トレーシングサービスが取得できませんでした。");
                }
    
                // PostOperationの場合、InputParametersにTargetは存在しないため、OutputParameterから取得する。
                // ①Createの場合、context.Outputparameters["id"]に作成したレコードのGUIDが含まれている。
                // ②Updateの場合、context.InputParameters["Target"]に更新したレコードが含まれているが、
                //  PostOperationでは、更新後のデータが必要となるため、通常は取得したレコードを再度、サービスで取得し直す。
                // ③Deleteの場合、context.InputParameters["Target"]に削除したレコードが含まれている。
                // 今回はCreateとUpdateを利用します。
    
                Entity account = null;
                if (context.MessageName == "Create" && context.OutputParameters.Contains("id"))
                {
                    // 作成したレコードのGUIDを取得
                    Guid accountId = (Guid)context.OutputParameters["id"];
                    tracingService.Trace($"Account created with GUID:{accountId}");
    
                    // 作成したAccountを再取得
                    account = service.Retrieve("account", accountId, new ColumnSet("telephone1", "primarycontactid"));
                }
                else if (context.MessageName == "Update" && context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                {
                    // 更新したレコードを取得
                    // ※InputParametersのTargetは更新項目のみしか含まないため、再取得
                    Entity updateAccount = (Entity)context.InputParameters["Target"];
                    tracingService.Trace($"Account update with GUID:{updateAccount.Id}");
    
                    account = service.Retrieve("account", updateAccount.Id, new ColumnSet("telephone1", "primarycontactid"));
                }
    
                if (account == null)
                {
                    tracingService.Trace("Account entity not found in context. Exiting plugin.");
                    return;
                }
    
                // Accountの電話番号が空でないかチェック
                if (account.Contains("telephone1") && !string.IsNullOrWhiteSpace(account.GetAttributeValue<string>("telephone1")))
                {
                    string accountPhoneNumber = account.GetAttributeValue<string>("telephone1");
                    tracingService.Trace($"Account Phone Number: {accountPhoneNumber}");
    
                    // Primary Contanct(主取引先担当者)が設定されているかチェック
                    if (account.Contains("primarycontactid") && account.GetAttributeValue<EntityReference>("primarycontactid") != null)
                    {
                        EntityReference primaryContactRef = account.GetAttributeValue<EntityReference>("primarycontactid");
                        tracingService.Trace($"Primary Contanct GUID: {primaryContactRef.Id}");
    
                        try
                        {
                            // ContactレコードをRetrieveして、電話番号が既に設定されているかチェック
                            Entity contact = service.Retrieve("contact", primaryContactRef.Id, new ColumnSet("telephone1"));
    
                            // Contactの電話番号が空欄の場合、または、Accountの電話番号と異なる場合、更新
                            if (!contact.Contains("telephone1") || contact.GetAttributeValue<string>("telephone1") != accountPhoneNumber)
                            {
                                Entity contactToUpdate = new Entity("contact", primaryContactRef.Id);
                                contactToUpdate["telephone1"] = accountPhoneNumber;
                                service.Update(contactToUpdate);
                                tracingService.Trace($"Successfully updated Primary Cntact {primaryContactRef.Name} phone number to: {accountPhoneNumber}");
                            }
                            else
                            {
                                tracingService.Trace($"Primary Contact phone number is alredy set or matches Account's. No update needed.");
                            }
                       }
                       catch (Exception ex)
                        {
                            tracingService.Trace($"Error updating Primary Cotact phone number: {ex.Message}");
    
                            // 本番環境では、InvalidPluginExecutionExceptionをスローしてロールバックするのが良い。
                            //throw new InvalidPluginExecutionException("An error occurred during phone number synchronization.", ex);
                        }
                    }
                    else
                    {
                        tracingService.Trace("No Primary Contact associated with this Account.");
                    }
                }
                else
                {
                    tracingService.Trace("Account does not have a telephone number or its's empty.");
                }
    
                // 処理全体をtry-catchで囲って、catchでInvalidPluginExecutionExceptionするのもあり。
            }
        }
    }
    

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です