Home

Wednesday, 8 January 2025

sfdc-learn #16: Rollup Summary using trigger (Child - Parent -Grandparent)

 If we have requirement to rollup summary on two level using Apex trigger

We have Account  as Grandparent

  Contact as parent 

 Location__c as child 

When any record inserted / updated or deleted in Location object we need to calculate number of contacts count and calculate number of location count associated with each contact associated with account and  update below two custom fields on Account.

No Of Contacts (All contact associated with account )

No Of Contact Locations   -->(all location count from each contact associated with Account)

Apex Trigger:

trigger locationTrigger on Location__c (after insert, after update, after delete) {
    Set<Id> contactIdSet =  new Set<Id>();
    List<Account> accUpdateList =  new List<Account>();

    if(trigger.isInsert){
            for(Location__c locRec: trigger.new){
                if(locRec.Contact__c != null){
                    contactIdSet.add(locRec.Contact__c);
                }
            }
    }

    if( trigger.isUpdate){
        for(Location__c locRec: trigger.new){
            if(locRec.Contact__c != null &&
            locRec.Contact__c != trigger.oldMap.get(locRec.Id).Contact__c){
                contactIdSet.add(locRec.Contact__c);
                contactIdSet.add(trigger.oldMap.get(locRec.Id).Contact__c);
            }
        }
    }

    if(trigger.isDelete){
        for(Location__c locRec: trigger.old){
            contactIdSet.add(locRec.Contact__c);
        }  
    }

    Set<Id> accountIdSet = new Set<Id>();
    set<Id> allContactIdSet = new Set<Id>();
    for (Contact con : [SELECT Id,AccountId
from Contact where Id In:contactIdSet ]) {
        if(con.AccountId != null){
            accountIdSet.add(con.AccountId);
        }
    }
    for (Contact con : [SELECT Id from Contact where AccountId In:accountIdSet ]) {
            allContactIdSet.add(con.Id);
    }

    Map<Id, Integer> accountWithLocCountMap = new Map<Id, Integer>();
   
    List<AggregateResult> locAggrList = [SELECT Count(Id)locCount,Contact__r.AccountId AccId
                                from Location__c
                                where contact__c In:allContactIdSet
                                group by Contact__r.AccountId];
   
                                           
    for(AggregateResult aggr: locAggrList){
        if((string)aggr.get('AccId') != null){
          accountWithLocCountMap.put((string)aggr.get('AccId'), (Integer)aggr.get('locCount') );
        }
    }

    if(locAggrList.isEmpty() ||
(!locAggrList.isEmpty() && accountWithLocCountMap.isEmpty())){
        for(Id accId: accountIdSet){
            accountWithLocCountMap.put(accId, 0 );
        }
    }
   
    Map<Id, Integer> accountWithContactMap =  new Map<Id, Integer>();
    List<AggregateResult> conAggrList = [SELECT count(Id)conCount, AccountId
                                FROM Contact
                                where  AccountId In:accountWithLocCountMap.keySet()
                                group by AccountId];

    for(AggregateResult aggr: conAggrList){
    accountWithContactMap.put((string)aggr.get('AccountId'), (Integer)aggr.get('conCount') );
    }

    if(conAggrList.isEmpty()){
        for(Id accId: accountIdSet){
            accountWithContactMap.put(accId, 0 );
        }
    }

    for(Id accId : accountWithContactMap.keySet()){
        Account  acc =  new Account();
        acc.Id = accId;
        acc.No_Of_Contacts__c = accountWithContactMap.get(accId);
        acc.No_Of_Contact_Location__c = accountWithLocCountMap.get(accId);
        accUpdateList.add(acc);
    }

    if(!accUpdateList.isEmpty()){
        update accUpdateList;
    }
}

Test Results:

Account Which having 2 contacts

Create New location on one of Contact

Check Contact and location count on account

Add another location on another contact

Check Count on Account

Then Try to delete one of location

Check Location count on account


                  Update Location and associate to another contact which not associated with this old contact account (update contact which account is different)
Check Count is reduced..



2 comments:

  1. Good info. Thanks!

    ReplyDelete
  2. Two things are missing on update senario if contact is not mandatory on location obhect
    1.Exsting Location object record which don't have contcat and updating it with contcat.
    2.Extsting Location object record which has contact and we are updating it without contact.
    Also I believe in code don't require 2 for loop we can add accountId !=null inside query.
    I believe some more improvement is needed in this code. nice try.
    From
    Enzigma

    ReplyDelete