Recuperar e detectar alterações nos metadados

 

Publicado: janeiro de 2017

Aplicável a: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online

As classes no namespace Microsoft.Xrm.Sdk.Metadata.Query e as classes RetrieveMetadataChangesRequest e RetrieveMetadataChangesResponse permitem que você crie metadados e consultas eficientes e que você capture alterações nos metadados, à medida que elas ocorrem.

Todos os exemplos de código referenciados neste documento estão localizados em Exemplo: Consultar metadados e detectar alterações.

O artigo técnico Metadados de consulta usando o JavaScript fornece uma biblioteca JavaScript para usar os objetos e mensagens no código do lado cliente.

Neste tópico

Estratégias para usar metadados

Recupere apenas os metadados de que você precisa

Recuperar metadados novos ou alterados

Recuperar informações sobre metadados excluídos

Estratégias para usar metadados

Os metadados permitem que você crie aplicativos que se adaptam, se o modelo de dados de Microsoft Dynamics 365 for alterado. Os metadados são importantes para os seguintes tipos de aplicativo:

  • IU para aplicativos clientes

  • Ferramentas de integração que precisam mapear dados de Dynamics 365 para sistemas externos

  • Ferramentas de desenvolvimento

Usando as classes no namespace Microsoft.Xrm.Sdk.Metadata.Query, é possível implementar os designs que ficarão em algum lugar entre uma consulta simples e um cache de metadados persistente.

Consulta simples

Um exemplo de uma consulta simples é quando você tem uma IU de recursos personalizados da Web que fornece um controle de seleção para exibir as opções atuais em um atributo de conjunto de opções (lista de seleção) do Microsoft Dynamics 365. Você não deseja embutir essa opções no código porque seria necessário atualizar o código, caso as opções disponíveis fossem alteradas. Em vez disso, é possível criar uma consulta apenas para recuperar os valores e rótulos das opções para os metadados.

Não é necessário armazenar esses dados em cache, porque você pode usar as classes de Microsoft.Xrm.Sdk.Metadata.Query para recuperar esses dados diretamente a partir do cache do aplicativo do Microsoft Dynamics 365.

Cache de metadados persistentes

Se você tiver um aplicativo que possa funcionar enquanto estiver desconectado do servidor do Microsoft Dynamics 365, ou que for sensível à largura de banda de rede limitada entre o cliente e o servidor, como um aplicativo móvel, você deverá implementar um cache de metadados persistentes.

Com um cache de metadados persistentes, seu aplicativo terá que consultar todos os metadados necessários ao ser conectado pela primeira vez. Em seguida, você salvará os dados no aplicativo. Na próxima vez que o aplicativo se conectar ao servidor, você poderá recuperar apenas a diferença desde sua última consulta, que deverá ter bem menos dados a transmitir e, então, mesclar as alterações em seu cache de metadados quando o aplicativo estiver carregando.

A frequência com que você deve sondar as alterações nos metadados depende da volatilidade esperada dos metadados e do tempo restante de execução do aplicativo. Não há eventos disponíveis a serem usados para detectar o momento em que as alterações nos metadados ocorrem. Há um limite quanto ao número de dias em que as alterações nos metadados excluídos ficam salvas, e uma solicitação de alterações que ocorre após esse limite exige uma reinicialização completa do cache de metadados. Para obter mais informações, consulte Expiração de metadados excluídos.

Quando não há alterações, a consulta deve responder rapidamente e não há nenhum dado para transmitir de volta. Entretanto, se houver alterações, principalmente se houver itens excluídos dos metadados que precisem ser removidos do cache, você poderá esperar que a solicitação demore mais para ser concluída.Para obter mais informações:Desempenho para recuperar metadados excluídos

Recupere apenas os metadados de que você precisa

Os metadados são recuperados ou sincronizados com frequência quando um aplicativo é inicializado e podem afetar o tempo necessário para que o aplicativo seja carregado. Isso é especialmente verdadeiro no caso dos aplicativos móveis que recuperam metadados pela primeira vez. Recuperar apenas os metadados dos quais você precisa é muito importante para criar um aplicativo de bom desempenho.

A classe de EntityQueryExpression fornece uma estrutura consistente com a classe de QueryExpression usada para criar consultas complexas, a fim de recuperar os dados de entidade. Ao contrário das classes RetrieveAllEntitiesRequest, RetrieveEntityRequest, RetrieveAttributeRequest ou RetrieveRelationshipRequest, a classe RetrieveMetadataChangesRequest contém um parâmetro Query que aceita uma instância de EntityQueryExpression, que pode ser usada para especificar critérios específicos para que os dados retornem, além das propriedades que você deseja. Você pode usar RetrieveMetadataChangesRequest para retornar o conjunto completo de metadados obtido ao usar o RetrieveAllEntitiesRequest, ou apenas um rótulo para um atributo específico.

Especifique seus critérios de filtro

A propriedade EntityQueryExpression.Criteria aceita um MetadataFilterExpression com um conjunto de objetos de MetadataConditionExpression que permitem definir condições para filtrar propriedades de entidade com base no valor. Essas condições utilizam um MetadataConditionOperator que permite que os operadores a seguir:

O MetadataFilterExpression também inclui um LogicalOperator para representar a aplicação de And ou a lógica de Or ao avaliar as condições.

Nem todas as propriedades podem ser usadas como critérios de filtragem. Somente as propriedades que representam tipos simples de dados, enumerações, BooleanManagedProperty ou os tipos AttributeRequiredLevelManagedProperty podem ser usadas em MetadataFilterExpression. Quando um BooleanManagedProperty ou um AttributeRequiredLevelManagedProperty é especificado, somente a propriedade Value é avaliada.

A tabela a seguir lista as propriedades de EntityMetadata que não podem ser usadas em MetadataFilterExpression:

Attributes

Description

DisplayCollectionName

DisplayName

ManyToManyRelationships

ManyToOneRelationships

OneToManyRelationships

Privileges

O exemplo a seguir mostra uma MetadataFilterExpression que retornará um conjunto de entidades de propriedade do usuário e que não se cruzam, não incluídas em uma lista de entidades a serem excluídas:



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


' An array SchemaName values for non-intersect, user-owned entities that should not be returned.
                  Dim excludedEntities() As String =
                      {
                          "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.
Dim EntityFilter As 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))
Dim isVisibileInMobileTrue As New MetadataConditionExpression("IsVisibleInMobile", MetadataConditionOperator.Equals, True)
EntityFilter.Conditions.Add(isVisibileInMobileTrue)

Especifique as propriedades que deseja

A propriedade Properties aceita uma MetadataPropertiesExpression. Você pode definir MetadataPropertiesExpression.AllProperties como true para retornar todas as propriedades, ou você pode fornecer um conjunto de cadeias de caracteres para MetadataPropertiesExpression.PropertyNames se quiser definir as propriedades que deseja incluir nos resultados.

Os objetos fortemente tipados que foram retornados incluirão todas as propriedades, mas apenas aquelas que você solicitar terão dados. Todas as outras propriedades serão nulas, com as poucas exceções a seguir: cada item de metadados incluirá os valores de MetadataId ,LogicalName e valores de HasChanged, se eles existirem para esse item. Não é necessário especificá-los nas Properties solicitadas por você.

Se você não estiver usando o código gerenciado e estiver, na verdade, analisando o responseXML retornado de XMLHttpRequest, você receberá elementos para cada propriedade, mas apenas aquelas solicitadas por você conterão dados. O XML a seguir mostra o xml dos metadados da entidade de contato que serão retornadas quando IsVisibleInMobile for a única propriedade 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>

Em uma versão futura, uma eficiência maior poderá ser atingida ao deixar de retornar elementos de valores nulos para propriedades que não foram solicitadas. Se você escrever um código para analisar este XML, provavelmente o XML retornado para a mesma consulta poderá ser reduzido para apenas o XML a seguir.

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

Os metadados são retornados em uma estrutura hierárquica, da mesma forma que ao usar RetrieveAllEntitiesRequest. Para acessar um atributo ou relacionamento específico, crie uma consulta que retorne a entidade da qual façam parte. Para recuperar dados sobre um atributo específico, inclua a propriedade EntityMetadata.Attributes em seu EntityQueryExpression.Properties. Para que os relacionamentos de entidades sejam retornados, você deve incluir uma ou mais das seguintes propriedades de EntityMetadata: ManyToManyRelationships, ManyToOneRelationships ou OneToManyRelationships.

O exemplo a seguir retornará a propriedade de Attributes para as 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" });

'A properties expression to limit the properties to be included with entities
Dim EntityProperties As New MetadataPropertiesExpression() With {.AllProperties = False}
EntityProperties.PropertyNames.AddRange(New String() { "Attributes" })

Recuperar metadados do atributo

A propriedade EntityQueryExpression.AttributeQuery aceita um AttributeQueryExpression que define Criteria e Properties para que atributos sejam retornados para as entidades que correspondem à EntityQueryExpressionCriteria e Properties.

A tabela a seguir lista as propriedades de AttributeMetadata que não podem ser usadas em um MetadataFilterExpression

Description

DisplayName

OptionSet

Targets

O exemplo a seguir limitará os atributos retornados aos que têm um OptionSet apenas, e só retornará as propriedades de OptionSet e AttributeType para esses 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");

'A condition expresson to return optionset attributes
                  Dim optionsetAttributeTypes() As 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
Dim AttributeFilter As New MetadataFilterExpression(LogicalOperator.Or)
AttributeFilter.Conditions.AddRange(optionsetAttributeTypes)

'A Properties expression to limit the properties to be included with attributes
Dim AttributeProperties As New MetadataPropertiesExpression() With {.AllProperties = False}
AttributeProperties.PropertyNames.Add("OptionSet")
AttributeProperties.PropertyNames.Add("AttributeType")

Recuperar metadados de relacionamento

A propriedade EntityQueryExpression.RelationshipQuery aceita RelationshipQueryExpression para especificar o relacionamento de entidade Criteria e Properties que você deseja para as entidades que correspondem a EntityQueryExpressionCriteria e Properties.

Use a propriedade RelationshipType em seus critérios para especificar se deseja retornar relacionamentos de ManyToMany ou de OneToMany.

A tabela a seguir lista as propriedades de metadados de relacionamento que não podem ser usadas em MetadataFilterExpression:

OneToManyRelationshipMetadata.AssociatedMenuConfiguration

OneToManyRelationshipMetadata.CascadeConfiguration

ManyToManyRelationshipMetadata.Entity1AssociatedMenuConfiguration

ManyToManyRelationshipMetadata.Entity2AssociatedMenuConfiguration

Recuperar rótulos

Por fim, a propriedade EntityQueryExpression.LabelQuery aceita um LabelQueryExpression que permite a você especificar um ou mais valores inteiros de LCID, para determinar quais rótulos localizados retornar.Os valores de ID de localidade válidos podem ser encontrados em Gráfico de LCID (ID de localidade). Se uma organização tiver muitos pacotes de idioma instalados, os rótulos para todos os idiomas serão retornados, a menos que você especifique um LabelQuery.

O exemplo a seguir define um LabelQueryExpression que limitará os rótulos a apenas aqueles que representam o idioma da preferência dos usuários.


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

Private _userId As Guid
Private _languageCode As Integer
_userId = (CType(_service.Execute(New WhoAmIRequest()), WhoAmIResponse)).UserId
_languageCode = RetrieveUserUILanguageCode(_userId)
 Protected Function RetrieveUserUILanguageCode(ByVal userId As Guid) As Integer
  Dim userSettingsQuery As New QueryExpression("usersettings")
  userSettingsQuery.ColumnSet.AddColumns("uilanguageid", "systemuserid")
  userSettingsQuery.Criteria.AddCondition("systemuserid", ConditionOperator.Equal, userId)
  Dim userSettings As EntityCollection = _service.RetrieveMultiple(userSettingsQuery)
  If userSettings.Entities.Count > 0 Then
Return CInt(Fix(userSettings.Entities(0)("uilanguageid")))
  End If
  Return 0
 End Function
'A label query expression to limit the labels returned to only those for the user's preferred language
Dim labelQuery As New LabelQueryExpression()
labelQuery.FilterLanguages.Add(_languageCode)

Recuperar metadados novos ou alterados

A classe de RetrieveMetadataChangesResponse retorna um EntityMetadataCollection fortemente tipado que contém os dados solicitados. A classe de RetrieveMetadataChangesResponse também fornece um valor de ServerVersionStamp que pode ser passado para a propriedade de RetrieveMetadataChangesRequest.ClientVersionStamp em solicitações posteriores. Quando um valor é incluído para a propriedade de ClientVersionStamp, apenas os dados que corresponderem a EntityQueryExpression e tiverem sido alterados desde a recuperação de ClientVersionStamp serão retornados. A única exceção a isto ocorre nos casos em que seu EntityQueryExpression.Properties incluir EntityMetadata.Privileges. Privilégios serão sempre retornados, independentemente de ClientVersionStamp. Dessa maneira, seu aplicativo pode determinar se alguma alteração importante do seu interesse ocorreu desde a última consulta aos metadados. Então, você pode mesclar quaisquer metadados novos ou modificados no cache persistente de metadados, assim, seu aplicativo poderá evitar problemas de desempenho durante a transferência de metadados possivelmente desnecessários.

A propriedade HasChanged oferece uma maneira de detectar quais elementos secundários em um item de metadados foram alterados. Como todos os metadados são retornados como parte do item que contém metadados, quando o rótulo de OptionMetadata foi alterado, o EntityMetadata contido AttributeMetadata e as propriedades de OptionSetMetadata foram retornadas. Entretanto, a propriedade de HasChanged será falsa para esses itens que contêm metadados. Somente a propriedade OptionMetadata.HasChanged será verdadeira.

O exemplo a seguir faz uma solicitação inicial, definindo EntityQueryExpression e executando uma solicitação com uma ClientVersionStamp definida como nula.


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

}

'An entity query expression to combine the filter expressions and property expressions for the query.
                  Dim entityQueryExpression_Renamed As New EntityQueryExpression() With
                      {
                          .Criteria = EntityFilter,
                          .Properties = EntityProperties,
                          .AttributeQuery = New AttributeQueryExpression() With
                                            {
                                                .Criteria = AttributeFilter,
                                                .Properties = AttributeProperties
                                            },
                          .LabelQuery = labelQuery
                      }

'Retrieve the metadata for the query without a ClientVersionStamp
                  Dim initialRequest As RetrieveMetadataChangesResponse =
                      getMetadataChanges(entityQueryExpression_Renamed, Nothing, DeletedMetadataFilters.OptionSet)

Protected Function getMetadataChanges(ByVal entityQueryExpression_Renamed As EntityQueryExpression,
                                      ByVal clientVersionStamp As String,
                                      ByVal deletedMetadataFilter As DeletedMetadataFilters) As RetrieveMetadataChangesResponse
    Dim retrieveMetadataChangesRequest_Renamed As New RetrieveMetadataChangesRequest() With
        {
            .Query = entityQueryExpression_Renamed,
            .ClientVersionStamp = clientVersionStamp,
            .DeletedMetadataFilters = deletedMetadataFilter
        }

    Return CType(_service.Execute(retrieveMetadataChangesRequest_Renamed), RetrieveMetadataChangesResponse)

End Function

Recuperar informações sobre metadados excluídos

A propriedade RetrieveMetadataChangesResponse.DeletedMetadata retornará DeletedMetadataCollection quando as propriedades ClientVersionStamp e DeletedMetadataFilters estiverem definidas em RetrieveMetadataChangesRequest. O DeletedMetadataCollection contém os valores de MetadataId de qualquer EntityMetadata, AttributeMetadata ou objetos de RelationshipMetadataBase que tenham sido excluídos do sistema em um limite de tempo. Para obter mais informações, consulte Expiração de metadados excluídos.

Use a enumeração de DeletedMetadataFilters com RetrieveMetadataChangesRequest.DeletedMetadataFilters para limitar as informações apenas para os tipos de metadados nos quais você tem interesse. A enumeração de DeletedMetadataFilters oferece as opções a seguir.

Você também usará a enumeração de DeletedMetadataFilters como uma chave para que o RetrieveMetadataChangesResponse.DeletedMetadata filtre os valores de GUID encontrados na propriedade RetrieveMetadataChangesResponse. deDeletedMetadata.

Ao criar um cache de metadados, talvez seja preferível usar MetadataId para cada item, assim você poderá identificar os itens excluídos dos metadados e removê-los.

Expiração de metadados excluídos

Todos os itens dos metadados que são excluídos são controlados por tempo limitado, especificado pelo valor de Organization.ExpireSubscriptionsInDays. Por padrão, esse valor corresponde a 90 dias. Se o valor de RetrieveMetadataChangesRequest.ClientVersionStamp indicar que a última consulta de metadados é anterior à data de expiração, o serviço acionará um erro ExpiredVersionStamp (0x80044352). Ao recuperar dados para atualizar qualquer cache de metadados, é preciso sempre tentar capturar este erro e estar preparado para reinicializar seu cache de metadados com os resultados de uma segunda solicitação, passada sem um ClientVersionStamp. O erro ExpiredVersionStamp também é acionado quando alterações no servidor, como as alterações no valor de ExpireSubscriptionsInDays, afetam o controle preciso dos metadados excluídos.

O exemplo a seguir transmite um ClientVersionStamp e captura o ExpiredVersionStamp. Se o erro for capturado, o cache será reinicializado por meio da transmissão de uma nova solicitação com o conjunto ClientVersionStamp para 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;
}

Protected Function updateOptionLabelList(ByVal entityQueryExpression_Renamed As EntityQueryExpression,
                                         ByVal clientVersionStamp As String) As String
    'Retrieve metadata changes and add them to the cache
    Dim updateResponse As RetrieveMetadataChangesResponse
    Try
        updateResponse = getMetadataChanges(entityQueryExpression_Renamed, clientVersionStamp, DeletedMetadataFilters.OptionSet)
        addOptionLabelsToCache(updateResponse.EntityMetadata, True)
        removeOptionLabelsFromCache(updateResponse.DeletedMetadata, True)

    Catch ex As FaultException(Of Microsoft.Xrm.Sdk.OrganizationServiceFault)
        ' Check for ErrorCodes.ExpiredVersionStamp (0x80044352)
        ' Will occur when the timestamp exceeds the Organization.ExpireSubscriptionsInDays value, which is 90 by default.
        'INSTANT VB TODO TASK: There is no VB equivalent to 'unchecked' in this context:
        If ex.Detail.ErrorCode = CInt(&amp;H80044352) Then
            'reinitialize cache
            _optionLabelList.Clear()

            updateResponse = getMetadataChanges(entityQueryExpression_Renamed, Nothing, DeletedMetadataFilters.OptionSet)
            'Add them to the cache and display the changes
            addOptionLabelsToCache(updateResponse.EntityMetadata, True)

        Else
            Throw ex
        End If

    End Try
    Return updateResponse.ServerVersionStamp
End Function

Desempenho para recuperar metadados excluídos

Quando um item de metadados é excluído, ele é salvo no banco de dados, e não no cache de metadados do Microsoft Dynamics 365. Embora os metadados excluídos sejam limitados apenas a MetadataId e ao tipo de item de metadados, acessar o banco de dados é uma operação que exige mais recursos de servidor do que apenas consultar alterações.

Confira Também

Estender o Microsoft Dynamics 365 no servidor
Uso offline dos serviços do Microsoft Dynamics 365
Exemplo: Consultar metadados e detectar alterações
Usar o serviço da Organização com metadados do Dynamics 365
Personalizar metadados da entidade
Personalizar metadados do atributo de entidades
Personalizar metadados do relacionamento entre entidades
Metadados de consulta que utilizam JavaScript

Microsoft Dynamics 365

© 2017 Microsoft. Todos os direitos reservados. Direitos autorais