0

I am not getting any errors with the below code however, after doing some testing I found that recalculation is not taking place when a contact is deleted and field "Number of Contacts is not updating. Also, my code has two parts. How can I merge the two without having code on the contact and account object (Still a newbie)?

    trigger NumberOfContacts on Account (before insert, before update) {
    if(trigger.isinsert)
        for(account a:trigger.new)
            a.Number_of_contacts__c = 0;
    else {
        List<AggregateResult> agResult = [SELECT Count(ID) conCount, AccountId accId FROM Contact WHERE AccountId IN :trigger.new Group By AccountId];
        for(AggregateResult result : agResult){
            trigger.newmap.get((Id) result.get('accId')).Number_of_contacts__c = (Integer)result.get('conCount');
        }

        for(Account act : Trigger.new){
            act.Number_of_active_contacts__c = 0;
        }
        agResult = [SELECT Count(ID) conCount, AccountId accId FROM Contact WHERE AccountId IN :trigger.new AND Inactive__c = false Group By AccountId];
        for(AggregateResult result : agResult){
            trigger.newmap.get((Id) result.get('accId')).Number_of_active_contacts__c = (Integer)result.get('conCount');
        }
    }
}

..

trigger NumberOfContactsOnAccount on Contact (after insert, after update, after delete, after undelete) {
    List<Contact> contacts = new list<contact>();
    Map<Id,account> accounts = new map<id,account>();
    if(trigger.new!=null)
        contacts.addAll(trigger.new);
    if(trigger.old!=null)
        contacts.addAll(trigger.old);
    for(contact c:contacts)
        accounts.put(c.accountid,new account(id=c.accountid));
    accounts.remove(null);
    update accounts.values();
}

Contact related list is Zero

enter image description here

3
  • 1
    Just use declarative-lookup-rollup-summaries.
    – Adrian Larson
    Nov 14 '16 at 15:19
  • Thanks Adrian but I just want to correct what I have so far. I have reports and dashboards already created around these triggers.
    – nevaeh1919
    Nov 14 '16 at 15:44
  • You can use the same fields and simply delete your triggers to replace them with a point-and-click version...
    – Adrian Larson
    Nov 14 '16 at 15:59
1

Why do you need a trigger on Account AND Contact? Seems you would only need one on contact

trigger ContactCount on Contact(after insert, after update, after delete){

    Map<ID,Account> accMap = New Map<ID,Account>();

    for(Contact c : (trigger.isDelete ? trigger.old : trigger.new)){
        accMap.add(c.AccountId);
    }

    accMap = new Map<ID,Account>([Select (Select ID From Contacts) From Account where Id In :accMap.keySet()]);

    for(Id aId : accMap.keySet()){
        Account a = accMap.get(aId);
        a.Count_Of_Contacts__c = a.Contacts.size();
    }

    update accMap.values();

}

If you have a large number of contacts per account this aggregate trigger should be more useful

trigger ContactCount on Contact(after insert, after update, after delete){

    Map<ID,Account> accMap = New Map<ID,Account>();

    for(Contact c : (trigger.isDelete ? trigger.old : trigger.new)){
        accMap.add(c.AccountId);
    }

    for (AggregateResult aggregate : [
            Select Count(Id) cnt, AccountId Id
            From Contact where AccountId In :accIds
            Group By AccountId]
    ) {
            acctMap.put((Id) aggregate.get('Id'),
                    new Account(Id = aggregate.get('Id'), Count_Of_Contacts__c = aggregate.get('count')
                    ));
    }

    //This covers those cases where all contacts for a give account are deleted            
    for(Id aId : accMap.keySet()){
                Account a = accMap.get(aId);
                if(a == null) accMap.put(aId,New Account(Id=aId,Count_Of_Contacts__c = 0));
    }

    update accMap.Values();

}

This should cover all scenarios and bulkify pretty well.

8
  • I think this approach does hit some limits on the number of children it will work with. Probably better to query AggregateResult.
    – Adrian Larson
    Nov 14 '16 at 23:16
  • @AdrianLarson - I guess it could if you have a lot of contacts per account. I am not 100% sure if it will trigger the "Too many record for direct assignment, use map" I will put up an alternate here in a few
    – Eric
    Nov 14 '16 at 23:18
  • @AdrianLarson - There. Think that should cover it, no?
    – Eric
    Nov 14 '16 at 23:25
  • 1
    @AdrianLarson - Yea, got all excited to try out sfdcfox's trick and went for it lol. Thx for the edit
    – Eric
    Nov 14 '16 at 23:30
  • 1
    Made a few more edits to cover those cases where there are no contacts after deletion
    – Eric
    Nov 14 '16 at 23:36
0

You can't combine the two triggers since one is on Contacts and the other is on Accounts.

What you can do though is change the definition on your Account trigger. You need it fire again after your Contact trigger if an Account is updated because of an insert, deletion or undeletion of a Contact. Change it to the following:

trigger NumberOfContacts on Account (before insert, before update, after update){
0

I was able to solve my issue but how could I have made this into one trigger on the Contact object only?

Scenarios: • Create new contact • Mark contact as inactive • Delete inactivated contact • Undelete inactivated contact from recycle bin • Transfer contact to another account • Create new lead, convert to contact

/On Contact
trigger NumberOfContactsOnAccount on Contact (after insert, after update, after delete, after undelete) {
List<Contact> contacts = new list<contact>();
Map<Id,account> accounts = new map<id,account>();
if(trigger.new!=null)
    contacts.addAll(trigger.new);
if(trigger.old!=null)
    contacts.addAll(trigger.old);
for(contact c:contacts)
    accounts.put(c.accountid,new account(id=c.accountid));
accounts.remove(null);
update accounts.values();
}





/On Account

trigger NumberOfContacts2 on Account (before insert, before update) {
    system.debug(' ');
    if(trigger.isinsert)
        for(account a:trigger.new)
            a.Number_of_contacts__c = 0;
    else {
        List<AggregateResult> agResult = [SELECT Count(ID) conCount, AccountId accId FROM Contact WHERE AccountId IN :trigger.new Group By AccountId];

        for (account a: trigger.new)
            a.Number_of_contacts__c = 0;

        for(AggregateResult result : agResult){
            system.debug('num of contacts' + result);
            trigger.newmap.get((Id) result.get('accId')).Number_of_contacts__c = (Integer)result.get('conCount');
        }

        for(Account act : Trigger.new){
            act.Number_of_active_contacts__c = 0;
        }
        agResult = [SELECT Count(ID) conCount, AccountId accId FROM Contact WHERE AccountId IN :trigger.new AND Inactive__c = false Group By AccountId];
        for(AggregateResult result : agResult){
            system.debug('num of active contacts' + result);
            trigger.newmap.get((Id) result.get('accId')).Number_of_active_contacts__c = (Integer)result.get('conCount');
        }
    }
}

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.