Monday, December 15, 2014

Updating SDK.Metadata.Query to Sdk.Soap.js

If you've done any JavaScript work in Dynamics CRM in the past few years and needed to get access to entity and attribute metadata there is a good chance you used the the SDK.Metadata.Query sample code from the CRM 2011 SDK to do so. This code as is stands breaks in CRM 2015. Instead of working through any issues trying to update that code we can now use the Sdk.Soap.js library to accomplish the same result with minimal changes to existing code.

In your previous code you used SDK.Metadata.Query.js and your code probably looked something like this:

var mdq = SDK.Metadata.Query;
var semp = mdq.SearchableEntityMetadataProperties;
var samp = mdq.SearchableAttributeMetadataProperties;
var emp = mdq.EntityMetadataProperties;
var amp = mdq.AttributeMetadataProperties;

var entityFilter = new mdq.MetadataFilterExpression(mdq.LogicalOperator.And);
entityFilter.addCondition(semp.LogicalName, mdq.MetadataConditionOperator.Equals, "account");
var entityProperties = new mdq.MetadataPropertiesExpression(false, [emp.Attributes, emp.SchemaName,
    emp.ManyToManyRelationships, emp.ManyToOneRelationships, emp.OneToManyRelationships]);
var attributesFilter = new mdq.MetadataFilterExpression(mdq.LogicalOperator.And);
attributesFilter.addCondition(samp.AttributeType, mdq.MetadataConditionOperator.NotEquals, "Virtual");
var attributeProperties = new mdq.MetadataPropertiesExpression(false, [amp.DisplayName,
    amp.AttributeType, amp.OptionSet, amp.SchemaName]);
var relationshipFilter = new mdq.MetadataFilterExpression(mdq.LogicalOperator.And);
relationshipFilter.addCondition(samp.IsValidForAdvancedFind, mdq.MetadataConditionOperator.Equals, true);
var relationshipProperties = new mdq.MetadataPropertiesExpression(true, [emp.ManyToManyRelationships,
    emp.ManyToOneRelationships, emp.OneToManyRelationships]);
var labelQuery = new mdq.LabelQueryExpression([Xrm.Page.context.getUserLcid()]);

var query = new mdq.EntityQueryExpression(
    entityFilter,
    entityProperties,
    new mdq.AttributeQueryExpression(attributesFilter, attributeProperties),
    new mdq.RelationshipQueryExpression(relationshipFilter, relationshipProperties),
    labelQuery);

var request = new mdq.RetrieveMetadataChangesRequest(query);
mdq.RetrieveMetadataChanges(
    request,
    RetrieveMetadataChangesRequest_Callback,
    function (error) {
        alert(error.message);
    });

The equivalent Sdk.Soap.js code is almost identical, just a few minor differences. You would need to include both Sdk.Soap.js  as well as Sdk.RetrieveMetadataChanges.js from the available messages.

Obviously references to SDK.Metadata.Query will need to be replaced with Sdk.Mdq. Beyond that instead of calling RetrieveMetadataChanges as you did in the past you'll substitute one the methods from Sdk.Soap.js such as Sdk.Async.execute with the same parameters and you're in business.
var mdq = Sdk.Mdq;
var semp = mdq.SearchableEntityMetadataProperties;
var samp = mdq.SearchableAttributeMetadataProperties;
var emp = mdq.EntityMetadataProperties;
var amp = mdq.AttributeMetadataProperties;

var entityFilter = new mdq.MetadataFilterExpression(mdq.LogicalOperator.And);
entityFilter.addCondition(semp.LogicalName, mdq.MetadataConditionOperator.Equals, "account");
var entityProperties = new mdq.MetadataPropertiesExpression(false, [emp.Attributes, emp.SchemaName,
    emp.ManyToManyRelationships, emp.ManyToOneRelationships, emp.OneToManyRelationships]);
var attributesFilter = new mdq.MetadataFilterExpression(mdq.LogicalOperator.And);
attributesFilter.addCondition(samp.AttributeType, mdq.MetadataConditionOperator.NotEquals, "Virtual");
var attributeProperties = new mdq.MetadataPropertiesExpression(false, [amp.DisplayName,
    amp.AttributeType, amp.OptionSet, amp.SchemaName]);
var relationshipFilter = new mdq.MetadataFilterExpression(mdq.LogicalOperator.And);
relationshipFilter.addCondition(samp.IsValidForAdvancedFind, mdq.MetadataConditionOperator.Equals, true);
var relationshipProperties = new mdq.MetadataPropertiesExpression(true, [emp.ManyToManyRelationships,
    emp.ManyToOneRelationships, emp.OneToManyRelationships]);
var labelQuery = new mdq.LabelQueryExpression([Xrm.Page.context.getUserLcid()]);

var query = new mdq.EntityQueryExpression(
    entityFilter,
    entityProperties,
    new mdq.AttributeQueryExpression(attributesFilter, attributeProperties),
    new mdq.RelationshipQueryExpression(relationshipFilter, relationshipProperties),
    labelQuery);

var request = new Sdk.RetrieveMetadataChangesRequest(query, null, null);
Sdk.Async.execute(request,
    RetrieveMetadataChangesRequest_Callback,
    function (error) {
        alert(error.message);
    });

That was fairly painless :)