Trigger to count number of Contacts associated with an Account

Sample Trigger:

trigger ContactCount on Contact (after insert, after update, after delete, after undelete) {
    Map<Id, List<Contact>> mapAcctIdContactList = new Map<Id, List<Contact>>();
    Map<Id, List<Contact>> mapAcctIdDelContactList = new Map<Id, List<Contact>>();
    Set<Id> AcctIds = new Set<Id>();    
    List<Account> listAcct = new List<Account>();
    
    if(trigger.isInsert) {
        for(Contact Con : trigger.New) {
            if(String.isNotBlank(Con.AccountId)) {
                if(!mapAcctIdContactList.containsKey(Con.AccountId)) {
                    mapAcctIdContactList.put(Con.AccountId, new List<Contact>());
                }
                mapAcctIdContactList.get(Con.AccountId).add(Con); 
                AcctIds.add(Con.AccountId);
            }   
        }  
    }
    
    if(trigger.isUpdate) {
        for(Contact Con : trigger.New) {
            if(String.isNotBlank(Con.AccountId) && Con.AccountId != trigger.oldMap.get(Con.Id).AccountId) {
                if(!mapAcctIdContactList.containsKey(Con.AccountId)){
                    mapAcctIdContactList.put(Con.AccountId, new List<Contact>());
                }
                mapAcctIdContactList.get(Con.AccountId).add(Con); 
                AcctIds.add(Con.AccountId);
            } else if(String.isBlank(Con.AccountId) && String.isNotBlank(trigger.oldMap.get(Con.Id).AccountId)) {
                if(!mapAcctIdDelContactList.containsKey(Con.AccountId)){
                    mapAcctIdDelContactList.put(Con.AccountId, new List<Contact>());
                }
                mapAcctIdDelContactList.get(Con.AccountId).add(Con);   
                AcctIds.add(trigger.oldMap.get(Con.Id).AccountId);
            }
        }  
    }
    
    if(trigger.isUndelete) {
        for(Contact Con : trigger.new) {
            if(String.isNotBlank(Con.AccountId)){
                if(!mapAcctIdContactList.containsKey(Con.AccountId)){
                    mapAcctIdContactList.put(Con.AccountId, new List<Contact>());
                }
                mapAcctIdContactList.get(Con.AccountId).add(Con);     
                AcctIds.add(Con.AccountId);
            }
        }  
    }      

    if(trigger.isDelete) {
        for(Contact Con : trigger.Old) {
            if(String.isNotBlank(Con.AccountId)){
                if(!mapAcctIdDelContactList.containsKey(Con.AccountId)){
                    mapAcctIdDelContactList.put(Con.AccountId, new List<Contact>());
                }
                mapAcctIdDelContactList.get(Con.AccountId).add(Con);    
                AcctIds.add(Con.AccountId); 
            }
        }  
    }   
    
    if(AcctIds.size() > 0) {
        listAcct = [SELECT Id, Number_of_Contacts__c FROM Account WHERE Id IN : AcctIds];
        
        for(Account acct : listAcct) {
            Integer noOfConts = 0;
            if(mapAcctIdContactList.containsKey(acct.Id)) {
                noOfConts += mapAcctIdContactList.get(acct.Id).size();
            }
            if(mapAcctIdDelContactList.containsKey(acct.Id)) {
                noOfConts -= mapAcctIdDelContactList.get(acct.Id).size();
            }
            acct.Number_of_Contacts__c = acct.Number_of_Contacts__c == null ? noOfConts : (acct.Number_of_Contacts__c + noOfConts);
        }
        
        update listAcct;    
    }
}

Cheers!!!

29 comments:

  1. Great Job! the code works great :D thank you!!!!

    ReplyDelete
  2. Hai,This code is not Working For Me

    ReplyDelete
    Replies
    1. It woks fine for me. Check whether the contact has account on it.

      Cheers!!!

      Delete
  3. Hi nice work, but why do we check

    if(!AcctContactList.containsKey(Con.AccountId)){
    AcctContactList.put(Con.AccountId, new List());
    }
    since our list of contacts have all account Id?

    waiting for your reply.

    ReplyDelete
    Replies
    1. because we are checking if key is not present in AcctContactList then we are adding to new list if key is present we are adding to same list

      Delete
  4. Here,AccountId is a custom field in contact object

    ReplyDelete
  5. code is working ...but why we used if(AcctIds.size() > 0)

    ReplyDelete
    Replies
    1. Account is not a mandatory field in Contact. So, sometimes the set may be empty. Its why we are checking...

      Delete
    2. if we not use if condition also the code is working ...

      Delete
  6. in salesforce fields are case sensitve or not ....i used Number_of_Contacts__c in trigger but in field creation i given name as Number_of_contacts__c ..but its working

    ReplyDelete
  7. Hello Guys,,

    I need your help... want to know How can I learn and become expert in APEX, Triggers, VF?? I don't have any mentor except internet and u guys. I read some workbooks but not reaching anywhere... just get basic knowledge. but How can be good Salesforce Developer?

    ReplyDelete
    Replies
    1. I can help you out... mail me your queries @upparapalli.saikrishna@gmail.com...

      Delete
    2. after writing the above code how to see output?\

      Delete
    3. HI Sai Krishna..I saw your coding format. Its really superb. I have to improve my Coding format.Could help me ?.
      Balaji.

      Delete
    4. HI Sai Krishna..I saw your coding format. Its really superb. I have to improve my Coding format.Could help me ?.
      Balaji.

      Delete
  8. Thanks buddy...Code works great..Thanks a million.

    ReplyDelete
  9. On which object to I create this trigger? Contact or Account?

    ReplyDelete
  10. Ignore my question above. I placed the trigger in contact object and it worked like a charm. Is it possible to have a certain criteria on the contact: If Contact:New_Trial_c=True then trigger the count? Where do I place that filter in the code?

    ReplyDelete
  11. This code is working in sandbox, but in production it fails with 0% code coverage. How do I fix that?

    ReplyDelete
    Replies
    1. Write test class before moving to production.
      Cheers!!!

      Delete
    2. Do you have a test code for this that you are able to share? I tried one, but they do not work with your code. I do not know how to read code to be able to debug.

      Delete
    3. Hi refer docs to write test classes.

      Delete
  12. Hi I'm trying to find number of Contacts for the Account and all of its children in the Account hierarchy.
    For example, assume you have an Account hierarchy like this:
    • Account A - 2 Contacts
    Account A1 – 3 Contacts
    Account A1a – 4 Contacts
    Account A2 – 5 Contacts
    The end result would be:
    Account A 2+3+4+5 = 14 Contacts
    Account A1 3+4 = 7 Contacts
    Account A1a 4 Contacts
    Account A2 5 Contacts
    Please let me know how we can find the child records and grand child record for an account and find it's contacts

    ReplyDelete
  13. On undelete of contact from recycle bin.. will this contact again get link with same account & will this trigger fire again ?

    ReplyDelete
    Replies
    1. Hi, I have include After Undelete even too.

      Check it!!!

      Delete
  14. Hi, Thanks for the code, I am new to salesforce and do not know how to test the code, can you please let me know how to run the code and write test cases for this?

    Thanks in advance for your help!

    ReplyDelete
    Replies
    1. Check this for test class - http://www.infallibletechie.com/2014/06/syntax-istest-private-class-classname.html

      Delete