Compartir a través de


Recuperar y detectar cambios en los metadatos

Las clases en el espacio de nombres Microsoft.Xrm.Sdk.Metadata.Query y las clases RetrieveMetadataChangesRequest y RetrieveMetadataChangesResponse permiten crear consultas de metadatos eficaces y capturar cambios en los metadatos a medida que se producen a lo largo del tiempo.

Todos los ejemplos de código a los que se hace referencia en este documento se encuentran en Ejemplo: Metadatos de consulta y Detectar cambios.

En el artículo técnico Metadatos de consulta mediante JavaScript se proporciona una biblioteca de JavaScript para usar los objetos y mensajes en el código del lado cliente.

Estrategias para el uso de metadatos

Los metadatos le permiten crear aplicaciones que se adaptan a medida que cambia el modelo de datos de Dynamics 365 Customer Engagement (on-premises). Los metadatos son importantes para los siguientes tipos de aplicaciones:

  • Interfaz de usuario para aplicaciones cliente

  • Herramientas de integración que tienen que asignar datos de Dynamics 365 Customer Engagement (on-premises) a sistemas externos

  • Herramientas de desarrollo

    Mediante las clases del espacio de nombres Microsoft.Xrm.Sdk.Metadata.Query puede implementar los diseños que existirán en algún punto entre una consulta ligera y una memoria caché de metadatos persistente.

Consulta ligera

Un ejemplo de una consulta ligera es cuando tiene una interfaz de usuario de recurso web personalizada que proporciona un control de selección para mostrar las opciones actuales en un atributo de conjunto de opciones (lista de selección) de Dynamics 365 Customer Engagement. No desea codificar de forma rígida estas opciones porque tendría que actualizar ese código si alguna vez se cambian las opciones disponibles. En su lugar, puede crear una consulta para recuperar solo las opciones, los valores y las etiquetas de los metadatos.

No es necesario almacenar en caché estos datos porque puede usar las Microsoft.Xrm.Sdk.Metadata.Query clases para recuperar estos datos directamente desde la caché de la aplicación Dynamics 365 Customer Engagement.

Caché de metadatos persistentes

Cuando tenga una aplicación que deba poder funcionar mientras está desconectada de Dynamics 365 Server, o que sea sensible a un ancho de banda de red limitado entre el cliente y el servidor, como una aplicación móvil, querrá implementar una caché de metadatos persistente.

Con una caché de metadatos persistente, la aplicación tendrá que consultar todos los metadatos necesarios la primera vez que se conecte. A continuación, guardará esos datos en la aplicación. La próxima vez que la aplicación se conecte al servidor, puede recuperar solo la diferencia desde la última consulta, que debería ser mucho menos datos para transmitir, y luego combinar los cambios en la caché de metadatos cuando se esté cargando la aplicación.

La frecuencia con la que se deben sondear los cambios en los metadatos depende de la volatilidad esperada de los metadatos de la aplicación y del tiempo que la aplicación permanezca en ejecución. No hay ningún evento disponible que pueda usar para detectar cuándo se producen cambios en los metadatos. Hay un límite en el número de días que se guardan los cambios de metadatos eliminados y una solicitud de cambios que se produzca más allá de ese límite requerirá una reinicialización completa de la caché de metadatos. Para obtener más información, consulte Caducidad de metadatos eliminados.

Cuando no hay cambios, la consulta debe responder rápidamente y no habrá datos que transmitir. Sin embargo, si hay cambios, especialmente si hay elementos de metadatos eliminados que deben eliminarse de la memoria caché, puede esperar que la solicitud tarde algún tiempo adicional en finalizar. Más información: Rendimiento al recuperar metadatos eliminados

Recupere solo los metadatos que necesita

Los metadatos se recuperan o sincronizan con frecuencia cuando se inicia una aplicación y pueden afectar al tiempo que tarda la aplicación en cargarse. Esto es particularmente cierto para las aplicaciones móviles que recuperan metadatos por primera vez. Recuperar solo los metadatos que necesita es muy importante para crear una aplicación que funcione bien.

La EntityQueryExpression clase proporciona una estructura coherente con la QueryExpression clase que se utiliza para crear consultas complejas para recuperar datos de entidad. A diferencia de las RetrieveAllEntitiesRequestclases , RetrieveEntityRequest, RetrieveAttributeRequest, o RetrieveRelationshipRequest , contiene RetrieveMetadataChangesRequest un Query parámetro que acepta una EntityQueryExpression instancia que puede usar para especificar criterios específicos para los datos que se van a devolver, además de las propiedades que desea. Puede usarlo RetrieveMetadataChangesRequest para devolver el conjunto completo de metadatos que obtiene mediante el RetrieveAllEntitiesRequest, o simplemente una etiqueta para un atributo específico.

Especificar los criterios de filtro

La propiedad EntityQueryExpression.Criteria acepta un MetadataFilterExpression que contiene una colección de objetos de MetadataConditionExpression que permiten definir condiciones para filtrar propiedades de la entidad basándose en su valor. Estas condiciones utilizan un MetadataConditionOperator que permite los siguientes operadores:

En el ejemplo siguiente se muestra un MetadataFilterExpression que devolverá un conjunto de entidades propiedad del usuario que no se intersectan y que no se incluyen en una lista de entidades que se van a excluir:




     // 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);

Especifique las propiedades que desee

La Properties propiedad acepta un MetadataPropertiesExpression. Puede establecer MetadataPropertiesExpression.AllProperties en true si desea devolver todas las propiedades o puede proporcionar una colección de cadenas a .PropertyNamesMetadataPropertiesExpressionpara definir qué propiedades desea incluir en los resultados.

Los objetos con establecimiento inflexible de tipos devueltos incluirán todas las propiedades, pero solo las que se hayan solicitado tendrán datos. Todas las demás propiedades serán nulas, con las siguientes excepciones: cada elemento de metadatos incluirá los valores MetadataId, LogicalName y HasChanged si existen para ese elemento. No es necesario que los especifique en la solicitud Properties que realice.

Si no usa código administrado y realmente está analizando el responseXML código devuelto por XMLHttpRequest, obtendrá elementos para cada propiedad, pero solo los que solicite contendrán datos. El siguiente XML muestra el xml de metadatos de la entidad de contacto que se devolverá cuando IsVisibleInMobile sea la única propiedad solicitada.

<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>  
  

En una versión futura, se pueden lograr más eficiencias si no se devuelven elementos con valores nulos para las propiedades que no se solicitaron. Si escribe código para analizar este XML, debe esperar que el XML devuelto para la misma consulta se pueda reducir solo al siguiente 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>  

Los metadatos se devuelven en una estructura jerárquica del mismo modo que se utiliza el RetrieveAllEntitiesRequest. Para acceder a un atributo o relación específicos, debe crear una consulta que devuelva la entidad de la que forman parte. Si desea recuperar datos sobre un atributo específico, debe incluir la propiedad EntityMetadata.Attributes en su EntityQueryExpression.Properties. Para que se devuelvan las relaciones de entidad, debe incluir una o varias de las siguientes EntityMetadata propiedades: ManyToManyRelationships, ManyToOneRelationships, o OneToManyRelationships.

El siguiente ejemplo devolverá la propiedad Attributes para las entidades solicitadas:



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

Recuperar metadatos de atributo

La EntityQueryExpressionpropiedad .AttributeQuery acepta un AttributeQueryExpression atributo que define Criteria y Properties para que se devuelvan las entidades que coincidan con el EntityQueryExpressionCriteria y Properties.

En la tabla siguiente se enumeran AttributeMetadata las propiedades que no se pueden utilizar en un MetadataFilterExpression

En el ejemplo siguiente se limitará los atributos devueltos solo a aquellos que tienen un OptionSet y solo devolverá las OptionSet propiedades y AttributeType para esos atributos:



//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");

Recuperar metadatos de relación

La propiedad EntityQueryExpression.RelationshipQuery acepta RelationshipQueryExpression para especificar la relación de entidad Criteria y Properties que desea para las entidades que coinciden con EntityQueryExpressionCriteria y Properties.

Use la propiedad RelationshipType en sus criterios para especificar si desea devolver relaciones ManyToMany o OneToMany.

En la tabla siguiente se enumeran las propiedades de metadatos de relación que no se pueden usar en MetadataFilterExpression:

Recuperar etiquetas

Por último, la propiedad EntityQueryExpression.LabelQuery acepta un LabelQueryExpression que le permite especificar uno o más valores LCID enteros para determinar qué etiquetas localizadas devolver. Los valores de identificadores de configuración regional válidos pueden encontrarse en el gráfico de identificadores de configuración regional (LCID). Si una organización tiene muchos paquetes de idioma instalados, se devolverán las etiquetas para todos los idiomas, a menos que especifique un LabelQuery.

En el ejemplo siguiente se define un LabelQueryExpression que limitará las etiquetas solo a aquellas que representen el idioma preferido de los usuarios.



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);

Recuperar metadatos nuevos o modificados

La clase RetrieveMetadataChangesResponse devuelve EntityMetadataCollection con establecimiento inflexible de tipos que contiene los datos solicitados. La RetrieveMetadataChangesResponse clase también proporciona un ServerVersionStamp valor que puedes pasar a la propiedad RetrieveMetadataChangesRequest.ClientVersionStamp en solicitudes posteriores. Cuando se incluye un valor para la ClientVersionStamp propiedad, solo se devolverán los datos que coincidan con el EntityQueryExpression y que hayan cambiado desde que ClientVersionStamp se recuperaron. La única excepción a esto es cuando su EntityQueryExpression.Properties incluye EntityMetadata.Privileges. Los privilegios siempre se devolverán independientemente del ClientVersionStamp. De este modo, la aplicación puede determinar si se han producido cambios importantes que le interesen desde la última vez que consultó los metadatos. A continuación, puede combinar los metadatos nuevos o modificados en la caché de metadatos persistentes para que la aplicación pueda evitar los problemas de rendimiento con la descarga de metadatos que no necesite.

La HasChanged propiedad proporciona una manera de detectar qué elementos secundarios de un elemento de metadatos han cambiado. Dado que todos los metadatos se devuelven como parte del elemento de metadatos contenedor, cuando la etiqueta de a OptionMetadata ha cambiado, se devuelven las propiedades contenedoras EntityMetadata, AttributeMetadatay OptionSetMetadata . Sin embargo, la HasChanged propiedad será falsa para aquellos que contengan elementos de metadatos. Solo la propiedad OptionMetadataHasChanged será verdadera.

En el ejemplo siguiente se realiza una solicitud inicial definiendo un EntityQueryExpression y ejecutando una solicitud con un ClientVersionStamp valor establecido en null.



//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);

}

Recuperar información sobre los metadatos eliminados

La propiedad RetrieveMetadataChangesResponse.DeletedMetadata devolverá un DeletedMetadataCollection cuando las propiedades ClientVersionStamp y DeletedMetadataFilters se establezcan en el RetrieveMetadataChangesRequest. DeletedMetadataCollection contiene los valores MetadataId de cualquier objeto EntityMetadata, AttributeMetadata o RelationshipMetadataBase que se haya eliminado del sistema en un límite de tiempo. Para obtener más información, consulte Caducidad de metadatos eliminados.

Utilice la DeletedMetadataFilters enumeración con RetrieveMetadataChangesRequest.DeletedMetadataFilters para limitar la información solo a los tipos de metadatos que le interesan. La DeletedMetadataFilters enumeración proporciona las siguientes opciones:

Caducidad de metadatos eliminados

Se realiza un seguimiento de los elementos de metadatos que se eliminan durante un período de tiempo limitado especificado por el Organization.ExpireSubscriptionsInDays valor. De forma predeterminada, este valor es de 90 días. Si el valor RetrieveMetadataChangesRequest.ClientVersionStamp indica que la última consulta de metadatos fue anterior a la fecha de expiración, el servicio producirá un error ExpiredVersionStamp (0x80044352). Cuando recupere datos para actualizar la caché de metadatos existente, siempre debe intentar detectar este error y estar preparado para reinicializar la caché de metadatos con los resultados de una segunda solicitud pasada sin un ClientVersionStamp. El error ExpiredVersionStamp también se lanza cuando los cambios en el servidor, como cambios en el valor ExpireSubscriptionsInDays, afectan el seguimiento preciso de los metadatos eliminados.

En el siguiente ejemplo se pasa ClientVersionStamp y recoge el ExpiredVersionStamp. Si se detecta el error, la caché se reinicializa mediante el envío de una nueva solicitud con el ClientVersionStamp establecido en null.



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;
}

Rendimiento al recuperar metadatos eliminados

Cuando se elimina un elemento de metadatos, se guarda en la base de datos y no en la caché de metadatos de Dynamics 365 Customer Engagement. Aunque los metadatos eliminados se limitan solo al MetadataId y el tipo de elemento de metadatos, el acceso a la base de datos es una operación que requerirá más recursos del servidor que solo consultar los cambios.

Consulte también

Escribir aplicaciones y extensiones de servidor
Uso sin conexión de los servicios de Dynamics 365 Customer Engagement
Ejemplo: consultar metadatos y detectar cambios
Ampliar el modelo de metadatos para Dynamics 365 Customer Engagement
Personalizar los metadatos de la entidad
Personalizar metadatos de atributos de entidad
Personalizar los metadatos de la relación de entidad