Example Of A Roll-Up Summary Trigger When The Parent Has A lookup Relationship With The Child

Trigger Scenario:

The following code example illustrates a Roll-Up Summary Apex trigger that updates the parent object “A__c” when a child object “B__c” is either deleted, inserted, updated, or reparented (parent changed from one record to another).

Trigger Functionality:

The trigger initiates by defining a set named “parentIds” to store the Ids of the parent object “A__c.” For insert or undelete actions, the trigger loops through new records, adding non-null parent Ids to the “parentIds” set. Subsequently, the code addresses delete actions by iterating through old records, adding parent Ids to the “parentIds” set for any matching Ids. For update actions, the trigger examines new records to identify changes in the parent Id or value field. If changes are detected, it adds the old parent Id to the “parentIds” set and includes the new parent Id (if not null). Once all parent Ids are added to the “parentIds” set, the trigger creates two maps. The first map stores the child record count for each parent, while the second map accumulates the sum of the value field for all children associated with each parent. A SOQL query is employed to retrieve child records, and the trigger checks if the “parentIds” set contains the parent Id. Subsequently, it increments the record count and the sum of the value field for each parent. Finally, the trigger updates the “Record_Count__c” and “Total__c” fields of the parent object.

Sample Code:

The provided sample trigger code demonstrates field updates similar to Roll-Up Summary fields. It calculates the record count and the total sum of the value field for all related child records, updating the corresponding fields of the parent object.

// Trigger to update the Total__c and Record_Count__c fields of parent records A__c
// when child records B__c are inserted, updated, undeleted or deleted.
 
trigger RollUpBOnA on B__c(
      after delete,
      after insert,
      after update,
      after undelete
) {
      // Declare a set to store the Ids of the parent object A__c
      Set<Id> parentIds = new Set<Id>();
 
      // Check if the trigger is for insert or undelete
      if (Trigger.isInsert || Trigger.isUndelete) {
            // Check if the new version of the records is not null
            if (Trigger.new != null) {
                  for (B__c child : Trigger.new) {
                        // Check if the parent Id is not null
                        if (child.A_No__c != null) {
                              parentIds.add(child.A_No__c);
                        }
                  }
            }
      }
 
      // Check if the trigger is for delete
      if (Trigger.isDelete) {
            // Check if the old version of the records is not null
            if (Trigger.old != null) {
                  for (B__c child : Trigger.old) {
                        // Add the parent Id of each deleted child record to the set of parent Ids to be updated.
                        parentIds.add(child.A_No__c);
                  }
            }
      }
 
      // Check if the trigger is for update
      if (Trigger.isUpdate) {
            for (B__c child : Trigger.new) {
                  // Check if the parent Id is changed
                  if (child.A_No__c != Trigger.oldMap.get(child.id).A_No__c) {
                        // Check if either the old parent Id or the value field of the child record has been changed
                        // and if so, it adds the old parent Id to the set of parent Ids to be updated.
                        if (
                              Trigger.oldMap.get(child.id).A_No__c != null ||
                              child.Value__c !=
                              Trigger.oldMap.get(child.Id).Value__c
                        ) {
                              parentIds.add(
                                    Trigger.oldMap.get(child.id).A_No__c
                              );
                        }
                        // Check if the new parent Id is not null
                        if (child.A_No__c != null) {
                              // Add the parent Id of each updated child record to the set of parent Ids
                              parentIds.add(child.A_No__c);
                        }
                  } else {
                        //Check if the value field of the child record has been changed add the parent Id to the set of parent Ids to be updated.
                        if (
                              child.Value__c !=
                              Trigger.oldMap.get(child.Id).Value__c
                        ) {
                              // Add the parent Id of each updated child record to the set of parent Ids
                              parentIds.add(child.A_No__c);
                        }
                  }
            }
      }
 
      // Declare a map to store the child record count for each parent
      Map<Id, Integer> childRecordCount = new Map<Id, Integer>();
      // Declare a map to store the sum of the value field for each parent
      Map<Id, Decimal> childValuesSum = new Map<Id, Decimal>();
 
      // Increment the record count and sum of the value field for each parent
      for (B__c child : [
            SELECT Id, A_No__c, Value__c
            FROM B__c
            WHERE A_No__c IN :parentIds
            ORDER BY A_No__c
      ]) {
            if (childRecordCount.containsKey(child.A_No__c)) {
                  childRecordCount.put(
                        child.A_No__c,
                        childRecordCount.get(child.A_No__c) + 1
                  );
            } else {
                  childRecordCount.put(child.A_No__c, 1);
            }
            if (childValuesSum.containsKey(child.A_No__c)) {
                  childValuesSum.put(
                        child.A_No__c,
                        childValuesSum.get(child.A_No__c) + child.Value__c
                  );
            } else {
                  childValuesSum.put(child.A_No__c, child.Value__c);
            }
      }
 
      // Create a list of parent records to update
      List<A__c> parentsToUpdate = new List<A__c>();
 
      // Loop through the parent records to update the record count and sum of the value field fields
      for (A__c parent : [
            SELECT Id, Total__c, Record_Count__c
            FROM A__c
            WHERE Id IN :parentIds
      ]) {
            parent.Record_Count__c = childRecordCount.get(parent.Id);
            parent.Total__c = childValuesSum.get(parent.Id);
            parentsToUpdate.add(parent);
      }
 
      // Update the parent object
      update parentsToUpdate;
}

Note: The code above provides an example of utilizing a map for calculations. If you prefer to use an aggregate query,…