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,…