Category Archives: Uncategorized

Salesforce: Check if Record Has Been Manually Edited

Published by:

We recently had a requirement in Salesforce that was a little unique. An ongoing automated process would update the associated Contact to a record, however they didn’t want the automated process to do the update if the field had been updated by a human. Makes sense – if someone takes the time to make a manual association of a Contact to a record, then it’s probably better information than the automatic matching algorithm.

As far as I can tell it’s impossible at runtime to know if the edit is due to a UI edit or is coming from code, so that’s out.

Here’s how we made it happen. The idea is to have a “last updated by code” checkbox that will be set by a workflow. But in order for it to know if it’s been updated by code, you need a 2nd checkbox that is only updated in Apex.

First, make two checkboxes on your record:
Contact_Change_Trailing_Lock__c
Contact_Last_Changed_By_Code__c

Set the latter to true by default when a new record is created.

When your code updates the record, set Contact_Change_Trailing_Lock__c = true.

Then, make two workflows.
if(and(Contact_Change_Trailing_Lock__c=false,ischanged(Contact__c)),true,false)
-> Field Update – Contact_Last_Changed_By_Code__c = false

And
if(and(ischanged(Contact_Change_Trailing_Lock__c),Contact_Change_Trailing_Lock__c=true),true,false)
–> Field Update: Contact_Last_Changed_By_Code__c = true
–> Field Update: Contact_Change_Trailing_Lock__c = false

This results in you being able to use the Contact_Last_Changed_By_Code__c checkbox downstream in your logic to know not to overwrite the manual edit.

ISV code aborted the operation.

Published by:

When writing a Microsoft Dynamics CRM plugin, you might come across the dreaded “ISV code aborted the operation” (isvaborted) error – code -2147220891 or 80040265.

In my experience this means the plugin is calling itself. For example, if your plugin fires on change of estimatedvalue on Opportunity, and your plugin updates estimatedvalue, you’re going to get an infinite loop.

Nip it in the bud with this simple line:

if (context.Depth > 1) {
                trace.Trace("Plugin has called itself. Exiting.");
                return;
            }