0

I started apex few months ago currently having some trouble. So my requirement is to populate Sum of Amount of Closed opportunities on Closed_Opportunity_Sum__c field of Primary Contact of Account.

and i am getting Error 'System.ListException: Duplicate id in list' in Apex

specifically in debug log

USER_DEBUG [53]|DEBUG|You got this exception ------------------->Duplicate id in list: 0035g000002d6tvAAA

public class OppclosedSUMHelper 
{
   
 public static void afterClosed(List<Opportunity> newopp){
        
        set<Id> oppAccountId = new Set<Id>();
        List<Contact> updatedCon = new List<Contact>();
        
        for(Opportunity opp : newopp){
            if(opp.AccountId != null){
                oppAccountId.add(opp.AccountId);
            }           
        }
        
        AggregateResult[] amountSum = [select SUM(AMOUNT)add , ID , AccountID , StageName from Opportunity WHERE StageName = 'Closed Won' AND AccountID IN:oppAccountId GROUP BY ID,AccountId,StageName];
        List<contact> conlist = new List<contact>([select Id , AccountId , Closed_Opportunity_Sum__c , Primary_Contact__c From Contact Where Primary_Contact__c = True AND AccountId IN : oppAccountId]);
        
  
        for(Opportunity opp : newopp){ 
            for(AggregateResult arr : amountSum){
                for(Contact con :conlist ){ 
                    if (con.Primary_Contact__c == true && opp.AccountId == con.AccountId){
                        con.AccountId = (Id)arr.get('AccountId');
                        con.Closed_Opportunity_Sum__c = (Decimal)arr.get('add');
                        system.debug('------------------------------------->'+opp.AccountId);                        
                        system.debug('------------------------------------->'+con.AccountId);
                        updatedCon.add(con);
                    }
                }
            }
        }
        
        
        
        try{
            if(!updatedCon.isEmpty()) {
                update updatedCon;
            }
        }
        catch(Exception e) {
            system.debug('You got this exception ------------------->'+e.getMessage());
        }
    }
    
}
1
  • You can cut this down to virtually out of the box by 1) using Roll-Up Summary Field on the Account to automatically represent total amount of closed opportunities 2) Flow or Workflow to copy the value of the roll-up field to primary Contact
    – identigral
    Jul 8, 2021 at 16:21

1 Answer 1

0

As per the relationship between account and opportunity, more than one opportunity can have the same account linked, so

  // cosider this list have 2 opportunities with the same accountid say combination is Opp1 : Acc1, Opp2 : Acc1
        
        for(Opportunity opp : newopp){ 
            
            // you could have reduced this loop by adding the query result in a map
            
            for(AggregateResult arr : amountSum){
                
                // conlist list have all the contacts related to all accounts relate to opportunities in the newopp variable
                
                for(Contact con :conlist){ 
                    
                    // Iteration 1: ran for Opp1 opportunity, processed the primary contact of Acc1 and added to updatedCon list. 
                    // Iteration 2: ran for Opp2 opportunity, processed the primary contact of Acc1 and added to updatedCon list. 
                    // This is how same contact got added to updatedCon list.
                    
                    if (opp.AccountId == con.AccountId){
                        con.AccountId = (Id)arr.get('AccountId');
                        //con.Closed_Opportunity_Sum__c = (Decimal)arr.get('add');
                        system.debug('------------------------------------->'+opp.AccountId);                        
                        system.debug('------------------------------------->'+con);
                        updatedCon.add(con);
                    }
                }
            }
        }

Since updatedCon is a list type variable, the same contact record is getting added to the list more than once. To avoid this, one quick solution can be to use Map type variable instead of a List type.

Map<Id, contact> updatedCon = new Map<Id, contact>();

then inside the loop, add the following condition to check if a contact record does not already exists in the Map, only then add the contact to map

if(!updatedCon.containsKey(con.id))
    updatedCon.put(con);

and for the DML operation, update

if(!updatedCon.isEmpty()) { update updatedCon; }

to this

if(!updatedCon.isEmpty()) {
    update updatedCon.values();
}

Your code can be optimized using maps to reduce the number of nested loops.

0

You must log in to answer this question.

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