Introduction:
In this blog post, we will explore an example that shows how to roll up child counts using aggregate query. It will also demonstrate how to sum values on a parent record. This example applies to lookup relationships but you can use the same with master-detail also.
Example Scenario:
Imagine a business that manages projects (A__c records) and their associated tasks (B__c records) in Salesforce. Tasks (B__c) has a look relationship to projects (A__c) records. Each project has a field to track the total number of tasks (Record_Count__c). Another field sums up the estimated effort or cost of all tasks (Total__c).
Whenever a task is added, updated, removed, or reassigned between projects, the corresponding project’s fields must reflect the changes. For example:
- Adding a New Task: When a task is added to a project, the task count should increase. Additionally, the total effort and cost fields on the project should increase accordingly.
- Updating a Task: If the task’s effort/cost changes, the corresponding project’s total should be updated. Similarly, if the task is moved to another project, the old project needs to reflect the correct task counts. The new project also needs to reflect the correct totals.
- Deleting a Task: When a task is removed, the project’s task count and total effort/cost fields should decrease accurately.
- Restoring a Task: If a previously deleted task is restored, the associated project’s fields must include it again.
Project managers always have up-to-date information about the number of tasks. They also know their cumulative effort and cost without manual calculations. The RollUpBOnA trigger automates these updates, enhancing data accuracy and reducing administrative effort.
Trigger Overview:
This is a Salesforce Apex trigger. It maintains summary fields on a parent record (A__c). The updates are based on changes to its child records (B__c).
What it Updates :
- Record_Count__c: Counts how many child records are linked to each parent
- Total__c: Sums up the Value__c field from all child records
When it Runs:
The trigger fires when child records (B__c) are:
- ✨ Created (Insert)
- 🔄 Updated
- ❌ Deleted
- ↩️ Undeleted
How It Works:
Here is a step-by-step explanation of what the RollUpBOnA trigger does:
- Declare a Set for Parent Record IDs:
The trigger begins by declaring a set. It usesparentIdsto store the IDs of the parentA__crecords. These records need to be updated. - Identify Relevant Parent IDs for Insert or Undelete Events:
- During
insertorundeleteevents, the trigger loops through theTrigger.newcollection. - If a child record (
B__c) has a non-null parent (A_No__c), the parent ID is added to theparentIdsset.
- During
- Identify Relevant Parent IDs for Delete Events:
- During
deleteevents, the trigger loops through theTrigger.oldcollection. - If a deleted child record has a non-null parent, the parent ID is added to the
parentIdsset.
- During
- Handle Updates to Parent IDs or Values:
- During
updateevents, the trigger compares the old (Trigger.oldMap) and new (Trigger.new) versions of eachB__crecord. - If the parent ID (
A_No__c) changes, both the old and new parent IDs are added to the set. - If the parent ID remains the same but the value (
Value__c) field changes, add the parent ID to the set.
- During
- Exit if No Parent IDs to Update:
If no parent IDs are collected in the set, the trigger exits. There is no further processing. - Aggregate Queries to Count Records and Sum Values:
- The trigger uses an aggregate query to count the number of
B__crecords (COUNT(Id)). It sums theirValue__cfields for eachA__crecord in theparentIdsset. - The results are stored in two maps: one for the record count (
childRecordCount) and one for the total value (childValuesSum).
- The trigger uses an aggregate query to count the number of
- Retrieve and Prepare Parent Records for Update:
- The trigger queries all
A__crecords in theparentIdsset, retrieving theirRecord_Count__candTotal__cfields. - It updates these fields based on the values stored in the maps (
childRecordCountandchildValuesSum). If a parent ID is not found in the maps, the corresponding field is set to 0.
- The trigger queries all
- Collect Parent Records to Update:
Each updated parent record is added to a list (parentsToUpdate) for processing. - Perform the Update Operation:
Finally, the trigger updates all theA__crecords in theparentsToUpdatelist. This ensures theirRecord_Count__candTotal__cfields are accurate. They are also kept up-to-date.
Sample Code:
Key Benefits:
- 🚀 Efficient (uses aggregate queries)
- 🎯 Accurate (handles all DML scenarios)
- 💪 Robust (handles null values and edge cases)
- 🔄 Maintains roll-up summary fields in real-time
Note – The above code shows an example of using aggregate query for calculations. If you want to use the map approach, please refer to this blog post Roll up summary trigger To Update Child Records Count and total Sum of values of child records on Parent Record using Maps.


Leave a reply to Comparing Aggregate Query vs Map in Salesforce Apex – Welcome to The Salesforce Dev Cancel reply