メタデータへの変更の取得および検出

Microsoft.Xrm.Sdk.Metadata.Query 名前空間のクラスと RetrieveMetadataChangesRequest および RetrieveMetadataChangesResponse クラスで、有効なメタデータ クエリの構築と時間経過に伴って発生するメタデータへの変更の取得が可能です。

このドキュメントで参照されるすべてのコード例は、「サンプル: メタデータのクエリと変更の検出」にあります。

技術記事「 JavaScriptを使用したメタデータのクエリ 」では、クライアント側コードでオブジェクトとメッセージを使用するためのJavaScriptライブラリが提供されています。

メタデータの使用方法

メタデータで Dynamics 365 Customer Engagement (on-premises) のデータ モデリングの変更に合わせたアプリケーションを作成することができます。 メタデータは次の種類のアプリケーションで重要です。

  • クライアント アプリケーションの UI

  • 外部システムに Dynamics 365 Customer Engagement (on-premises) データをマップする統合ツール

  • 開発ツール

    Microsoft.Xrm.Sdk.Metadata.Query 名前空間のクラスを使用して軽量のクエリと永続メタデータ キャッシュ間に存在する設計を実行できます。

軽量のクエリ

軽量クエリの例には、Dynamics 365 Customer Engagement オプション セット (候補リスト) 属性で、現在のオプションを表示するための選択コントロールを設定するユーザー定義 Web リソース UI がある場合が含まれます。 使用可能なオプションが変更されると、コードを更新する必要があるため、これらのオプションはハード コードにするのは好ましくありません。 その代わり、メタデータから、オプション値とラベルを取得するクエリを作成できます。

Dynamics 365 Customer Engagement アプリケーション キャッシュからこのデータを直接取得する場合に Microsoft.Xrm.Sdk.Metadata.Query クラスを使用できるため、このデータをキャッシュする必要はありません。

永続メタデータ キャッシュ

Dynamics 365 Server から切断しているときに動作可能でなければならないアプリケーションがある場合や、モバイル アプリケーションなどのクライアントとサーバー間のネットワーク帯域幅の制限に影響を受けやすいアプリケーションがある場合、永続メタデータ キャッシュを実装することができます。

永続メタデータ キャッシュを使用すると、アプリケーションで最初の接続時に、必要なすべてのメタデータをクエリする必要があります。 次にそのアプリケーションにそのデータを保存します。 次にアプリケーションが接続する時には、最後のクエリからの差異のみを取得できます。これにより、送信する必要があるデータが少なくなり、アプリケーションを読み込んでいる間に、変更をメタデータ キャッシュに統合します。

メタデータの変更へのポーリング頻度は、アプリケーションのメタデータの変化予測と、アプリケーションの実行時間に基づいて決めます。 メタデータの変更がいつ発生するかの検出に使用できるイベントはありません。 検出されたメタデータの変更が保存される日数には制限があります。また、素の制限を超えて発生する変更要求があった場合、メタデータ キャッシュの完全再初期化が必要です。 詳細については、「削除されたメタデータの有効期限」を参照してください。

変更がない場合は、クエリはすぐに応答し、送信されるデータはありません。 ただし、特にキャッシュから削除される予定の削除済みメタデータ アイテムがある場合、その要求が終了するまでさらに時間がかかることが予想されます。 詳細については、「削除されたメタデータを取得するときのパフォーマンス」を参照してください。

必要なメタデータのみの取得

メタデータは、アプリケーションを起動した時に頻繁に取得または同期されるため、アプリケーションの読み込み時間に影響を与えます。 これは、メタデータを取得するのが初めてのモバイル アプリケーションで特に当てはまります。 必要なメタデータのみを取得することは、アプリケーションのパフォーマンスを向上させるために非常に重要です。

EntityQueryExpression クラスは、エンティティ データを取得する複雑なクエリを作成するときに使用する QueryExpression クラスと構造的に一貫しています。 RetrieveAllEntitiesRequestRetrieveEntityRequestRetrieveAttributeRequest、または RetrieveRelationshipRequest クラスとは異なり、RetrieveMetadataChangesRequest には必要なプロパティに加えて返されるデータの特定の条件を指定するときに使用できる EntityQueryExpression インスタンスを受け入れる Query パラメーターが含まれます。 RetrieveMetadataChangesRequest を使用して、RetrieveAllEntitiesRequest を使用して取得したメタデータのフル セットまたは特定の属性のラベルだけを返すことができます。

フィルターの条件の指定

EntityQueryExpression.Criteria プロパティは、値に基づいてエンティティのプロパティをフィルター処理するための要件を定義できる MetadataConditionExpression オブジェクトのコレクションを含む MetadataFilterExpression を受け取ります。 これらの要件では、以下の演算子で使用できる MetadataConditionOperator を使用します。

次の例は、除外するエンティティの一覧に含まれない、交差するエンティティではないユーザー所有のエンティティのセットを返す MetadataFilterExpression を示します。




     // An array SchemaName values for non-intersect, user-owned entities that should not be returned.
     String[] excludedEntities = {
"WorkflowLog",
"Template",
"CustomerOpportunityRole",
"Import",
"UserQueryVisualization",
"UserEntityInstanceData",
"ImportLog",
"RecurrenceRule",
"QuoteClose",
"UserForm",
"SharePointDocumentLocation",
"Queue",
"DuplicateRule",
"OpportunityClose",
"Workflow",
"RecurringAppointmentMaster",
"CustomerRelationship",
"Annotation",
"SharePointSite",
"ImportData",
"ImportFile",
"OrderClose",
"Contract",
"BulkOperation",
"CampaignResponse",
"Connection",
"Report",
"CampaignActivity",
"UserEntityUISettings",
"IncidentResolution",
"GoalRollupQuery",
"MailMergeTemplate",
"Campaign",
"PostFollow",
"ImportMap",
"Goal",
"AsyncOperation",
"ProcessSession",
"UserQuery",
"ActivityPointer",
"List",
"ServiceAppointment"};

     //A filter expression to limit entities returned to non-intersect, user-owned entities not found in the list of excluded entities.
     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);

必要なプロパティの指定

Properties プロパティは MetadataPropertiesExpression を受け取ります。 すべてのプロパティを返す場合は MetadataPropertiesExpression.AllPropertiestrue に設定することができます。または文字列のコレクションを MetadataPropertiesExpression.PropertyNames に提供して、状態をどのプロパティに含めるかを定義することができます。

返される、厳密に型指定されたオブジェクトには、すべてのプロパティが含まれますが、要求したオブジェクトのみにデータがあります。 他のプロパティはすべて null ですが、いくつかの例外があります。メタデータの各アイテムはいずれも、そのアイテムの値が存在する場合は MetadataIdLogicalName および HasChanged の値が含まれます。 要求した Properties 内に指定する必要はありません。

マネージド コードを使用せず、XMLHttpRequest から返される responseXML を実際に分析する場合、各プロパティの要素が取得されますが、要求したものだけにデータが含まれます。 次の XML は IsVisibleInMobile が要求した唯一のプロパティの場合に返される、取引先担当者エンティティ メタデータを示します。

<a:EntityMetadata>  
 <c:MetadataId>608861bc-50a4-4c5f-a02c-21fe1943e2cf</c:MetadataId>  
 <c:HasChanged i:nil="true"/>  
 <c:ActivityTypeMask i:nil="true"/>  
 <c:Attributes i:nil="true"/>  
 <c:AutoRouteToOwnerQueue i:nil="true"/>  
 <c:CanBeInManyToMany i:nil="true"/>  
 <c:CanBePrimaryEntityInRelationship i:nil="true"/>  
 <c:CanBeRelatedEntityInRelationship i:nil="true"/>  
 <c:CanCreateAttributes i:nil="true"/>  
 <c:CanCreateCharts i:nil="true"/>  
 <c:CanCreateForms i:nil="true"/>  
 <c:CanCreateViews i:nil="true"/>  
 <c:CanModifyAdditionalSettings i:nil="true"/>  
 <c:CanTriggerWorkflow i:nil="true"/>  
 <c:Description i:nil="true"/>  
 <c:DisplayCollectionName i:nil="true"/>  
 <c:DisplayName i:nil="true"/>  
 <c:IconLargeName i:nil="true"/>  
 <c:IconMediumName i:nil="true"/>  
 <c:IconSmallName i:nil="true"/>  
 <c:IsActivity i:nil="true"/>  
 <c:IsActivityParty i:nil="true"/>  
 <c:IsAuditEnabled i:nil="true"/>  
 <c:IsAvailableOffline i:nil="true"/>  
 <c:IsChildEntity i:nil="true"/>  
 <c:IsConnectionsEnabled i:nil="true"/>  
 <c:IsCustomEntity i:nil="true"/>  
 <c:IsCustomizable i:nil="true"/>  
 <c:IsDocumentManagementEnabled i:nil="true"/>  
 <c:IsDuplicateDetectionEnabled i:nil="true"/>  
 <c:IsEnabledForCharts i:nil="true"/>  
 <c:IsImportable i:nil="true"/>  
 <c:IsIntersect i:nil="true"/>  
 <c:IsMailMergeEnabled i:nil="true"/>  
 <c:IsManaged i:nil="true"/>  
 <c:IsMappable i:nil="true"/>  
 <c:IsReadingPaneEnabled i:nil="true"/>  
 <c:IsRenameable i:nil="true"/>  
 <c:IsValidForAdvancedFind i:nil="true"/>  
 <c:IsValidForQueue i:nil="true"/>  
 <c:IsVisibleInMobile>  
  <a:CanBeChanged>false</a:CanBeChanged>  
  <a:ManagedPropertyLogicalName>canmodifymobilevisibility</a:ManagedPropertyLogicalName>  
  <a:Value>false</a:Value>  
 </c:IsVisibleInMobile>  
 <c:LogicalName>contact</c:LogicalName>  
 <c:ManyToManyRelationships i:nil="true"/>  
 <c:ManyToOneRelationships i:nil="true"/>  
 <c:ObjectTypeCode i:nil="true"/>  
 <c:OneToManyRelationships i:nil="true"/>  
 <c:OwnershipType i:nil="true"/>  
 <c:PrimaryIdAttribute i:nil="true"/>  
 <c:PrimaryNameAttribute i:nil="true"/>  
 <c:Privileges i:nil="true"/>  
 <c:RecurrenceBaseEntityLogicalName i:nil="true"/>  
 <c:ReportViewName i:nil="true"/>  
 <c:SchemaName i:nil="true"/>  
</a:EntityMetadata>  
  

将来のリリースでは、要求していないプロパティの値に null 要素を返さないようにすることでさらなる効率性が達成される可能性もあります。 この XML を解析するためのコードを作成する場合、同じクエリで返される XML を次の XML のみに削除することができることが想定されます。

<a:EntityMetadata>  
 <c:MetadataId>608861bc-50a4-4c5f-a02c-21fe1943e2cf</c:MetadataId>  
 <c:IsVisibleInMobile>  
  <a:CanBeChanged>false</a:CanBeChanged>  
  <a:ManagedPropertyLogicalName>canmodifymobilevisibility</a:ManagedPropertyLogicalName>  
  <a:Value>false</a:Value>  
 </c:IsVisibleInMobile>  
 <c:LogicalName>contact</c:LogicalName>  
</a:EntityMetadata>  

メタデータは階層構造で RetrieveAllEntitiesRequest を使用したときと同じように返されます。 特定の属性または関係にアクセスするには、その一部となるエンティティを返すクエリを作成する必要があります。 特定の属性についてのデータを取得する場合、EntityMetadata.Attributes プロパティを EntityQueryExpression.Properties に含める必要があります。 返されるエンティティ関係で、EntityMetadata プロパティの ManyToManyRelationshipsManyToOneRelationships、または OneToManyRelationships の 1 つまたは複数が含まれている必要があります。

次の例は、要求したエンティティの Attributes プロパティを返します。



//A properties expression to limit the properties to be included with entities
MetadataPropertiesExpression EntityProperties = new MetadataPropertiesExpression()
{
 AllProperties = false
};
EntityProperties.PropertyNames.AddRange(new string[] { "Attributes" });

属性メタデータの取得

EntityQueryExpression.AttributeQuery プロパティは、EntityQueryExpressionCriteria および Properties に一致するエンティティに対して返される属性の Criteria および Properties を定義する、AttributeQueryExpression を受入れます。

次の表は、MetadataFilterExpression で使用できない AttributeMetadata プロパティを示します。

次の例は、返される属性を OptionSet がある属性のみに制限し、これらの属性に対し OptionSet および AttributeType プロパティのみを返します。



//A condition expresson to return optionset attributes
MetadataConditionExpression[] optionsetAttributeTypes = new MetadataConditionExpression[] { 
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)
};

//A filter expression to apply the optionsetAttributeTypes condition expression
MetadataFilterExpression AttributeFilter = new MetadataFilterExpression(LogicalOperator.Or);
AttributeFilter.Conditions.AddRange(optionsetAttributeTypes);

//A Properties expression to limit the properties to be included with attributes
MetadataPropertiesExpression AttributeProperties = new MetadataPropertiesExpression() { AllProperties = false };
AttributeProperties.PropertyNames.Add("OptionSet");
AttributeProperties.PropertyNames.Add("AttributeType");

関連付けのメタデータの取得

EntityQueryExpression.RelationshipQuery プロパティは、EntityQueryExpressionCriteria および Properties と一致するエンティティに必要なエンティティの関連付け Criteria および Properties を指定する RelationshipQueryExpression を受け入れます。

ManyToMany 関連付けまたは OneToMany 関連付けを返すかどうかを指定するには、条件で RelationshipType プロパティを使用します。

次の表は、MetadataFilterExpression で使用できない関連付けメタデータ プロパティを示します。

ラベルの取得

最後に EntityQueryExpression.LabelQuery プロパティは、1 つまたは複数の整数 LCID 値を指定してどのローカライズされたラベルを返すかを決定できる LabelQueryExpression を受け取ります。 有効なロケール ID 値は、ロケール ID (LCID) の一覧のページで確認できます。 組織で複数の言語パックがインストールされている場合は、LabelQuery を指定しないとすべての言語が返されます。

次の例では、ユーザーが使用する言語を表すラベルのみに制限する LabelQueryExpression の定義を示します。



private Guid _userId;
private int _languageCode;



_userId = ((WhoAmIResponse)_service.Execute(new WhoAmIRequest())).UserId;
_languageCode = RetrieveUserUILanguageCode(_userId);



protected int RetrieveUserUILanguageCode(Guid userId)
{
 QueryExpression userSettingsQuery = new QueryExpression("usersettings");
 userSettingsQuery.ColumnSet.AddColumns("uilanguageid", "systemuserid");
 userSettingsQuery.Criteria.AddCondition("systemuserid", ConditionOperator.Equal, userId);
 EntityCollection userSettings = _service.RetrieveMultiple(userSettingsQuery);
 if (userSettings.Entities.Count > 0)
 {
  return (int)userSettings.Entities[0]["uilanguageid"];
 }
 return 0;
}




//A label query expression to limit the labels returned to only those for the user's preferred language
LabelQueryExpression labelQuery = new LabelQueryExpression();
labelQuery.FilterLanguages.Add(_languageCode);

新規または変更済みのメタデータの取得

RetrieveMetadataChangesResponse クラスは要求したデータが含まれている厳密に型指定された EntityMetadataCollection を返します。 RetrieveMetadataChangesResponse クラスは、以降の要求でRetrieveMetadataChangesRequest.ClientVersionStamp に渡すことができる ServerVersionStamp 値も提供します。 値が ClientVersionStamp プロパティに含まれているとき、EntityQueryExpression に一致し、ClientVersionStamp が取得された以降に変更されたデータだけが返されます。 これの唯一の例外は、EntityQueryExpression.PropertiesEntityMetadata.Privileges が含まれる場合です。 特権は ClientVersionStamp に関係なく、常に返されます。 こうすると、アプリケーションで最後にメタデータをクエリした後で関連する重要な変更が発生したかどうかを確認できます。 次に、新しいまたは変更されたメタデータを、アプリケーションで不要なメタデータのダウンロードに伴うパフォーマンスの問題が発生するのを防げるよう、永続メタデータ キャッシュに統合できます。

HasChanged プロパティでは、変更されたメタデータ アイテムの子要素を検出できる方法を提供します。 すべてのメタデータが、メタデータ アイテムの一部として返されるので、OptionMetadata のラベルを変更した場合、含まれる EntityMetadataAttributeMetadataOptionSetMetadata のプロパティが返されます。 ただし、HasChanged プロパティがこれらのメタデータ アイテムを含む場合は false を返します。 OptionMetadata.HasChanged プロパティのみが true になります。

次の例は EntityQueryExpression を定義し、null に設定されている ClientVersionStamp の要求を実行することにより、最初の要求を作成しています。



//An entity query expression to combine the filter expressions and property expressions for the query.
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{

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

};

//Retrieve the metadata for the query without a ClientVersionStamp
RetrieveMetadataChangesResponse initialRequest = getMetadataChanges(entityQueryExpression, null, DeletedMetadataFilters.OptionSet);



protected RetrieveMetadataChangesResponse getMetadataChanges(
 EntityQueryExpression entityQueryExpression,
 String clientVersionStamp,
 DeletedMetadataFilters deletedMetadataFilter)
{
 RetrieveMetadataChangesRequest retrieveMetadataChangesRequest = new RetrieveMetadataChangesRequest()
 {
  Query = entityQueryExpression,
  ClientVersionStamp = clientVersionStamp,
  DeletedMetadataFilters = deletedMetadataFilter
 };

 return (RetrieveMetadataChangesResponse)_service.Execute(retrieveMetadataChangesRequest);

}

削除されたメタデータに関する情報の取得

RetrieveMetadataChangesResponse.DeletedMetadata プロパティは ClientVersionStamp および DeletedMetadataFilters プロパティが RetrieveMetadataChangesRequest に設定されている場合に DeletedMetadataCollection を返します。 DeletedMetadataCollection には、時間制限内で削除された EntityMetadataAttributeMetadata または RelationshipMetadataBase オブジェクトの MetadataId の値を含みます。 詳細については、「削除されたメタデータの有効期限」を参照してください。

DeletedMetadataFilters 列挙を、RetrieveMetadataChangesRequest.DeletedMetadataFilters とともに使用して、関心のあるメタデータの種類のみに情報を限定します。 DeletedMetadataFilters 列挙体には次のオプションが用意されています。

削除されたメタデータの有効期限

削除されたメタデータ アイテムは、Organization.ExpireSubscriptionsInDays の値により指定されている制限期間中、追跡されます。 既定では、値は 90 日に設定されています。 RetrieveMetadataChangesRequest.ClientVersionStamp 値が、最後のメタデータ クエリが有効期限の前のものであることを示している場合、サービスは ExpiredVersionStamp エラー (0x80044352) を表示します。データを取得して更新中に、既存のメタデータ キャッシュを取得しようとするたびにこのエラーが表示され、ClientVersionStamp を使用せずに渡された 2 番目の要求から結果を取得したメタデータ キャッシュの再初期化の準備が行われます。 ExpiredVersionStamp エラーは、ExpireSubscriptionsInDays 値の変更などのサーバー上での変更が、削除データの正確な追跡に影響する場合にもスローされます。

次の例は ClientVersionStamp を渡し、ExpiredVersionStamp を取得しています。 エラーが示された場合、キャッシュは null に設定された ClientVersionStamp を使用した新しい要求を渡すことによって再初期化されます。



protected String updateOptionLabelList(EntityQueryExpression entityQueryExpression, String clientVersionStamp)
{
 //Retrieve metadata changes and add them to the cache
 RetrieveMetadataChangesResponse updateResponse;
 try
 {
  updateResponse = getMetadataChanges(entityQueryExpression, clientVersionStamp, DeletedMetadataFilters.OptionSet);
  addOptionLabelsToCache(updateResponse.EntityMetadata, true);
  removeOptionLabelsFromCache(updateResponse.DeletedMetadata, true);

 }
 catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
 {
  // Check for ErrorCodes.ExpiredVersionStamp (0x80044352)
  // Will occur when the timestamp exceeds the Organization.ExpireSubscriptionsInDays value, which is 90 by default.
  if (ex.Detail.ErrorCode == unchecked((int)0x80044352))
  {
   //reinitialize cache
   _optionLabelList.Clear();

   updateResponse = getMetadataChanges(entityQueryExpression, null, DeletedMetadataFilters.OptionSet);
   //Add them to the cache and display the changes
   addOptionLabelsToCache(updateResponse.EntityMetadata, true);

  }
  else
  {
   throw ex;
  }

 }
 return updateResponse.ServerVersionStamp;
}

削除されたメタデータを取得するときのパフォーマンス

メタデータ アイテムを削除すると、Dynamics 365 Customer Engagement メタデータ キャッシュではなくデータベースに保存されます。 削除されたメタデータが MetadataId とメタデータ アイテムの種類のみに制限されていても、データベースへのアクセスは変更をクエリするだけの場合よりもより多くのサーバー リソースが必要な操作です。

関連項目

アプリケーションとサーバー拡張機能の作成
Dynamics 365 Customer Engagement サービスをオフラインで使用する
サンプル: メタデータのクエリと変更の検出
Dynamics 365 Customer Engagement のメタデータ モデルを拡張する
エンティティ メタデータのカスタマイズ
エンティティ属性メタデータのカスタマイズ
エンティティ関係メタデータをカスタマイズする