After Update in Apex Class - Total Contacts "Roll-Up Summary"

552 views Asked by At

I added the Apex Class and Apex trigger below to update the field Number_of_Contacts at the Account level when a Contact is added or removed to a certain Account.

My idea is to display in Accounts reports, how many Contacts an Account has. I had to do this, because Salesforce doesn't provide a Roll-Up Summary, at the Account level, to count Contacts.

I also tried creating a Flow, but it only works when a Contact is created or deleted.

Here are Apex Class and Trigger I tried to use:

Class:

public without sharing class  ContactTriggerHandler {
    
   private Set<Id> getAccountIds(List<Contact> contacts) {
       
       Set<Id> accountIds = new Set<Id>();
       
        for(Contact c : contacts) {
            if(c.AccountId != null) {
                accountIds.add(c.AccountId);
            }
        }
        
        return accountIds;
   }
    
   private Map<Id, Account> getAccountMap(Set<Id> accountIds) {
       
       return new Map<Id, Account>([SELECT Id, Number_of_Contacts__c FROM Account WHERE Id in :accountIds]);
   }
   public void process(List<Contact> contacts, System.TriggerOperation operation) {
       
       Set<Id> accountIds = getAccountIds(contacts);
        
        if(accountIds.size() > 0) {
            Map<Id, Account> accountMap = getAccountMap(accountIds);
            
            for(Contact c : contacts) {
                if(accountMap.containsKey(c.AccountId)) {
                    switch on operation{
                        when AFTER_INSERT {
                            accountMap.get(c.AccountId).Number_of_Contacts__c += 1;
                        }
                        when AFTER_DELETE {
                            accountMap.get(c.AccountId).Number_of_Contacts__c -= 1;
                        }
                        when AFTER_UNDELETE {
                            accountMap.get(c.AccountId).Number_of_Contacts__c += 1;
                        }
                    }
                }
            }
            
            update accountMap.values();
        }
       
   }


}

Trigger

trigger ContactTrigger on Contact (after insert, after delete, after undelete) {
    
    ContactTriggerHandler handler = new ContactTriggerHandler();
    switch on Trigger.operationType {
        when AFTER_INSERT {
            handler.process(Trigger.new, Trigger.operationType);
        }
        when AFTER_DELETE {
            handler.process(Trigger.old, Trigger.operationType);
        }
        when AFTER_UNDELETE {
            handler.process(Trigger.new, Trigger.operationType);
        }
    }
    
}

However, how can I include a line of code that updates the Number_of_Contacs__c field when a Contact moves to a different Account (like, an "After_Update" trigger)?

Thank you,

I tried some guidance on how to add AFTER UPDATE triggers in Apex Code, but I didn't succeed.

1

There are 1 answers

3
eyescream On

Trigger context variables give you access to old and new values, state of the database before the user clicked save and what the user has changed. You're passing from trigger to class only trigger.new but to get the id of original account the contact was linked to and update it - something like this.

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

// During update, only if account id changes...
for(Contact c : trigger.new){
    Contact old = trigger.oldMap.get(c.Id);
    if(c.AccountId != old.AccountId){
        idsToCheck.add(c.AccountId);
        idsToCheck.add(old.AccountId); // mark both for further processing
    }
}
idsToCheck.remove(null);

List<Account> accounts = [SELECT Id, (SELECT Id FROM Contacts) FROM Account WHERE Id IN :idsToCheck];
for(Account a : accounts){
    a.Number_of_Contacts__c = a.Contacts.size();
}
update accounts;