6

I know how to compare fields before/after a trigger. But how can I know whether any field has changed or not (or that a user has 'edited' an object without actually editing anything).

It seems a bit much to check every field, especially when an object carries a substantial amount of them.

  • 2
    What reason do you need to know whether ANY field has changed. Maybe with a little more info we could help you come up with another solution. – dphil Oct 29 '14 at 14:28
  • I provided an answer but if you checked every field, including ones that are not edited by the user, you'd get Trigger.New. Fields like LastModifiedDate is always updated, so this comparison would always catch the entire list. – Programmable Medley Oct 29 '14 at 16:52
  • @dphil one reason could be that you don't want to start the save process when nothing has actually changed. – westerforce Nov 20 '14 at 9:50
6

What you'd need to do is something like the following:

mapFieldMapNew = Schema.getGlobalDescribe().get(sObjectName__c').getDescribe().Fields.getMap();
String key = ' '; 
String value = ' '; 
mapLabelToFieldsObj = new Map<String,String>();

for(String s : mapFieldMapNew.keySet()) { 
   key = mapFieldMapNew.get(s).getDescribe().getLabel(); 
   value = mapFieldMapNew.get(s).getDescribe().getName();
   if(mapFieldMapNew.get(s).getDescribe().isUpdateable()) mapLabelToFieldsObj.put(key, value); 
}

That would give you a map of all the fields in the sObject that are updatable which you could simply convert to a list or set of field names if you wanted to. You could then use those fields to test to see if anything has changed between trigger.new and trigger.old on those fields.

Although it's implicit, don't forget that you also have the isCreatable attribute for a describe call and could potentially have new records that you'd also want to test for which could exist in trigger.new, but not in trigger.old if your trigger included an afterInsert section.

EDIT

I should add that its also going to be important to know what Type of field each one is. You can't go around and compare certain types of fields with the assumption of an equality either being true or false. You also may need to have try catch blocks to prevent exceptions from being thrown where data exists in say trigger.new, but not trigger.old which could cause a null pointer exception when you try to access it. Those are things you'll want to set up in advance for the field type you're going to compare.

  • This will certainly push me in the right direction, thank you. It is kind of an issue, so I will probably be following up on this. – westerforce Nov 20 '14 at 9:49
2

You could do a quick comparison with a Set operation.

You could simply go:

Set<sObject> oldRecordSet = new Set<sObject>(Trigger.Old.deepClone(true, true, true));

oldRecordSet.removeAll(Trigger.New);
Integer numberOfChanges = oldRecordSet.size();

If the number is 0, there were no changes. Otherwise, you have the number of changes.

If there were changes, you can then get the Ids of the records that did change like this:

Set<Id> changedRecordIdSet = (new Map<Id, sObject>(new List<sObject>(oldRecordSet))).keySet();

I haven't tested it yet, but I believe this will work.

Edit

There's one issue with doing this approach. It will always return Trigger.New if you think about it. Even if you checked all fields that could be editable, there are always fields that will be edited, like the LastModified date.

0

Would something similar to this work for you:

AND(
ISCHANGED( LastModifiedDate ),
$Profile.Name == 'xyz'
)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.