Contacts/Cases rollup for Accounts in Salesforce

** Update Sept 3rd 2015 – This code is not recommended as it does not scale for Contacts greater than 1,000. I will be posting an update version of this code soon. **

If you’re familiar with using roll-up/summary fields in Salesforce, you’ve probably come up against the fact that you can’t create those fields types to count the number of cases or contacts related to a given account record. I don;t know why that is, but I recently created a workaround using Apex triggers to perform that function in the same automated fashion.

You’ll need to add two fields to your account object. The labels can be changed but the API names should be left as is, if you don’t want to change the code.

  • Number of Cases – Number_of_Cases__c
  • Number Of Contacts – Number_of_Contacts__c

Then add the following triggers to your org. First, the Case trigger;

/* Provide summary of Number of Cases on Account record */

trigger CaseTrigger on Case (after delete, after insert, after undelete,
after update) {

    Case[] cases;
    if (Trigger.isDelete)
        cases = Trigger.old;
    else
        cases = Trigger.new;

    // get list of accounts
    Set<ID> acctIds = new Set<ID>();
    for (Case cse : cases) {
            acctIds.add(cse.AccountId);
    }
   
    Map<ID, Case> casesForAccounts = new Map<ID, Case>([select Id
                                                            ,AccountId
                                                            from Case
                                                            where AccountId in :acctIds]);

    Map<ID, Account> acctsToUpdate = new Map<ID, Account>([select Id
                                                                 ,Number_of_Cases__c
                                                                  from Account
                                                                  where Id in :acctIds]);
                                                                
    for (Account acct : acctsToUpdate.values()) {
        Set<ID> caseIds = new Set<ID>();
        for (Case cse : casesForAccounts.values()) {
            if (cse.AccountId == acct.Id)
                caseIds.add(cse.Id);
        }
        if (acct.Number_of_Cases__c != caseIds.size())
            acct.Number_of_Cases__c = caseIds.size();
    }

    update acctsToUpdate.values();
}

Next the Contact trigger;

/* Provide summary of Number of Contacts on Account record */

trigger ContactSumTrigger on Contact (after delete, after insert, after undelete,
after update) {

    Contact[] cons;
    if (Trigger.isDelete)
        cons = Trigger.old;
    else
        cons = Trigger.new;

    // get list of accounts
    Set<ID> acctIds = new Set<ID>();
    for (Contact con : cons) {
            acctIds.add(con.AccountId);
    }
   
    Map<ID, Contact> contactsForAccounts = new Map<ID, Contact>([select Id
                                                            ,AccountId
                                                            from Contact
                                                            where AccountId in :acctIds]);

    Map<ID, Account> acctsToUpdate = new Map<ID, Account>([select Id
                                                                 ,Number_of_Contacts__c
                                                                  from Account
                                                                  where Id in :acctIds]);
                                                                
    for (Account acct : acctsToUpdate.values()) {
        Set<ID> conIds = new Set<ID>();
        for (Contact con : contactsForAccounts.values()) {
            if (con.AccountId == acct.Id)
                conIds.add(con.Id);
        }
        if (acct.Number_of_Contacts__c != conIds.size())
            acct.Number_of_Contacts__c = conIds.size();
    }

    update acctsToUpdate.values();

}

Now those two fields will maintain a real-time count of the contacts/cases related to a parent account even if those records are deleted and undeleted (restored from the Recycle bin).

You can Download (7k) all the triggers and test classes necessary for deployment via Eclipse or Ant. Enjoy.