Dynamics CRM 2011 SDK 5.0.13: メタデータのクエリ その 2

みなさん、こんにちは。

今回も SDK 5.0.13 で改良されたメタデータクエリ API の紹介をします。
今日は強化されたメタデータクエリ概要と C# のサンプルを紹介します。

強化されたメタデータクエリ概要

SDK 5.0.13 では以下の機能が提供されます。

・ QueryExpression と似た手法でクエリが記述可能
・ 柔軟なフィルターにより、最小限のデータのみ取得
・ 前回クエリ以降の差分のみを取得可能
・ 削除されたメタデータの取得

Microsoft.Xrm.Sdk.Metadata.Query

Microsoft.Xrm.Sdk.Metadata.Query 名前空間は、EntityQueryExpression
を初めとしたクエリに利用するクラスやプロパティを提供します。以下の
要素でフィルターが可能です。

・ エンティティ の種類 (ホワイトリスト、およびブラックリスト)
・ エンティティのプロパティによる絞り込み
・ 属性の種類 (取得する型の指定)
・ 属性のプロパティによる絞り込み
・ 指定した言語のラベル

また一度クエリの結果を取得した後再度同じクエリを実行する際に、前回
からの差分のみを取得することが可能です。

サンプル紹介

サンプルは sdk\samplecode\cs\metadata\metadataquery にあります。
早速中身を確認してみましょう。

EntityQueryExpression 作成部分

以下に実際のクエリ部分を抜き出してコメントを入れています。

// WhoAmI を実行して、表示言語の ID を取得
_userId = ((WhoAmIResponse)_service.Execute(new WhoAmIRequest())).UserId;
_languageCode = RetrieveUserUILanguageCode(_userId);
//</snippetLabelQueryExpression1>

 

//<snippetEntityFilter>

// 取得しないエンティティの一覧 (ブラックリストの作成)
String[] excludedEntities = {
"WorkflowLog",
・・省略・・
"ServiceAppointment"};

// 取得するエンティティのフィルターを作成
MetadataFilterExpression EntityFilter = new MetadataFilterExpression(LogicalOperator.And);
// 中間テーブルではない
EntityFilter.Conditions.Add(new MetadataConditionExpression("IsIntersect", MetadataConditionOperator.Equals, false));
// ユーザー所有エンティティである
EntityFilter.Conditions.Add(new MetadataConditionExpression("OwnershipType", MetadataConditionOperator.Equals, OwnershipTypes.UserOwned));
// ブラックリストに指定した以外のエンティティである
EntityFilter.Conditions.Add(new MetadataConditionExpression("SchemaName", MetadataConditionOperator.NotIn, excludedEntities));
// モバイルで表示するもの
MetadataConditionExpression isVisibileInMobileTrue = new MetadataConditionExpression("IsVisibleInMobile", MetadataConditionOperator.Equals, true);
EntityFilter.Conditions.Add(isVisibileInMobileTrue);

 

//</snippetEntityFilter>
//<snippetEntityProperties>
// 取得するエンティティのプロパティを指定
MetadataPropertiesExpression EntityProperties = new MetadataPropertiesExpression()
{
    // 指定したものだけを取得
    AllProperties = false
};
// フィールドを取得
EntityProperties.PropertyNames.AddRange(new string[] { "Attributes" });
//</snippetEntityProperties>

//<snippetAttributeQueryExpression>
// さらにフィールドの種類を指定するフィルターを作成
MetadataConditionExpression[] optionsetAttributeTypes = new MetadataConditionExpression[] {
// フィールドの種類が Picklist、State、Status、Boolean の物だけ取得
new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.Picklist),
new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.State),
new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.Status),
new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.Boolean)
};

// 作成した属性用のフィルターを属性フィルターの設定
MetadataFilterExpression AttributeFilter = new MetadataFilterExpression(LogicalOperator.Or);
AttributeFilter.Conditions.AddRange(optionsetAttributeTypes);

// 取得する属性のプロパティを指定。オプションセットと型情報のみ取得
MetadataPropertiesExpression AttributeProperties = new MetadataPropertiesExpression() { AllProperties = false };
AttributeProperties.PropertyNames.Add("OptionSet");
AttributeProperties.PropertyNames.Add("AttributeType");

//</snippetAttributeQueryExpression>

//<snippetLabelQueryExpression3>

// ラベル用のクエリを作成。表示言語を指定
LabelQueryExpression labelQuery = new LabelQueryExpression();
labelQuery.FilterLanguages.Add(_languageCode);

//</snippetLabelQueryExpression3>

//<snippetInitialRequest>
// 最後に EntityQueryExpression を作成。作成済の各種フィルターを指定
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{

    Criteria = EntityFilter,
    Properties = EntityProperties,
    AttributeQuery = new AttributeQueryExpression()
    {
        Criteria = AttributeFilter,
        Properties = AttributeProperties
    },
    LabelQuery = labelQuery

};

// クエリの実行をするために getMetadataChanges メソッドを実行
RetrieveMetadataChangesResponse initialRequest = getMetadataChanges(entityQueryExpression, null, DeletedMetadataFilters.OptionSet);
//</snippetInitialRequest>

RetrieveMetadataChangesResponse メソッド

上記で作成したクエリを実際に実行し、クエリの結果とその時点のバージョンを
取得します。またこのメソッドの第 2 引数に前回のバージョンを指定すると、
差分のみが取得可能です。

protected RetrieveMetadataChangesResponse getMetadataChanges(
   EntityQueryExpression entityQueryExpression,
   String clientVersionStamp,
   DeletedMetadataFilters deletedMetadataFilter)
  {
// RetrieveMetadataChangesRequest  を実行。引数にクエリ、バージョン情報、取得したい
// 削除されたメタデータの種類を指定
      RetrieveMetadataChangesRequest retrieveMetadataChangesRequest = new RetrieveMetadataChangesRequest()
      {
          Query = entityQueryExpression,
          ClientVersionStamp = clientVersionStamp,
          DeletedMetadataFilters = deletedMetadataFilter
      };

      return (RetrieveMetadataChangesResponse)_service.Execute(retrieveMetadataChangesRequest);

  }

その後の流れ

上記コードでまず初めにメタデータを取得した後、サンプルコードでは
メタデータの追加を行いメタデータの取得、またメタデータの削除を行い
メタデータの取得をすることで、追加されたものや削除されたものだけが
差分で取得できることを示しています。

まとめ

以前のメタデータ API と異なり、新しい手法ではクエリ対象の種類を
フィルターするだけでなく、プロパティもフィルターできるため、必要
最小限の情報のみ取得することができ、パフォーマンス向上に貢献
します。すでにメタデータを取得するプログラムがある場合、是非
新しいものに書き換えてください。

尚、こちらの機能を利用するには、2012年 12月 サービスアップデート
または Update Rollup 12 が適用済みである必要があります。

- Dynamics CRM サポート 中村 憲一郎