EntityDataRecordManipulation.DataLoad  は データファイルとマッピング定義ファイルを使用して、エンティティレコードを作成、更新するツールです。このツールを使えばカスタムプログラムを作ることなく、既存データの更新と作成を行うことができます。本ツールは同一レコード判定やLookupレコードの検索にマッピング定義ファイルで指定したキー情報を使用します。そのため、標準のインポートウィザードやDataConfiguration Utility よりも柔軟に同一レコード判定およびLookupレコード判定を行うことができます。

ツールはDynamics CRM 4.0 TinyEntityRecordManipulationTool からダウンロードできます。

現在のところ、本ツールは Dynamics CRM のデータが格納された SQL Server および、 Dynamics CRM サーバに対して統合認証を使用してアクセスできる環境での動作をサポートしています。

今回の記事はDynamics CRM において システム管理者ロールを持つユーザで処理を実行している前提で説明します。

1. アプリケーションのセットアップ

ツールは使用するためにはアプリケーション構成ファイル TinyEntityDataRecordManipulation.DataLoad.exe.config を編集する必要があります。アプリケーション構成ファイルの構成例です。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="crmServerUrl" value="http://localhost"/>
    <add key="organizationName" value="dyn"/>
    <add key="domain" value="CRM"/>
    <add key="traceRoot" value=".\"/>
    <add key="CrmAuthType" value="AD"/>
    <add key="multiplicity" value="1"/>
  </appSettings>
  <connectionStrings>
    <add name="crmDbConnection"  providerName="System.Data.SqlClient" connectionString="Data Source=(local);Initial Catalog=dyn_MSCRM;Integrated Security=SSPI"/>
  </connectionStrings>
  <system.net>
    <!-- Webサービス接続数上限を増やす。既定値は2のためパフォーマンスを向上させる場合設定する必要がある。 -->
    <connectionManagement>
      <add address="*" maxconnection="10"/>
    </connectionManagement>
    <!--
    <defaultProxy enabled="false" />
    -->
  </system.net>
  <system.diagnostics>
    <sources>
      <source name="DataLoad" switchName="TraceSwitch"
        switchType="System.Diagnostics.SourceSwitch" >
        <listeners>
          <add name="ConsoleWriter" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="TraceSwitch" value="Information"/>
    </switches>
    <sharedListeners>
      <add name="ConsoleWriter" type="System.Diagnostics.ConsoleTraceListener" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
</configuration>

appSettings には次の内容を設定します。

キー
crmServerUrl CRMサーバのURLです。http://サーバ名 で指定します。
organizationName データロード対象の Dynamics の 組織名を指定します。組織名は大文字小文字をただしく設定する必要があります。
domain Dynamics CRMが動作しているドメインのドメイン名を指定します。
traceRoot トレースファイルの出力先フォルダを指定します。
CrmAuthType 認証タイプを指定します。On-Premise の場合は AD, IFD認証の場合は IFD を指定します。online 認証は対応していません。
multiplicity データロードワーカスレッドの多重度を指定します。ロードデータが多い場合多重度を増やすことでパフォーマンスを向上させることができます。

connectionStrings にはname を crmDbConnection として、Dynamics CRM サーバの組織データベースへの接続文字列を指定します。

system.diagnostics のトレース設定は任意の項目です。sourceノードで指定されるSourceSwitch の名前が DataLoad のソーススイッチがある場合にトレースログが出力されます。構成例では、コンソールのトレースリスナを追加しています。構成ファイルのトレースリスナ設定に加えて、プログラム内でテキストリスナーをトレースリスナとして追加するように実装されています。

2. 使いかた

ツールを使用するにはアプリケーション構成ファイルの他に、データファイルとマッピング定義ファイルを準備する必要があります。データファイルはヘッダを持つインポートデータファイルです。マッピング定義ファイルはインポートデータファイルの列とエンティティ属性列のマッピングを定義するファイルです。マッピング定義ファイルの定義方法は使用方法の説明を通じて説明していきます。

2.1 データロードモード

DataLoad では、3つのモードをサポートしています。データファイルの内容をすべて新規レコードとして作成する Insert モードと、 既存のエンティティレコードが存在した場合のみデータファイルの内容でレコードを更新する Update モード。そして、 データが存在した場合は更新を行い、存在しなかった場合にはエンティティレコードを更新する UpdateInsert モードです。

ロードモードはコマンドラインから指定します。

2.2 Insert モードでデータをインポートする

取引先企業を対象として、ファイルのデータをロードしエンティティレコードを作成する方法を使用します。データファイルは次のCSVとします。ファイル名はaccount.txt とします。CSVファイルは1行目にヘッダ行を設定します。それ以降にデータ行を設定します。

acnum,acname,desc,numOfEmployees,bulkmail,ownercode,address_logitude,revenue,websiteurl,emailaddress1,currency
AC001,Company001,DESC 001, 1001,true,1,100.05,10000,http://sample.org,AC001@sample.org,F2C6403B-0B5C-DF11-8ABA-0003FFBF2D57 

ヘッダと1行のデータ行を持つcsvファイルです。次にマッピングファイルを定義します。マッピング定義ファイルのファイル名はmapping.xml です。

<?xml version="1.0" encoding="utf-8" ?>
<entity-mappings>
  <entity name="account">
    <property name="accountnumber" sourceColumn="acnum" crmType="string" isKey="true" />
    <property name="name" sourceColumn="acname" crmType="string" />
    <property name="description" sourceColumn="desc" crmType="string" />
    <property name="numberofemployees" sourceColumn="numOfEmployees" crmType="CrmNumber" />
    <property name="donotbulkmail" sourceColumn="bulkemail" crmType="CrmBoolean" />
    <property name="ownershipcode" sourceColumn="ownercode" crmType="Picklist" />
    <property name="address1_longitude" sourceColumn="address_logitude" crmType="CrmFloat" />
    <property name="revenue" sourceColumn="revenue" crmType="CrmMoney" />
    <property name="websiteurl" sourceColumn="websiteurl" crmType="String" />
    <property name="emailaddress1" sourceColumn="emailaddress1" crmType="String"/>
    <property name="transactioncurrencyid" sourceColumn="currency" crmType="Lookup" lookupType="transactioncurrency" />
  </entity>
</entity-mappings>

マッピング定義は 対象とするエンティティ毎に entity ノードに定義します。 entityノードのname属性にエンティティの論理名を指定して下さい。entityノードの子ノードにproperty ノードを追加して属性の論理名を name 属性に、 sourceColumn 属性にインポートデータファイルのヘッダ名を指定します。crmType には Dynamics 上での型を指定します。

crmTypeで指定できる文字列は次の通りです。

型名 説明
CrmBoolean bit型の属性に指定します。
CrmDateTime datetime型の属性に指定します。
CrmDecimal decimal型の属性に指定します。
CrmFloat float型の属性に指定します。
CrmMoney money型の属性に指定します。
CrmNumber int型の属性に指定します。
Customer customer型の属性に指定します。lookupType属性にlookupするエンティティの論理名を指定する必要があります。
Key key型の属性に指定します。
Lookup lookup型の属性に指定します。lookupType属性にlookupするエンティティの論理名を指定する必要があります。
Owner owner型の属性に指定します。lookupType属性にlookupするエンティティの論理名を指定する必要があります。
Picklist picklist型の属性に指定します。
State state型の属性に指定します。
Status status型の属性に指定します。Stateとともに使用します。 Status が -1 の場合はStateの値の既定値のStatusが設定されます。
String ntext, nvarchar 型など文字列属性に指定します。

property でLookup,Key,Owner,Customerを設定する場合 GUID をデータとして指定する必要があります。動的にデータを検索してGUIDを解決する場合はrelationノードを使用します。relationノードの使い方は後程説明します。

データをInsertモードでロードします。コマンドは次のように指定します。

TinyEntityDataRecordManipulation.DataLoad.exe /in:account.txt /entity:account /mapping:sample\mapping.xml  /loadmode:Insert /lookupmissing:Null

 高度な検索画面の検索結果を確認すると、インポートデータとマッピング定義に従って取引先企業エンティティレコードが作成され属性に値が設定されていることが確認できます。通貨型もUSドルが設定されています。これはデータファイルに指定したGUIDがUSドルの通貨エンティティレコードのGUIDであるためです。(GUIDは環境によって変わります。)

エンティティフォームを表示した画面が下図になります。Webサイトや電子メールも正しく設定されています。

TinyEntityDataRecordManipulation.DataLoad.exe の コマンドラインで指定できるオプションを指定します。

引数 説明
/in: データファイルを指定します。
/entity: ロードする対象エンティティの論理名を指定します。
/mapping: マッピング定義ファイルを指定します。定義ファイルには/entity:で指定したエンティティのマッピング定義が含まれている必要があります。
/loadmode:

ロードモードを指定します。Insert, Update, UpdateInsert のいづれかを指定します。

Insert も場合はデータファイルをすべて作成します。Updateの場合、更新対象レコードが存在した場合のみ更新します。UpdateInsertは更新対象レコードが見つかった場合更新を行い、見つからない場合、レコードを作成します。

/lookupmissing:

relationノードで指定した動的にLookupデータを検索した場合にLookupエンティティが見つからなかったときの動作を指定します。Error または Nullを指定します。

Error の場合、対象データ行をエラーとして処理をスキップします。Nullの場合は、Lookupなどの参照型属性の値をNull としてロード処理を行います。

/help ヘルプメッセージを表示してプログラムを終了します。

2.3 UpdateInsert モードでデータロードを行う

このツールの機能の一つである、キー(複合キー可能)をマッピング定義で定義して更新および作成を行います。

データロードモードが、UpdateInsert の場合、マッピング定義ファイルの propertyノードの IsKey で指定された属性の値が一致するものがエンティティに存在した場合更新が行われます。データが存在しない場合は レコードの作成が行われます。

マッピング定義ファイルはInsertモードの定義と同じものを使用します。実はisKey属性が accountnumber に設定されています。isKey属性はInsertモードの場合は無視されます。

acnum,acname,desc,numOfEmployees,bulkemail,ownercode,address_logitude,revenue,websiteurl,emailaddress1,currency
AC001,Company001 updated,DESC 001 updated, 1001,true,2,100.05,10000,http://sample.org,AC001@sample.org,F2C6403B-0B5C-DF11-8ABA-0003FFBF2D57
AC002,Company002,DESC 002, 1002,false,3,-10,25000,http://ac002.org,AC002@sample.org,ECC6403B-0B5C-DF11-8ABA-0003FFBF2D57

コマンドラインで次のように入力します。/loadmode に UpdateInsert を指定します。

TinyEntityDataRecordManipulation.DataLoad.exe /in:account.txt /entity:account /mapping:sample\mapping.xml  /loadmode:UpdateInsert /lookupmissing:Null

高度な検索画面で取引先企業を確認すると、isKeyが指定された 取引先企業番号 AC001 はすでに存在するためデータが更新されています。取引先企業番号 AC002 のデータが存在しないためデータは作成されています。

/LoadMode:Update の場合、エンティティレコードが存在する場合のみ更新されます。存在しないデータは登録されません。

2.4 relation マッピングを使用して参照先エンティティのGUIDを動的に求める

ロードモードのUpdateInsertやUpdate と isKey 属性を使用することで、データの更新を行うことができますが、本ツールでは動的に参照先エンティティレコードのGUIDを求めることができます。今回はrelation ノードの使い方を説明します。

取引先担当者に対して動的Lookupを使用してロードを行うためのマッピング定義例を以下に示します。nameに属性の論理名、lookupEntity に参照先のエンティティ名、crmTypeに属性の型を指定します。crmTypeにはLookup,Customer,Ownerを指定できます。

relationノードの子ノードにlookupProperty を1つ以上定義します。lookupProperty に参照先を求めるために使用する参照先エンティティの属性とデータファイルの列のマッピングを指定します。ツールはlookupProperty で指定される属性をAND検索を行います。複数データが見つかった場合エラーとなります。本サンプルでは key 属性マッピングを定義しエンティティレコードのGUIDを明示的に指定する方法も示しています。

<?xml version="1.0" encoding="utf-8" ?>
<entity-mappings>
  <entity name="contact">
    <!-- if crmType is key , sourceColumn guid is used as entity record id  -->
    <property name="contactid" sourceColumn="contactid" crmType="key" isKey="true"/>
    <property name="lastname" sourceColumn="last" crmType="string" />
    <property name="firstname" sourceColumn="first" crmType="string" />
    <property name="birthdate" sourceColumn="birthdate" crmType="CrmDateTime" />
    <property name="statecode" sourceColumn="statecode" crmType="State" />
    <property name="statuscode" sourceColumn="statuscode" crmType="Status" />
    <!--
      relation ノードを使用して参照先エンティティのGUIDを動的に求めることができます.
      crmTypeに指定できるのは Lookup, Owner, Customer のみです.lookupEntityに参照先の
       エンティティの論理名を指定します。
      
      lookupPropertyノードでルックアップ先を求めるために使用するエンティティのマッピング
      を定義できます。
    -->
    <relation name="transactioncurrencyid" lookupEntity="transactioncurrency" crmType="lookup">
      <lookupProperty lookupColumn="currencyname" sourceColumn="currency" />
    </relation>
    <relation name="parentcustomerid" lookupEntity="account" crmType="Customer">
      <lookupProperty lookupColumn="accountnumber" sourceColumn="acnum" />
    </relation>
    <relation name="ownerid" lookupEntity="systemuser" crmType="Owner">
      <lookupProperty lookupColumn="firstname" sourceColumn="ownerfirst" />
      <lookupProperty lookupColumn="lastname" sourceColumn="ownerlast" />
    </relation>
  </entity>
</entity-mappings>

データロードに使用する contact.txt は次のCSVファイルです。

contactid,last,first,birthdate,statecode,statuscode,currency,acnum,ownerfirst,ownerlast
8676E054-90BF-42e9-A5A5-05DE23A6BA40,tarou,crm,2010-03-21,active,-1,円,AC001,管理者,CRM
4EF347B2-C947-46c4-B300-6A042D64B44B,hanako,crm,2008-01-10,inactive,2,オーストラリア㌦,AC002,管理者,CRM
6A2BD965-8CF3-45cf-A952-2379EEAEDB68,jirou,crm,2007-11-30,active,-1,,AC003,名,姓

コマンドプロンプトで次のコマンドを入力してデータのロードを行います。

TinyEntityDataRecordManipulation.DataLoad.exe /in:contact.txt /entity:contact /mapping:sample\mapping.xml  /loadmode:UpdateInsert /lookupmissing:Null

高度な検索結果で取引先担当者を表示します。所属取引先企業や通貨型が動的に検索されてLookupされた GUIDが設定されていることが確認できます。/lookupmissing:Null が指定されているので参照先が見つからない場合はNULLが設定されています。

また、データファイルにキーのGUIDを直接指定していたため、その値でエンティティレコードのGUIDが作成されます。

2.5 N:N 多対多関連エンティティデータをロードする

最後に 多対多関連のレコードをロードする方法を記述します。

多対多関連は 2つのrelate ノードを定義して参照先エンティティのレコードを検索して設定します。

マッピングデータの定義例です。entityノードのname属性には多対多関連の名前を指定します。例では、取引先担当者と潜在顧客の多対多関連用のデータと属性のマッピングを定義しています。

<?xml version="1.0" encoding="utf-8" ?>
<entity-mappings>
  <!--
    N:N 関連エンティティのマッピング定義にはisAssociateEntity属性が必要です。
    2つのrelationノードを定義しcrmTypeをLookupとします。
    lookupProperty子ノードで、参照先のエンティティレコードを検索するためのマッピングを定義します。
  -->
  <entity name="contactleads_association" isAssociateEntity="true" >
    <relation name="contactid" lookupEntity="contact" crmType="Lookup">
      <lookupProperty lookupColumn="fullname" sourceColumn="contact full name" />
    </relation>
    <relation name="leadid" lookupEntity="lead" crmType="Lookup">
      <lookupProperty lookupColumn="fullname" sourceColumn="lead full name" />
    </relation>
  </entity>
</entity-mappings>

サンプルとして使用する、ロードデータを次に示します。

contact full name,lead full name
tarou crm,潜在CRM 太郎丸

コマンドの指定例を記載します。

TinyEntityDataRecordManipulation.DataLoad.exe /in:contact_lead.txt /entity:contactleads_association /mapping:sample\mapping.xml  /loadmode:Insert /lookupmissing:Null

実行後、SQL Server Managemement Studio で多対多データが作成されたか確認した結果を下図に示します。カスタムエンティティの場合や標準エンティティで詳細に多対多関連レコードを表示できる場合は画面から確認することができます。

2.6 その他のマッピング定義例

紹介しきれなかったマッピング定義例を示します。isKeyを複数指定(複合キー)する場合や、 CrmDecimal を指定した例は Customer, Owner を relationノードではなく、 property ノードで データファイルでGUID指定する場合のマッピング定義方法を示しています。

<?xml version="1.0" encoding="utf-8" ?>
  <!-- other import mapping sample -->
  <entity name="new_sample">
    <property name="new_firstname" sourceColumn="firstname" crmType="String" isKey="true" />
    <property name="new_lastname" sourceColumn="lastname" crmType="String" isKey="true" />
    <property name="new_decimal" sourceColumn="decimalvalue" crmType="CrmDecimal" />
    <property name="ownerid" sourceColumn="ownerguid" crmType="Owner" />
    <property name="parentcustomerid" sourceColumn="customerguid" crmType="Customer" lookupType="contact" />
  </entity>
</entity-mappings>

3.まとめ

説明は以上です。

まだまだ改善点(型の自動解決やログの強化など)がありますが、ちょっと忙しくなりそうなことと一応動作するところまでいけたので公開しました。

使ってくれる人がいるのかとかの話がありますが、改善点などいろいろ指摘してくださると助かります。