This question already has an answer here:

I have a scenario where in before update context I want to check a list of fields for changes. Normally I would simply compare the values between newMap and oldMap as such:

for(Record r : Trigger.new)
{
    if(Trigger.oldMap.get(r.Id).thisField__c != Trigger.newMap.get(r.Id).thisField__c) //The field value has been edited in this update
    {perform business logic}
}

It seems to me like this could be a great place to use FieldSets, so that I can easily add or remove fields that I want to check for edits in this loop, but all I can find is FieldSetMember.getFieldPath() which returns a string - that is great for use in a SOQL query, but what about here where I want to directly reference those fields in my apex code?

Is there any way to do this? I had imagined it looking something like this, but I've put ??? where I am at a loss for how to reference the field in question on the record within newMap or oldMap.

List<FieldSetMember> fieldsToCheck = Schema.SObjectType.Object.fieldSets.Fields_To_Check.getFields();

for(Record r : Trigger.new)
{
    for(FieldSetMember fsm : fieldsToCheck)
    {
        if(Trigger.oldMap.get(r.Id).??? != Trigger.newMap.get(r.Id).???) //The field value has been edited in this update
        {perform business logic}
    }
}

marked as duplicate by Adrian Larson apex Sep 21 '17 at 19:17

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

You want the getFieldPath method:

for (FieldSetMember member : fieldsToCheck)
{
    String field = member.getFieldPath();
}

As for how to get a field's value when you have its name as a string, you would use the generic SObject.get method:

for (MyObject__c record : trigger.new)
{
    for (FieldSetMember member : fieldsToCheck)
    {
        Object newValue = record.get(member.getFieldPath());
    }
}

Note also that you are injecting quite a bit of inefficiency by calling trigger.newMap.get(r.Id). That gives you the same exact variable as r.

for (MyObject__c record : trigger.new)
{
    for (FieldSetMember member : fieldsToCheck)
    {
        String field = member.getFieldPath();
        if (record.get(field) != trigger.oldMap.get(record.Id).get(field))
        {
            // do stuff
        }
    }
}

Also, I highly recommend you look into using the Selector library. With it, you can simply do something like:

for (String member : fieldsToCheck)
{
    List<MyObject__c> changedRecords = Select.Field.hasChanged(member.getFieldPath())
        .filter(trigger.new, trigger.oldMap);
    // operate on this collection of records
    // containing only those whose value has changed
    // in the specific field in question
}
  • Oops sorry, I meant to mention getFieldPath() rather than getLabel() - will edit my post above. However, I still don't see how I can use that where i have ??? in my second code block. – Dupe_jockey Sep 21 '17 at 19:11
  • Thanks for the clarification - I see it now. Somehow the SObject.get() method has escaped my awareness all this time -_-. – Dupe_jockey Sep 21 '17 at 19:15

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