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