I want to make a roll-up summary-like field between two objects with a lookup relationship. The relationship can't be changed into master-detail so I'm writing some custom code to do this.

Since it isn't important for this data to be updated live, I've written some batch apex (that I'm planning to run every night) which takes all of the target records:

 public Database.QueryLocator start(Database.BatchableContext context){
  return Database.getQueryLocator([
     SELECT id, count_target__c FROM Object__c

and runs aggregate query on the source record to find the count.

public void execute(Database.BatchableContext context, Sobject[] scope){
    Map<Id,Sobject> objectIdMap = new Map<Id,SObject>(scope);
    List<AggregateResult> aggs = [SELECT count(Id) count, object__c FROM
    child_object__c WHERE object__c IN :objectIdMap.keyset() 
    GROUP BY object__c];

    for(AggregateResult ar: acctAggsAttended){
        Id objId = (Id) ar.get('object__c');
        Integer total = (Integer) ar.get('count');
        Object__c object = (Object__c) objectIdMap.get(objId);
        object.count_target__c = total;
    update objectIdMap.values();


I want to do it this way because there is a bit of spaghetti trigger issue with the objects in question and I don't want to add to the problem by adding more code into the trigger. Trigger seems harder to isolate, turn off etc, more likely to get lost.

But, is there likely some issue with running this code, likely to hit governor limits, or cause more problems than it is worth?

  • 2
    Consider using DLRS rather than reinventing the wheel.
    – Adrian Larson
    Feb 7 '20 at 14:14

Normally this shouldn't lead to any major issues with limits or whatsoever. You only change 1 field and update these records, so when it gets into the update trigger, the only thing that was changed is that particular field. For example this trigger handler:

public static void onBeforeUpdate(Map<Id, Account> oldMap, Map<Id, Account> newMap) {
    List<Account> accsWithChangedName = new List<Account>();
    for (Id accId : oldMap.keySet()) {
        Account oldAcc = oldMap.get(accId);
        Account newAcc = newMap.get(accId);
        if (oldAcc.Name != newAcc.Name) {

    if (!accsWithChangedName.isEmpty()) {
        // Do something

if you have something like that, most of the execution will be skipped, only the ones that fire when count_target__c changes will do their job.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.