Posted in

Create a Rollup-Summary trigger in Salesforce?

Table of Contents

Prerequisite

Create a Custom Field on the Account Object “Number of Contacts” with a Number Data Type that does not have any decimal point in it.

Introduction to Apex Trigger Scenario

Requirement (Roll-up Summary Trigger)
Develop a Solution that will count the related contact related to the Account and store the information in the “Number of Contacts” field.

Note:- The contact can be created/deleted/undeleted and updated from the Account Record. So please keep that in mind

Questions to be asked

Question?

  • Which Object
    • Contact
  • Events
    • after insert, after delete, after undelete, after update
  • Functionality
    • Develop a Solution that will count the related contact related to the Account and store the information in the “Number of Contacts” field.

Hands-On

Apex Trigger

trigger ContactTrigger on Contact (after insert, after update, after delete, after undelete) {
  ContactTriggerDispatcher.dispatch(Trigger.OperationType); 
}

Dispatcher Class

public class ContactTriggerDispatcher {
  public static void dispatch(System.TriggerOperation operationType) {
    switch on operationType {
      WHEN AFTER_INSERT {
        ContactTriggerHandler.handleAfterInsert((Map < Id,
          Contact > ) Trigger.newMap); // Map<Id, sObject>
      }
      WHEN AFTER_UPDATE {
        ContactTriggerHandler.handleAfterUpdate((Map < Id,
          Contact > ) Trigger.newMap, (Map < Id, Contact > ) Trigger.oldMap);
      }
      WHEN AFTER_DELETE {
        ContactTriggerHandler.handleAfterDelete((Map < Id,
          Contact > ) Trigger.oldMap);
      }
      WHEN AFTER_UNDELETE {
        ContactTriggerHandler.handleAfterUndelete((Map < Id,
          Contact > ) Trigger.newMap); // Map<Id, sObject>
      }
    }
  }
}

 

Handler Class

public class ContactTriggerHandler {
  public static void handleAfterInsert(Map < Id, Contact > newRecordsMap) {
    ContactTriggerHelper.countContact(newRecordsMap);
  }
  public static void handleAfterUndelete(Map < Id, Contact > newRecordsMap) {
    ContactTriggerHelper.countContact(newRecordsMap);
  }
  public static void handleAfterDelete(Map < Id, Contact > oldRecordsMap) {
    ContactTriggerHelper.countContact(oldRecordsMap);
  }
  public static void handleAfterUpdate(Map < Id, Contact > newRecordsMap,
    Map < Id, Contact > oldRecordsMap) {
    Set < Id > accountIdsSet = new Set < Id > ();
    for (Contact newRecord: newRecordsMap.values()) {
      Contact oldRecord = oldRecordsMap.get(newRecord.Id);
      if (oldRecord.AccountId < > newRecord.AccountId) {
        accountIdsSet.add(oldRecord.AccountId); // ABC
        accountIdsSet.add(newRecord.AccountId); // XYZ
      }
    }
    List < AggregateResult > aggregateList = [SELECT count(Id), AccountId
      FROM Contact
      WHERE AccountId IN: accountIdsSet
      Group By AccountId
    ];

    List < Account > accountListToUpdate = new List < Account > ();
    for (AggregateResult ag: aggregateList) {
      String accountId = (String) ag.get('AccountId'); // Object
      Integer totalContact = (Integer) ag.get('expr0'); // Object
      Account accountRecord = new Account();
      accountRecord.Id = accountId;
      accountRecord.Number_of_Contacts__c = totalContact;
      accountListToUpdate.add(accountRecord);
    }
    update accountListToUpdate;
  }
}

Helper Class

public class ContactTriggerHelper {
  public static void countContact(Map < Id, Contact > newRecordsMap) {
    // key - RecordId
    // value - Record
    // keySet() - Set<Key> - Set<Id>
    // values() - List<Value> - List<Account>

    /* Step1 - Get Account Ids */
    Set < Id > accountIdsSet = new Set < Id > ();
    for (Contact con: newRecordsMap.values()) {
      if (con.AccountId < > null) { // check if contact is related to account
        accountIdsSet.add(con.AccountId);
      }
    }

    /* Solution #1 - Inner Query
 List<Account> accountList = new List<Account>();
 accountList = [SELECT Id, (SELECT Id FROM CONTACTS) FROM Account
WHERE Id IN: accountIdsSet]; //50K
 for(Account acc : accountList){
 List<CONTACT> contList = acc.CONTACTS; // List of Contact
 if(contList != null){
 Integer size = contList.size();
 acc.Number_of_Contacts__c = size;
 }
 }
 update accountList;
 */

    /* Solution #1 will fail in case of Bulk Records */

    /* Solution #2 - Aggregate Query (Recommended) - SUM, COUNT, MIN, MAX,
AVG */
    /* Aggregate Query - LIMIT 2000 */
    List < AggregateResult > aggregateList = [SELECT count(Id), AccountId
      FROM Contact
      WHERE AccountId IN: accountIdsSet
      Group By AccountId
    ];
    //(AggregateResult:{expr0=3, AccountId=0012w00001Pz63SAAR})
    //(AggregateResult:{totalContact=3, AccountId=0012w00001Pz63SAAR})
    System.debug(aggregateList);
    List < Account > accountListToUpdate = new List < Account > ();
    for (AggregateResult ag: aggregateList) {
      String accountId = (String) ag.get('AccountId'); // Object
      Integer totalContact = (Integer) ag.get('expr0'); // Object
      Account accountRecord = new Account();
      accountRecord.Id = accountId;
      accountRecord.Number_of_Contacts__c = totalContact;
      accountListToUpdate.add(accountRecord);
    }
    update accountListToUpdate;
  }
}

Watch Complete Video

Assignments

→ Apex Trigger 10

Prerequisite
Create the Custom Fields on the Account Object “Sum of Closed Opportunity Amount” & “Sum of Open Opportunity Amount” with a Currency Data Type with 2 Decimal Points.

Requirement (Rollup Summary Trigger)
Develop an Apex trigger to SUM the Opportunity Amount of the Closed Opportunity and Open Opportunities. The closed opportunities are the ones with the Status equal to “Closed Won” OR “Closed Lost”. And store the result in the “Sum of Closed Opportunity Amount” & “Sum of Open Opportunity Amount” fields respectively in the related Account for the opportunity.

Note:- The Opportunity can be created/deleted/undeleted and updated from the Account Record. So please keep that in mind

Scenarios for Update DML

  • The account has been changed
  • The amount has been changed

Resources

Amit Singh aka @sfdcpanther/pantherschools, a Salesforce Technical Architect, Consultant with over 8+ years of experience in Salesforce technology. 21x Certified. Blogger, Speaker, and Instructor. DevSecOps Champion

Discover more from Panther Schools

Subscribe now to keep reading and get access to the full archive.

Continue reading