Rollup Summary for Lookup relationship in Salesforce

We know that we can create rollup summary fields for master-detail relationships on salesforce platform. But, there might be a situation where we need rollup summary details for lookup relationship as well. There is no out-of-the-box functionality for this scenario and we have to implement a custom solution for it. Also, this is the most common scenario question asked in salesforce code challenges.

We have four types of rollup summary i.e., COUNT, SUM, MIN, MAX. Let's go through an example for COUNT rollup summary type for lookup relation. As every salesforce org comes up with Account and Contact standard objects by default, I am going to use these objects in this example.

Scenario: Display total number of Contacts associated to an Account on Account record.

Solution:

  1. Create a number field TotalContacts__c on the Account object.
  2. Create a trigger on Contact object.
  3. As we are going to update the count on Account object, include after trigger contexts in the contact's trigger. Valid trigger contexts are: after insert, after update, after delete and after undelete.
  4. Implement the logic to update the total number of contacts on the associated Account record.

Assuming there is a trigger framework already in place, call our method from contexts shown below.

//After Insert, After Undelete
handleAfterInsert(){
    ContactTriggerHandler.rollupContactsToAccount(Trigger.new, null);
}

//After Update
handleAfterUpdate(){
    ContactTriggerHandler.rollupContactsToAccount(Trigger.new, Trigger.oldMap);
}

//After Delete
handleAfterDelete(){
    ContactTriggerHandler.rollupContactsToAccount(Trigger.old, null);
}

//ContactTriggerHandler.rollupContactsToAccount
public static void rollupContactsToAccount(List<Contact> contacts, Map<Id,Contact> oldMap) {
    Set<Id> accountIds = new Set<Id>();

    for (Contact c : contacts) {
        if (oldMap == null && String.isNotBlank(c.AccountId))
            accountIds.add(c.AccountId);
        else if (oldMap != null && c.AccountId != oldMap.get(c.Id).AccountId) {
            if (String.isNotBlank(oldMap.get(c.Id).AccountId))
                accountIds.add(oldMap.get(c.Id).AccountId);
            if (String.isNotBlank(c.AccountId))
                accountIds.add(c.AccountId);
        }
    }
    if (accountIds.isEmpty())
        return;

    Map<Id, Integer> accountContactCountMap = new Map<Id, Integer>();
    for (AggregateResult ar : [
        SELECT AccountId, COUNT(Id) contCount
        FROM Contact
        WHERE AccountId IN :accountIds
        GROUP BY AccountId
    ]) {
        accountContactCountMap.put((Id) ar.get('AccountId'), (Integer) ar.get('contCount'));
    }

    List<Account> accs2Update = new List<Account>();
    for (Id accId : accountIds) {
        accs2Update.add(
            new Account(
                Id = accId,
                TotalContacts__c = 
                	accountContactCountMap.containsKey(accId) ? accountContactCountMap.get(accId) : 0
            )
        );
    }
    update accs2Update;
}
Post a Comment (0)
Previous Post Next Post