September 17, 2013

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!!!

36 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
  15. For removing the account id from contact the trigger doesn't work fine, so please correct it
    Correct version:
    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());
    }
    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(trigger.oldmap.get(con.id).accountid, new List());
    }
    mapAcctIdDelContactList.get(trigger.oldmap.get(con.id).accountid).add(Con);
    AcctIds.add(trigger.oldMap.get(Con.Id).AccountId);
    }
    }
    }

    ReplyDelete
  16. Hey, can you please tell me it will work fine for bulk records or not

    ReplyDelete
    Replies
    1. It will work. But, when you are doing a data migration activity, it is always better to turn off or skip trigger for better performance.
      Insert parent records with the count. Insert child records next with triggers turned off.

      Delete
  17. it's not able to count existing records of Contact object

    ReplyDelete
    Replies
    1. For existing data, you should do one time data load.

      Delete
    2. for existing contact records, u can try like this

      Trigger contacttrigger on Contact(after insert, after update, after delete){

      contacthelper ch = new contacthelper();

      if(trigger.isAfter){

      if((trigger.isInsert) || (trigger.IsUpdate)){

      ch.updateAccount(Trigger.New);

      }
      if(trigger.IsDelete){
      ch.updateAccount(Trigger.Old);
      }


      }


      }

      public class ContactHelper{
      Set AccountIDs = new Set();
      List contactfetchlist = new List();
      Map> Accmap = new Map>();

      public void updateAccount(List conlist){

      // List contactfetchlist = [select id, AccountId from COntact where AccountId !=null];
      for(Contact c: conlist){

      if(String.IsNotBlank(c.AccountId)){
      AccountIDs.add(c.AccountId);
      }

      }
      List Acclist = [select id, Numberofcontacts__c, (select id from Contacts) From Account where Id in : AccountIDs ]; // parent Account field

      system.debug(Acclist);

      for(Account Ac : Acclist){

      Accmap.put(Ac.id, Ac.contacts);

      system.debug(Accmap);

      }

      List Accountlistupdate = new List();

      Integer noOfConts = 0;

      for(Account Acc : Acclist){

      system.debug(Accmap.get(Acc.id).size());

      Acc.Numberofcontacts__c = Accmap.get(Acc.id).size();

      Accountlistupdate.add(Acc);

      }
      update Accountlistupdate;

      }
      }

      Delete