0

I have written a test class for the below mentioned triggerhandler class but getting the below error after running the tests:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, ContactTrigger: execution of AfterInsert caused by: System.ListException: Duplicate id in list: 0012w000027SKxsAAG
Class.ContactTriggerHandler1.commonFunction: line 42, column 1 Class.ContactTriggerHandler1.afterInsert: line 4, column 1
Trigger.ContactTrigger: line 6, column 1: []

Contact Trigger :

trigger ContactTrigger on Contact (after insert,after update,after delete,after undelete) {
    Switch on Trigger.OperationType { 
        When After_Insert{
            ContactTriggerHandler1.afterInsert(Trigger.new);
        }
        When After_Update{
            ContactTriggerHandler1.afterUpdate(Trigger.new,Trigger.oldMap);
        }
        When After_Delete{
            ContactTriggerHandler1.afterDelete(Trigger.old);
        }
        When After_Undelete{
            ContactTriggerHandler1.afterUndelete(Trigger.new);
        } 
    }
}

Contact Trigger Handler:

public class ContactTriggerHandler1 {
    
    Public Static Void afterInsert(List<Contact> newContacts){
       ContactTriggerHandler1.commonFunction(newContacts);
    }
    
    Public Static Void afterUpdate(List<Contact> newContacts,Map<Id,Contact> oldContactsMap){
          List<Contact> contactList = new List<Contact>();
        for(Contact c: newContacts){
            if((c.Active__c == True && oldContactsMap.get(c.Id).Active__c==False) ||
                (c.Active__c == false && oldContactsMap.get(c.Id).Active__c==True) && !String.IsEmpty(c.AccountId)){
                    contactList.add(c);
            }
            if(c.Active__c == True && (c.AccountId != oldContactsMap.get(c.Id).AccountId)){
                contactList.add(c);
            }
        }
    ContactTriggerHandler1.commonFunction(contactList);
      }
    
    Public Static Void afterDelete(List<Contact> oldContacts){
        ContactTriggerHandler1.commonFunction(oldContacts);
    }
    
    Public Static Void afterUndelete(List<Contact> newContacts){
       ContactTriggerHandler1.commonFunction(newContacts);
    } 
    
    //This common functions holds the common code to be utilized in the above methods
Public Static Void commonFunction(List<Contact> conts){
     List<Account> accountList = new List<Account>();
        For(Contact c : conts){
           if(!String.IsEmpty(c.AccountId)){
                //Account act = [Select Id,Active_Contacts__c From Account where Id = :c.AccountId];
                List<AggregateResult> agr =[Select Count(Id) From Contact where AccountId = :c.AccountId and Active__c=True];
                Integer ActiveContacts = Integer.valueOf(agr.get(0).get('expr0'));
                Account act = new Account(Id= c.AccountId,Active_Contacts__c=ActiveContacts);
                accountList.add(act);
            }
        }
            Update accountList; 
}

Contact trigger handler test class:

@isTest

public with sharing class ContactTriggerHandlerTest {
    
    @isTest
    Public Static Void afterInsertTest(){
        
        //Testing when the contacts are present related to account but inactive
        List<Account> accountToInsert = new List<Account>();
          accountToInsert.add(new Account(Name = 'TestAccount1'));
          accountToInsert.add(new Account(Name = 'TestAccount2'));
          accountToInsert.add(new Account(Name = 'TestAccount3'));
        Insert accountToInsert;
        
        List<Contact> contactToInsert = new List<Contact>();
            contactToInsert.add(new Contact(AccountId=accountToInsert.get(0).id,LastName='TestContact1'));
            contactToInsert.add(new Contact(AccountId=accountToInsert.get(1).id,LastName='TestContact2'));
            contactToInsert.add(new Contact(AccountId=accountToInsert.get(0).id,LastName='TestContact3'));
            contactToInsert.add(new Contact(AccountId=accountToInsert.get(0).id,LastName='TestContact4'));
        Insert contactToInsert;
        
        List<Account> accountValidation =[Select Name,Active_Contacts__c FROM Account];
        System.assertEquals(3,accountValidation.size());
    }
}

Can any one please help me resolve the above mentioned error?

Edit: I have updated the code that is code is bulkified and I am not facing the issue now.

//This common functions holds the common code to be utilized in the above methods
Public Static Void commonFunction(List<Contact> conts){
    List<Account> accountList = new List<Account>();
    //Now I have moved query outside the loop and bulkified the code
    List<AggregateResult> agrResult =[SELECT count(Id), AccountId FROM Contact 
                                     where Active__c = true 
                                     GROUP BY AccountId];
    For(AggregateResult agr :agrResult ){
        Integer ActiveContacts = Integer.valueOf(agr.get('expr0'));  
        Account act = new Account(Id= String.valueof(agr.get('AccountId')), Active_Contacts__c = ActiveContacts);
        accountList.add(act);
    } 
    Update accountList;  
}
5
  • I don't think that's the problem you should really be focusing on. Have a look into bulkification best practices and you'll be in a much better place to work this out.
    – Nick C
    Commented Feb 23 at 6:15
  • @NickC could please let me know where my code is not bulkified or needs to be bulkified? Actually I am new salesforce development and I am trying to learn Commented Feb 23 at 6:51
  • You do an aggregate query for Account in a loop on Contact. This is where you also do not consider that multiple contacts may have the same account, which is what causes your error. Solving the bulkification should sort the duplicate error.
    – Phil W
    Commented Feb 23 at 7:07
  • Thanks @PhilW I have updated the code and it has resolved the issue. I have updated the code please do let me know if there is any place where it can be improved Thanks in advance Commented Feb 23 at 16:32
  • Restrict the aggregate query to only consider Contacts in your set of required Contacts. There are apparently some performance issues using something like Id IN :conts, so when you add this restriction (in the WHERE clause, using AND), use something like Id IN :new Map<Id, Contact>(conts).keySet().
    – Phil W
    Commented Feb 23 at 16:42

1 Answer 1

-1

The error you're encountering, "duplicate id in the list," which occurs when ur list of accounts having multiple records with the same account ID that's supposed to contain unique Account recordIds.

updated your code as below.

public static void commonFunction(List conts) { // Map to hold the aggregated count of active contacts per AccountId Map<Id, Integer> activeContactCountMap = new Map<Id, Integer>();

// Aggregate active contacts count per AccountId
for (AggregateResult agr : [SELECT COUNT(Id) activeContactsCount, AccountId 
                            FROM Contact 
                            WHERE Active__c = true 
                            GROUP BY AccountId]) {
    Id accountId = (Id) agr.get('AccountId');
    Integer activeContacts = (Integer) agr.get('activeContactsCount');
    
    activeContactCountMap.put(accountId, activeContacts);
}

// Query existing Account records to update
List<Account> accountsToUpdate = [SELECT Id, Active_Contacts__c 
                                  FROM Account 
                                  WHERE Id IN :activeContactCountMap.keySet()];

// Update existing Account records with active contact count
for (Account acc : accountsToUpdate) {
    acc.Active_Contacts__c = activeContactCountMap.get(acc.Id);
}

// Perform update on Account records
if (!accountsToUpdate.isEmpty()) {
    update accountsToUpdate;
}

}

1
  • I feel that this answer misses the point. Grouping by the AccountId in the main query means the accountIds in the results are unique. It also wastes a query (if you have the Id of an SObject, there is no need to query for it). Checking if a list is empty before performing DML is also poor practice (you don't need to do it, DML on an empty list is a no-op and won't count against governor limits).
    – Derek F
    Commented Mar 10 at 13:44

You must log in to answer this question.

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