Use Case:

Write a trigger:

Count the total number of contacts associated to an Account whenever a Contact is, 

  1. Inserted, Updated or Deleted related to the Account.
  2. Field Total_Contacts_Count__c should get updated with the latest count.

Pre-requisite: Create a Number field with API name “Total_Contacts_Count__c” on Account.

trigger ContactTrigger on Contact (after insert, after update, after delete) {
if(Trigger.isAfter) {
// Code runs when any contact is inserted.
if(Trigger.isInsert) {
// Map of Account Ids as the Keys and count of contacts which need to be updated later as the value.
Map<Id, Integer> accMapWithContsCount = new Map<Id, Integer>();
// Check if the inserted contact has some value in the account for each contact,
// if yes then add the Integer 1 in the map
for(Contact con : Trigger.new) {
// it would check if the key 'AccountId' already exists in the map, if no then simply set the integer value 1 for the account.
// else update the value to 1.
if(!accMapWithContsCount.containsKey(con.AccountId)) {
accMapWithContsCount.put(con.AccountId, 1);
}
else {
accMapWithContsCount.put(con.AccountId, accMapWithContsCount.get(con.AccountId) + 1);
}
}
// Get all the accounts with the keySet of map and update field 'Total_Contacts_Count__c' with the values from the map.
List<Account> accountsToBeUpdated = [Select Id, Total_Contacts_Count__c From Account Where Id IN :accMapWithContsCount.keySet()];
for(Account acc : accountsToBeUpdated) {
acc.Total_Contacts_Count__c = acc.Total_Contacts_Count__c + accMapWithContsCount.get(acc.Id);
}
update accountsToBeUpdated;
}
// Code runs when any contact is updated.
if(Trigger.isUpdate) {
Map<Id, Integer> accMapWithContsCount = new Map<Id, Integer>();
for(Contact con : Trigger.new) {
// Condition which checks that the code should run only if there is a change in Account field of contact.
if(con.AccountId != Trigger.oldMap.get(con.Id).AccountId) {
// Check when previously there was nothing in the account field but then some account was populated during updation.
if(Trigger.oldMap.get(con.Id).AccountId == null) {
if(!accMapWithContsCount.containsKey(con.AccountId)) {
accMapWithContsCount.put(con.AccountId, 1);
}
else {
accMapWithContsCount.put(con.AccountId, accMapWithContsCount.get(con.AccountId) + 1);
}
}
// Check when previously there was some value in the Account field but during updation the account was removed
// and new value is null
else if(Trigger.oldMap.get(con.Id).AccountId != null && con.AccountId == null) {
if(!accMapWithContsCount.containsKey(Trigger.oldMap.get(con.Id).AccountId)) {
// since there is no value after updation in the field Account of Contact
// so new Total Contacts Count on Account would be less
accMapWithContsCount.put(Trigger.oldMap.get(con.Id).AccountId, -1);
}
else {
accMapWithContsCount.put(Trigger.oldMap.get(con.Id).AccountId, accMapWithContsCount.get(Trigger.oldMap.get(con.Id).AccountId) - 1);
}
}
// Check when account associated to contact before and after updation was different.
else {
// For new account which was populated to the contact
if(!accMapWithContsCount.containsKey(con.AccountId)) {
accMapWithContsCount.put(con.AccountId, 1);
}
else {
accMapWithContsCount.put(con.AccountId, accMapWithContsCount.get(con.AccountId) + 1);
}
// For old account which was updated with the new one
Id oldId = Trigger.oldMap.get(con.Id).AccountId;
if(!accMapWithContsCount.containsKey(oldId)) {
accMapWithContsCount.put(oldId, -1);
}
else {
accMapWithContsCount.put(oldId, accMapWithContsCount.get(oldId) - 1);
}
}
}
}
// Get all the accounts with the keySet of map and update field 'Total_Contacts_Count__c' with the values from the map.
List<Account> accountsToBeUpdated = [Select Id, Total_Contacts_Count__c From Account Where Id IN :accMapWithContsCount.keySet()];
for(Account acc : accountsToBeUpdated) {
acc.Total_Contacts_Count__c = acc.Total_Contacts_Count__c + accMapWithContsCount.get(acc.Id);
}
update accountsToBeUpdated;
}
// Code runs when any contact is deleted.
if(Trigger.isDelete) {
Map<Id, Integer> accMapWithContsCount = new Map<Id, Integer>();
for(Contact con : Trigger.old) {
if(!accMapWithContsCount.containsKey(con.AccountId)) {
accMapWithContsCount.put(con.AccountId, -1);
}
else {
accMapWithContsCount.put(con.AccountId, accMapWithContsCount.get(con.AccountId) - 1);
}
}
// Get all the accounts with the keySet of map and update field 'Total_Contacts_Count__c' with the values from the map.
List<Account> accountsToBeUpdated = [Select Id, Total_Contacts_Count__c From Account Where Id IN :accMapWithContsCount.keySet()];
for(Account acc : accountsToBeUpdated) {
acc.Total_Contacts_Count__c = acc.Total_Contacts_Count__c + accMapWithContsCount.get(acc.Id);
}
update accountsToBeUpdated;
}
}
}

Test Class:

Scenario 1- Test the scenario which checks that whenever a new Contact is inserted to some account, Total_Contacts_Count__c field should be updated to value 1.

Scenario 2- Test the scenario when Account field on a Contact is updated from null to some value. 

Scenario 3- Test the scenario when Account field on a Contact is updated from some value to null.

Scenario 4- Test the scenario when Account field on a Contact is updated from some value to another value.

Scenario 5- Test the scenario when a contact record is deleted. Update related account’s field ‘Total_Contacts_Count__c’.

@isTest
private class ContactTriggerTest {
    @testSetup
static void dataSetup() {
Account newAcc = new Account(Name='TestAccount1');
insert newAcc;
Account newAcc2 = new Account(Name='TestAccount2');
insert newAcc2;
}
// Test the scenario which checks that when we insert a new Contact to some account,
// Total_Contacts_Count__c field should be updated to value 1.
// Here, we inserted 2 contacts, Total_Contacts_Count__c should be updated to 2.
@isTest
static void test_afterInsert() {
Account insertedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Name = 'TestAccount1'];
System.assertEquals(0, insertedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
List<Contact> contacts = new List<Contact>();
for(Integer i=0; i<2; i++) {
contacts.add(new Contact(LastName='TestContact'+i, AccountId=insertedAcc1.Id));
}
Test.startTest();
    insert contacts;
Account udpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(2, udpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
Test.stopTest();
}
// Test the scenario when Account field on a Contact is updated from null to some value
@isTest
static void test_afterUpdate_scenario1() {
// Verify that Total_Contacts_Count__c value is 0 initially
Account insertedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Name = 'TestAccount1'];
System.assertEquals(0, insertedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
// Verify that Total_Contacts_Count__c value is 0 after the insertion of the contact
List<Contact> contacts = new List<Contact>();
for(Integer i=0; i<2; i++) {
contacts.add(new Contact(LastName='TestContact'+i));
}
insert contacts;
Account udpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(0, udpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
// Verify that Total_Contacts_Count__c value is 1 after contact is updated with the account
Test.startTest();
for(Contact con: contacts) {
con.AccountId = insertedAcc1.Id;
}
update contacts;
Test.stopTest();
Account newUdpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(2, newUdpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
}
// Test the scenario when Account field on a Contact is updated from some value to null
@isTest
static void test_afterUpdate_scenario2() {
Account insertedAcc1 = [Select Id From Account Where Name = 'TestAccount1'];
List<Contact> contacts = new List<Contact>();
for(Integer i=0; i<2; i++) {
contacts.add(new Contact(LastName='TestContact'+i, AccountId=insertedAcc1.Id));
}
insert contacts;
Account udpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(2, udpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
Test.startTest();
for(Contact con : contacts) {
con.AccountId = null;
}
update contacts;
Test.stopTest();
Account newUdpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(0, newUdpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
}
// Test the scenario when Account field on a Contact is updated from some value to another value
@isTest
static void test_afterUpdate_scenario3() {
Account insertedAcc1 = [Select Id From Account Where Name = 'TestAccount1'];
Account insertedAcc2 = [Select Id From Account Where Name = 'TestAccount2'];
List<Contact> contacts = new List<Contact>();
for(Integer i=0; i<2; i++) {
contacts.add(new Contact(LastName='TestContact'+i, AccountId=insertedAcc1.Id));
}
insert contacts;
Account udpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
Account udpatedAcc2 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc2.Id];
System.assertEquals(2, udpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
System.assertEquals(0, udpatedAcc2.Total_Contacts_Count__c, 'Contacts count does not match.');
Test.startTest();
for(Contact con : contacts) {
con.AccountId = udpatedAcc2.Id;
}
update contacts;
Test.stopTest();
Account newUdpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
Account newUdpatedAcc2 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc2.Id];
System.assertEquals(0, newUdpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
System.assertEquals(2, newUdpatedAcc2.Total_Contacts_Count__c, 'Contacts count does not match.');
}

// Test the scenario when a contact is deleted.
// Update related account's field 'Total_Contacts_Count__c'
@isTest
static void test_afterDelete() {
Account insertedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Name = 'TestAccount1'];
System.assertEquals(0, insertedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
List<Contact> contacts = new List<Contact>();
for(Integer i=0; i<2; i++) {
contacts.add(new Contact(LastName='TestContact'+i, AccountId=insertedAcc1.Id));
}
insert contacts;
Account udpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(2, udpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
Test.startTest();
    delete contacts;
Test.stopTest();
Account newUdpatedAcc1 = [Select Id, Total_Contacts_Count__c From Account Where Id = :insertedAcc1.Id];
System.assertEquals(0, newUdpatedAcc1.Total_Contacts_Count__c, 'Contacts count does not match.');
}
}
Code Coverage: 100%
Like it ? Share : Do Nothing

This Post Has 3 Comments

  1. Anil

    Mr.apex Ace i think your code is not satisfying all the conditions

  2. ApexAce

    Short and Simple

    trigger ContactTrigger on Contact (after insert,after update, after delete){
    Set accountIds = new Set();

    if(Trigger.isInsert || Trigger.isUpdate){
    for(Contact con : Trigger.new){
    accountIds.add(con.AccountId);
    }
    }

    if(Trigger.isDelete){
    for(Contact con : Trigger.old){
    accountIds.add(con.AccountId);
    }
    }

    List accList = [SELECT Id,Total_Contacts_Count__c,(SELECT id FROM Contacts)
    FROM Account WHERE Id IN: accountIds];

    for(Account acc : accList){
    acc.Total_Contacts_Count__c = acc.Contacts.Size();
    }
    update accList;
    }

    1. Shreya

      Hey, It’s not passing all test cases as you forgot 2 cases of after update , I tried including those and it is passing all test cases.

      trigger ContactTrigger on Contact (after insert, after update , after delete){
      ContactTriggerHandler.countAllContactOfAccount(trigger.new,trigger.old,trigger.oldMap);
      }

      public static void countAllContactOfAccount(List newContacts,List oldContacts,MapoldMap){
      if(trigger.isAfter){
      List accounts = new List();
      if(trigger.isInsert){
      Set accIds = new Set();
      for(Contact con: newContacts){
      if(con.AccountId != null)
      accIds.add(con.AccountId);
      }
      accounts = updateAccounts(accIds);

      }
      if(trigger.isUpdate){
      system.debug(‘hi’);
      Set accIds = new Set();
      for(Contact con: newContacts){
      if(oldMap.get(con.Id).AccountId != con.AccountId){
      if(con.AccountId == null){
      accIds.add(oldMap.get(con.Id).AccountId);
      }else if(con.AccountId != null && oldMap.get(con.Id).AccountId == null){
      accIds.add(con.AccountId);
      }else {
      accIds.add(oldMap.get(con.Id).AccountId);
      system.debug(‘hi’);
      accIds.add(con.AccountId);
      system.debug(‘hi’);
      }
      }
      accounts = updateAccounts(accIds);
      }
      }
      if(trigger.isDelete){
      Set accIds = new Set();
      for(Contact con: oldContacts){
      if(con.AccountId != null)
      accIds.add(con.AccountId);
      }
      accounts = updateAccounts(accIds);
      }

      update accounts;
      }
      }

      private static List updateAccounts(Set accIds){
      List accounts = [Select id, (Select id from Contacts) from Account where id in : accIds];
      for(Account acc: accounts){
      acc.Total_Contacts_Count__c = acc.Contacts.size();
      }
      return accounts;
      }

Leave a Reply