CrmSer ice 経由で エンティティのレコードを作成すると 既定では重複チェックが行われません。エンティティが重複チェックを行うように設定されかつ、重複データの演出ルールが定義されていたとしても、データは登録、更新できます。
Windows Live版ブログDynamics CRM の CrmService API で データ登録時に重複データ検出ルールを使用するで紹介した OptionParameter のサブクラスである、CreateDuplicatesOptionalParameter と PersistInSyncOptionalParameter を使用して重複データの検出を行うようにできます。重複データが見つかった場合例外SoapException がスローされるようになります。
動作確認は Dynamics CRM 4.0 Rollup 8 が適用された環境で行っています。プログラムは Visual Studio 2008(.NET 3.5)でコンパイルしていますが.NET 3.0 以上の機能はつかっていないのでSystem.Linq などのusingを削除すれば.NET 2.0 以上で動作できると思います。
今回は、Dynamics CRM インストール時に既定で作成される 取引先企業の重複ルール(メールアドレス重複) に一致するデータを連続で投入して重複エラーが発生することを確認します。
1. CrmService経由でエンティティ作成時に重複データを検出するサンプル
1.1 サンプルプログラム
デモプログラムを以下に記載します。サンプルプログラムでは、CreateDuplicatesOptionalParameter(false) とすることで重複データの作成(更新)を行うときに重複データが存在したばあエラーとするように指定しています。また、PersistInSyncOptionalParameter(true) とすることで同期的にマッチコードの更新を行うようにしています。マッチコードについてはサンプログラムの後に記載します。
サンプルプログラムをコンパイルするには、 microsoft.crm.sdk, microsoft.crm.sdktypeproxy.dll, System.Web.Services.dll への参照を追加する必要があります。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Crm.SdkTypeProxy; using Microsoft.Crm.Sdk; using System.Net; using System.Web.Services.Protocols; using System.Xml; namespace CrmServiceDuplicateCheck { /// <summary> /// CreateDuplicatesOptionalParameter を使って、 CrmServiceのCreate,Update メソッド時に /// 重複データ検出ルールを使用して重複データ投入時にエラーにするサンプル /// /// サンプルプログラムでは Dynamics にデフォルトで用意されている 取引先企業の重複ルール /// に一致するデータを投入する. /// /// microsoft.crm.sdk.dll,microsoft.crm.sdktypeproxy.dll,System.Web.Services.dll への参照を追加すること /// /// キーワード:マッチコードの更新システムジョブ。画面から連続して重複したデータを投入しても /// エラーが発生しないのは、マッチコードの更新システムジョブが5分ごとにしか実行されない /// ためである。 /// マッチコードの更新も同期的に行うとパフォーマンスに影響が発生するので、注意してください。 /// </summary> class Program { /// <summary> /// ○まとめ /// CreateDuplicatesOptionalParameter.Valule /// true : 重複データが見つが存在してもデータの登録、更新を行う。(既定) /// false: 重複データが見つかった場合、データの登録、更新は行わない。SoapExceptionが発生 /// /// PersistInSyncOptionalParameter.Value /// true : マッチコードの更新を同期的に行う。(直後に重複データが登録・更新されても検知可能) /// false: マッチコードの更新を非同期で行う。(直後に重複データが登録・更新されても検知負荷)(既定) /// /// 非同期マッチコードの更新の場合、システムジョブのマッチコードの更新ジョブが実行されるまで /// 重複データの検出は行われない。(5分ごとにジョブは実行される) /// /// </summary> /// <param name="args"></param> static void Main(string[] args) { try { CrmService service = GetCrmService("localhost", "dyn"); // 同じメールアドレスで企業作成 CreateAccount(service, "取引先企業C1", "test@test36.com"); CreateAccount(service, "取引先企業D1", "test@test36.com"); } catch (SoapException se) { XmlNode code = se.Detail.SelectSingleNode("//code"); if (code != null) { Console.WriteLine("Error Code:" + code.InnerText); } XmlNode description = se.Detail.SelectSingleNode("//description"); if (description != null) { Console.WriteLine("Error Message:" + description.InnerText); } //Console.WriteLine(se.Detail.InnerXml); } Console.WriteLine("終了"); Console.ReadLine(); } /// <summary> /// 登録時に同期的にデータの重複チェックを行い、重複ルールに一致するものがあれば /// エラーとする。 /// 取引先企業の重複ルールでは、emailaddress1,emailaddress2,emailaddress3 がすべて /// 一致するとエラーとなる。ただしブランク(NULL)どうしの項目一致とみなされるので注意 /// </summary> /// <param name="service"></param> /// <param name="name"></param> /// <param name="email"></param> static void CreateAccount(CrmService service, string name, string email) { account account1 = new account(); account1.name = name; account1.emailaddress1 = email; //account1.emailaddress2 = email; //account1.emailaddress3 = email; CreateRequest request = new CreateRequest(); TargetCreateAccount target = new TargetCreateAccount(); target.Account = account1; // PersistInSyncOptionalparameter(false)の場合、非同期でマッチコードの更新が行われる // そのため、連続して重複ルールに一致するデータを投入するとエラーとならない。 request.OptionalParameters = new OptionalParameter[]{ new CreateDuplicatesOptionalParameter(false), new PersistInSyncOptionalParameter(true)}; request.Target = target; Response response = service.Execute(request); } /// <summary> /// OnPremise (AD) 認証 環境でテスト /// </summary> /// <param name="host">CRMサーバ名</param> /// <param name="orgName">組織名</param> /// <returns></returns> static CrmService GetCrmService(string host, string orgName) { CrmService service = new CrmService(); UriBuilder uriBuilder = new UriBuilder("http", host, 80); uriBuilder.Path = "/mscrmservices/2007/crmservice.asmx"; CrmAuthenticationToken token = new CrmAuthenticationToken(); token.AuthenticationType = 0; token.OrganizationName = orgName; service.Url = uriBuilder.ToString(); service.CrmAuthenticationTokenValue = token; service.Credentials = CredentialCache.DefaultCredentials; service.UseDefaultCredentials = true; return service; } } }
プログラムをコンパイルして実行すると例外が発生し、重複データの検出が行われたことが確認できます。 重複ルールの検出は、エンティティが重複データをチェックすることおよび重複データの検出ルールが公開されている必要があるので注意してくだっさい。
取引先企業の重複ルールは、emailaddress1,emailaddress2,emailaddress3 のすべてが他のレコードと一致すると重複とみなされます。Dynamicsの場合、値が null どうしの比較も等しいと判定されるので注意してください。たとえばemailaddress2がnull(ブランク)の場合、比較先のemailaddress2もnullなら一致すると判定されます。
1.1 CreateDuplicatesOptionalParameter と PersistInSyncOptionalParameter について
重複ルールの検出は OptionalParameter のサブクラスである CreateDuplicatesOptionalParameter と PersistInSyncOptionalParameter の設定値が重要なので、次にまとめておきます。
- CreateDuplicatesOptionalParameter.Valule
true : 重複データが見つが存在してもデータの登録、更新を行う。(既定)
false: 重複データが見つかった場合、データの登録、更新は行わない。SoapExceptionが発生
- PersistInSyncOptionalParameter.Value
true : マッチコードの更新を同期的に行う。(直後に重複データが登録・更新されても検知可能)
false: マッチコードの更新を非同期で行う。(直後に重複データが登録・更新されても検知負荷)(既定)
OptionalParameter を指定しないと 既定値(重複データが存在してもデータの登録、更新を行い、マッチコードの更新を非同期で行う) の振る舞いをするので、重複データを登録・更新が行われます。
マッチコードの更新は同期的に行うと、直後に重複データが登録・更新されても重複検出が行えるようになりますがパフォーマンスに影響があるので注意してください。
1.2 マッチコードの更新について
Dynamics は 5分ごとにマッチコードの更新ジョブが実行されます。マッチコードを使用してDynamicsは重複データのチェックを行っているため、非同期にマッチコードを更新する設定でWebサービスを呼び出した場合マッチコードが更新されるまでは重複のデータを投入しても重複データとして検出されません。
同期的にマッチコードを更新すると重複データの検出がすぐに可能になります。
2. 画面で投入したデータとインポートウィザードでの重複データの検出について
画面で投入したデータの重複データの検知が直後で有効にならないのは、マッチコードの更新が非同期で行われるためのようです。
インポートウィザードの場合は、下図のように"重複するレコードをインポートしない"オプションを選択すれば、マッチコードの更新が同期的に行われ、同じインポートファイル内に重複データがあっても重複データとしてを検知してくれるようです。
3.まとめと注意点
説明は以上です。間違い疑問点などありましたらご連絡ください。注意点ですが、マッチコードを同期的に更新したとしても、多重化するなどをして同時に重複ルールに該当するレコードを登録すると登録できてしまいます。マッチコードの更新を同期的に作成すると1秒もかからずに重複が検出されるようになるのですが、ほぼ同時にレコードを作成すると作成できることが確認しました。重複データが1秒以内に作成される場合などに問題になる可能性があります。その場合、非サポートの行為ですがユニークキー制約を設定するなどで対処するひつようがあります。
OptionalParameters は重複データ以外の場所でも使用できます。どのメッセージのときに OptionalParametersが使用できるかは次のリンクを参照してください。
- Using Optional Parameters in Messages
http://msdn.microsoft.com/en-us/library/cc151036.aspx