0

I have a custom field on Account called "Contact_Exist__c" (api name). I'm trying to write an apex trigger on contact that when the field is updated/inserted and it has an account name linked or unlinked to it, it updated on Account "Contact_Exist__c" by an increment of 1 or a decrement of 1. I tried to implement the following (I know its wrong)

Final version fixes all my issues. It no longer needs to sum off a column and instead works as is using count functionality.

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

    Set<Id> AccountIds = new Set<Id>();

    if(!Trigger.isDelete){
        for (Contact ct : Trigger.new) {        

            if(Trigger.isInsert && ct.AccountId != null){
                AccountIds.add(ct.AccountId);
            }
     //For Contact Update scenarios, Contact.AccountId value should be checked for null in new and old record.
            if(Trigger.isUpdate){
                if(ct.AccountId==null && Trigger.oldMap.get(ct.Id).AccountId != null){
                    AccountIds.add(Trigger.oldMap.get(ct.Id).AccountId);
                }
                if(ct.AccountId!=null && Trigger.oldMap.get(ct.Id).AccountId != null && ct.AccountId != Trigger.oldMap.get(ct.Id).AccountId){
                    AccountIds.add(ct.AccountId);
                    AccountIds.add(Trigger.oldMap.get(ct.Id).AccountId);
                }
                if(ct.AccountId!=null && Trigger.oldMap.get(ct.Id).AccountId == null){
                    AccountIds.add(ct.AccountId);
                }
            }

            if(Trigger.isUndelete && ct.AccountId != null){
                AccountIds.add(ct.AccountId);
            }
        }
    }else{
        for (Contact ct : Trigger.old){
            if(Trigger.isDelete && ct.AccountId != null){
                AccountIds.add(ct.AccountId);
            }
        }   
    }


            Map<ID, Account> account_updater = new Map<ID, Account>();


            //Preset to 0
            for(AggregateResult ar : [Select Id,sum(NumberContacts__c) cnt from Account where Id IN :accountIDs Group By Id ]){
                Account tmp = New Account(ID=(id)ar.get('Id'), NumberContacts__c = 0);
                account_updater.put(tmp.id,tmp);
            }




            for(AggregateResult ar : [Select AccountID,sum(ValidContactWorkflor__c) cnt From Contact Where AccountId IN :accountIDs Group By AccountID ]){
                Account tmp = New Account(ID=(id)ar.get('accountid'), NumberContacts__c = (decimal)ar.get('cnt'));
                account_updater.put(tmp.id,tmp);
            }

            update account_updater.values();  

     }
0

I understand that you are trying to get the count of Contacts and update it in a field in Account record. If yes, you may check the below trigger.

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

Set<Id> AccountIds = new Set<Id>();

if(!Trigger.isDelete){
    for (Contact ct : Trigger.new) {        

        if(Trigger.isInsert && ct.AccountId != null){
            AccountIds.add(ct.AccountId);
        }
 //For Contact Update scenarios, Contact.AccountId value should be checked for null in new and old record.
        if(Trigger.isUpdate){
            if(ct.AccountId==null && Trigger.oldMap.get(ct.Id).AccountId != null){
                AccountIds.add(Trigger.oldMap.get(ct.Id).AccountId);
            }
            if(ct.AccountId!=null && Trigger.oldMap.get(ct.Id).AccountId != null && ct.AccountId != Trigger.oldMap.get(ct.Id).AccountId){
                AccountIds.add(ct.AccountId);
                AccountIds.add(Trigger.oldMap.get(ct.Id).AccountId);
            }
            if(ct.AccountId!=null && Trigger.oldMap.get(ct.Id).AccountId == null){
                AccountIds.add(ct.AccountId);
            }
        }

        if(Trigger.isUndelete && ct.AccountId != null){
            AccountIds.add(ct.AccountId);
        }
    }
}else{
    for (Contact ct : Trigger.old){
        if(Trigger.isDelete && ct.AccountId != null){
            AccountIds.add(ct.AccountId);
        }
    }   
}

List<Account> AcctToUpdate = new List<Account>();
//AggregateResult to get count of Contact for each Account
for (AggregateResult ar: [Select Count(Id) ContactCount, AccountId from Contact where AccountId IN: AccountIds GROUP BY AccountId]){
    Account tmp = new Account(Id=(Id)ar.get('AccountId'), NumberContacts__c=(Decimal)ar.get('ContactCount'));
    AcctToUpdate.add(tmp);
}
if(AcctToUpdate.size()>0) update AcctToUpdate;
 }
  • Your answer brought me closest. It still fails to set accounts to zero because they no longer exist in the aggregate. I changed your list into a map and then before setting to X I reset them to 0. Using account as an in not contact. ITs technically more updates but I cannot see an alternative. Thank you so much. – Justin Fogel Jan 14 '15 at 23:36
  • While presetting to zero, you can fetch records as Account object instead of Aggregate Result. for(Account a: [Select Id,NumberContacts__c from Account where Id IN:AccountIds]{ //logic to preset 0 } – villsiva Jan 15 '15 at 3:51
0

A simple aggregate query should do it:

Basically, we get all the account IDs related to the contacts, then get all the accounts and total up the number where they are not blank. Then we update those accounts.

You could also include a check to ensure the value of YOURFIELD__c is new (and no null) or has changed, to reduce the number of rows / accounts you are working with

trigger CountField on Contact (after insert, after update){

    //You never mention what the name of the field was on the contact

    Set<ID> accountIDs = New Set<ID>();

        for(Contact c : trigger.new){
            if( (trigger.isInsert && c.YOURFIELD__C != null) || (c.YOURFIELD__c != trigger.oldMap.get(c.id).YOURFIELD__c))
                accountIDs.add(c.AccountID);
        }

        //could use a list of accounts and skip the map stuff if you want.
        Map<ID,Account>() account_updater = New Map<ID,Account>();

    for(AggregateResult ar : [Select AccountID Count(YOURFIELD__c)cnt From Contact Where AccointID IN :accountIDs AND YOURFIELD__ != null Group By AccountID ]){
        Account tmp = New Account(ID=(id)ar.get('accountid'), YOURFIELD__ = (decimal)ar.get('cnt'));
        account_updater.put(tmp.id,tmp);
    }

    update account_updater.values();



}
  • I hope you don't mind if I step through this. Set<Id> you establish the list of ids that have been set by trigger. Then for the list of contacts in said trigger that are either inserted and not null add that list of people to what is like an Array. I don't seem to understand the Map section. IT also gives me an error. "Unexpected token: 'Map'. Then you do an aggregate of how many contacts, then update them accordingly into a bulk. Then execute the bulk statement. – Justin Fogel Jan 14 '15 at 1:45
  • In addition the c.yourfield__c is slightly wrong. The field is on account that I am updating, your alias c is from contact. IF anything it should be where AccountId is not null that would mean it has a contact on it. When its the account field that doesn't work right logically. The only area my field should be is in Account tmp = New Account(ID=(id)ar.get('accountid'), YOURFIELD__ = (decimal)ar.get('cnt')); Where I finally update it in the command. – Justin Fogel Jan 14 '15 at 1:52
  • @JustinFogot - The contact field YOURFIELD__c is for the field that is being populated or not that you are counting. And yes I typed it up quickly so there may be some issues but the framework is there. – Eric Jan 14 '15 at 6:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.