DML error when migrating before insert trigger logic to apex class

apexbefore-triggertrigger

I have a functional simple proof of concept before insert trigger that uses a custom metadata type to translate field values into English that are populated from web forms that exist in multiple language.

I'm now doing the 'right thing' by moving the logic to a class, but running into unexpected issues with this error:

DML statement cannot operate on trigger.new or trigger.old

Other posts suggest instantiating a new record and setting the Id, but that results in another error, presumably bc this is a before insert trigger and the Id does not exist yet.

MISSING_ARGUMENT, Id not specified in an update call

So I find myself stumped – how do I update the fields on the records in trigger.new in a before insert trigger when using an apex class for the logic?

Trigger code

trigger LeadBeforeInsert on Lead (before insert) {
 leadAction.translateVentureNomination(trigger.new);
}

Apex Class (also not sure if i need static methods or not in here, but that is a separate question)

public class leadAction {
    
    static list<Lead_Field_Translation_Mapping__mdt> tmapList = new list<Lead_Field_Translation_Mapping__mdt>([select label,english_value__c, local_value__c from Lead_Field_Translation_Mapping__mdt]);
    static map<string,string> tmap = new map<string,string>();
    
    public leadAction(){        
            for (Lead_Field_Translation_Mapping__mdt ftm : tmapList){
                tmap.put(ftm.local_value__c,ftm.english_value__c);
            }
    }
    
    public static void translateVentureNomination(list<lead> leads){            
        list<lead> updateList = new list<lead>();
        for (lead l : leads){ 
        //+add better error handling        
        if(tmap.get(l.Country_of_Election__c) == null){
            utils_logging.writeToLog('error translating country of election', 'lead before insert trigger');
        }
        else (l.country_of_election__c = tmap.get(l.Country_of_Election__c));

        list<string> tpopList = l.target_population__c.split(';');                
        string tpop = '';
        for(string s : tpopList){
            //system.debug('s = ' + s);            
            tpop += tmap.get(s.trim())+';';    
        }        
        l.target_population__c = tpop;
        updateList.add(l);
    }
        update updateList;
        
        
    }
}

Best Answer

In BeforeTrigger you can change the value of the Lead directly and do not perform DML, as it will be changed. So, in your method, just remove the updateList and the DML statement, and it will work.

Other issue is that the tmap will be empty so you won’t have the right values. You can do your map static (as is) and populate directly in your method instead of in constructor.

Related Topic