-3

When a new Account is created I need to insert 3 contacts. My below syntax work perfectly but I need a solution without a nested loop.

My solution with a nested loop

trigger testAccountTrigger on Account (after insert) {
    
    String existingAccId;
    String existingAccName;
    
    System.debug(Trigger.New);
    
    List<Account> accounts=new List<Account>();

    //NESTED LOOP

    for(Account acc : Trigger.New){
        
        existingAccId=acc.Id;
        existingAccName=acc.Name;              
        
        List<Contact> contacts=new List<Contact>();
        for (Integer index=1; index <= 3;index++) {      
            
            Contact con=new Contact(LastName=existingAccName+' - '+string.valueOf(index),AccountId =existingAccId);
            contacts.add(con);
        }
        if(!contacts.isEmpty())
        {
            INSERT contacts;
        }        
    }  
}
4

The issue isn't the inner loop itself, it's the DML (Insert) inside the loop. Salesforce imposes a number of governor limits on your code, and total number of DML statements executed is one of those limits. The solution is to move the insert outside the outer loop:

trigger testAccountTrigger on Account (after insert) {
    
    List<Contact> contacts=new List<Contact>();

    for(Account acc : Trigger.New) {
        
        String existingAccId=acc.Id;
        String existingAccName=acc.Name;              
        
        for (Integer index=1; index <= 3; index++) {
            
            Contact con=new Contact(LastName=existingAccName+' - '+string.valueOf(index),AccountId =existingAccId);
            contacts.add(con);
        }
    }  

    insert contacts;

}

This is a common pattern in apex development - iterate over your inputs, accumulating records to be inserted/updated/deleted at the end of your processing.

Likewise there is a limit on SOQL queries per transaction. If you need other data from related records, you would commonly iterate the inputs once to gather criteria (like a set of Ids) for a single query (or a few queries, one per object) and store the result in map(s) for use while iterating the input again to actually process it.

2
  • 3
    Note that the if(!contacts.isEmpty()) guard around the dml statement is not required. Salesforce/Apex is smart/kind enough to not consume any DML statements if the list you pass to it is empty (and it appears to be impossible for it to be empty in your example anyway).
    – Derek F
    Aug 27 at 16:00
  • @DerekF Good point, I don't generally use that construction; I missed cleaning it up when rewriting the original. Will update my answer. Aug 27 at 16:09

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.