0

I wrote a trigger but My professor asked me to write it without nested loop and I don't know how to do it. I want to do is when a contact gets created i need to take field named- 'Description' of contact and update it on a field- Description present on the opportunity records (where stage='closed won') associated with the contact's Account Id. so the problem is:

trigger contactTrigger on Contact (before insert) {

    if (trigger.isInsert && trigger.isbefore){

        

        List<Opportunity> optoUpdate=new List<Opportunity>();

        Set<Id> accId =new Set<Id>();

        for(Contact c:trigger.new){

            accId.add(c.AccountId);

        }

        List <Opportunity> oppToUpdate=new List <Opportunity>();

        oppToUpdate=[select AccountId,Description from Opportunity where StageName='Closed Won' and AccountId in :accId];

        Map<Id,List <Opportunity>> testmap=new Map<Id,List<Opportunity>>();

        for(Opportunity op:oppToUpdate){

            if (testmap.containsKey(op.AccountId)){

                testMap.get(op.AccountId).add(op);

            }

            else{

                testmap.put(op.AccountId,new list<Opportunity>{op});

            }

        }

        

        for(Contact c:trigger.new){

            if (testmap.containsKey(c.AccountId)){

                for(opportunity op:testmap.get(c.AccountId)){

                    if(op.description ==''){

                    op.description=c.description;

                    }

                    else{

                       op.description=op.description+c.description; 

                    }

                        

                    optoUpdate.add(op);

                    

                }

            }

        }

        

       update optoUpdate;        

    }

}

Any help would be appriciated.

1 Answer 1

2

The only way to avoid doing this is to pre-concatenate the strings so you don't need to loop over the contacts again. At a basic level, that looks like this:

trigger contactTrigger on Contact (after insert) {
    Map<Id, String> descriptions = new Map<Id, String>();
    for(Contact contactRecord: Trigger.new) {
        // If the contact has a description, we'll put it in the map.
        if(contactRecord.Description != null) {
            String description = descriptions.get(contactRecord.AccountId);
            // Avoids "null" being placed in the description.
            if(description == null) {
                description = '';
            }
            // There may be more than one, so we'll concatenate if so.
            description += contactRecord.Description;
            descriptions.put(contactRecord.AccountId, description);
        }
    }
    // Do not query Opportunity with AccountId = null.
    descriptions.remove(null);
    Opportunity[] opportunitiesToUpdate = [SELECT AccountId, Description FROM Opportunity WHERE AccountId = :descriptions.keySet() AND StageName = 'Closed Won'];
    for(Opportunity opportunityRecord: opportunitiesToUpdate) {
        // Avoid null in the resulting description text.
        if(opportunityRecord.Description == null) {
            opportunityRecord.Description = '';
        }
        opportunityRecord.Description += descriptions.get(opportunityRecord.AccountId);
    }
    update opportunitiesToUpdate;
}

Please note that this fixes a bug in your code. Text fields retrieved from the database will never be an empty string (''), you need to check for null values instead.

Note also how you can update records from the same variable you stored a query from, and some unnecessary logic was removed.

Also, it is generally advisable to only perform updates on related records in an after trigger, not a before trigger. This is because another trigger could modify the contents of a record before you get to read the data, leading to inconsistent results.

3
  • sfdcfox, what is the purpose of descriptions.remove(null); given that you change null values to empty strings before adding them to descriptions ? Feb 8, 2021 at 6:44
  • @EmmanuelBRUNO I do this because I don't want to query Opportunity records with a null AccountId. This could have also been done in the if statement, it's just a matter of preference.
    – sfdcfox
    Feb 8, 2021 at 6:52
  • Of course, Map.remove() removes by key, not by value, my mistake ! Feb 8, 2021 at 8:03

You must log in to answer this question.

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