Wednesday, August 29, 2012

ColumnSet Constructor – Read The Fine Print

Admittedly I have not read the CRM 2011 SDK in its entirety but there are some bits of important information scattered throughout it that can save you some headaches.

Under the heading: ColumnSet Constructor (Boolean)

Important
You should avoid retrieving all columns in a query result because of the impact on a subsequent update of records. In an update, this will set all field values, even if they are unchanged, and often triggers cascaded updates to child records.

Example plugin code:
if (postImageEntity.LogicalName == "incident")
{
    if (postImageEntity.Attributes.Contains("customerid"))
    {
        EntityReference eRef = 
                (EntityReference)postImageEntity.Attributes["customerid"];
        if (eRef.LogicalName == "account")
        {
            Entity e = localContext.OrganizationService.Retrieve(
                eRef.LogicalName, eRef.Id, new ColumnSet(true));
            e.Attributes["description"] = "test";
            localContext.OrganizationService.Update(e);
        }
    }
}
All this should do is update the description field on an Account record that is tied to a case. However what happens if on the Account entity you have a workflow that gets triggered when field value changes other than description? In this scenario, that workflow will get executed unexpectedly because as our important note from the SDK points out; any field that is retrieved will be flagged as changed when performing an update.

So the easy way to prevent this is to not be lazy and actually list the fields you need rather than essentially doing a SELECT * on the entity.

Updated line:
Entity e = localContext.OrganizationService.Retrieve(
     eRef.LogicalName, eRef.Id, new ColumnSet("description"));