8

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.

3
  • 3
    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, 2014 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. Oct 29, 2014 at 16:52
  • @dphil one reason could be that you don't want to start the save process when nothing has actually changed. Nov 20, 2014 at 9:50

3 Answers 3

7

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.

1
  • 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. Nov 20, 2014 at 9:49
3

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

This may not be super slick but here's how I handled the need to watch if one specific field changed.

// Check if specific field has changed using Trigger.old/Trigger.new data
Integer fieldChangeCount = 0;
for(String nextMyObjectID : Trigger.oldMap.keySet()){
  MyObject oldObject = Trigger.oldMap.get(nextMyObjectID);
  MyObject newObject = Trigger.newMap.get(nextMyObjectID);
  if(oldObject.FieldToWatch__c != newObject.FieldToWatch__c) fieldChangeCount ++;  
}
if(fieldChangeCount > 0){
  // do stuff
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .