function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
manjunath vivekmanjunath vivek 

​I am trying to count the number of contacts associated with the account


Iam trying to count the number of contacts on account, Iam getting the following error message

Error: Compile Error: Initial term of field expression must be a concrete SObject: LIST<Account> at line 10 column 1    

Trigger counting on contact(after update,after insert){
Set<account> accids=New Set<Account>();
For(contact c:trigger.new){
Accids.add(c.Account);
}
List<Contact> con = [select id  from contact where AccountID IN:accids];
List<Account> Acc=[Select count__C from account where id IN:accids ];
For(contact c:trigger.new)
{
Acc.count__c=con.size();
}
}
John PipkinJohn Pipkin
The variable "Acc" is instantiated as a List, but you are calling it as an SObject. Try this:
Trigger counting on contact(after update,after insert){
	Set<ID> accids=New Set<ID>();
	For(contact c:trigger.new){
		Accids.add(c.AccountId);
	}

	Map<ID,Account> Acc= new Map<ID,Account>([Select count__c from account where id IN:accids ]);
	Map<ID,Account> updateMap = new Map<ID,Account>();
	for(Account ac :Acc.values())
	{
		Integer count = 0;
		for(Contact c:Trigger.New){
			if(ac.Id == c.AccountId)
				count += 1;
			
		}
		ac.count__c= count;
		updateMap.put(ac.Id,ac);
	}

	if(!updateMap.isEmpty())
		update updateMap.values();
}

 
Sandeep M 1Sandeep M 1
trigger countcontacts on Contact (after insert, after delete) {
    Set<Id> aId = new Set<Id>();
    if(Trigger.isInsert){
        for(Contact opp : Trigger.New){
            aId.add(opp.AccountId);
        }
        List<Account> acc = [select id,count_of_contacts__c from Account where Id in:aId];
        List<Contact> con = [select id from contact where AccountId in :aId];
        for(Account a : acc){
            a.count_of_contacts__c=con.size();
        }
        update acc;
    }
    if(Trigger.isDelete){
        for(Contact opp : Trigger.old){
            aId.add(opp.AccountId);
        }
        List<Account> acc = [select id,count_of_contacts__c from Account where Id in:aId];
        List<Contact> con = [select id from contact where AccountId in :aId];
        for(Account a : acc){
            a.count_of_contacts__c=con.size();
        }
        update acc;
    }
John PipkinJohn Pipkin
The issue with using:
a.count_of_contacts__c = con.size();

is that the trigger will not work in bulk. If you do a dataload or DML statement with multiple records on contacts, the contact list size will be the size of both accounts combined. You have to separate the list to make sure you are getting a true count of contacts per account.
manjunath vivekmanjunath vivek
Hi John,

I tried with your code, fo rsome reason, it doesn't work, code gets saved though.
John PipkinJohn Pipkin
Trigger counting on contact(after update,after insert){
	Set<ID> accids=New Set<ID>();
	For(contact c:trigger.new){
		Accids.add(c.AccountId);
	}

	Map<ID,Account> Acc= new Map<ID,Account>([Select ID, count__c from account where id IN:accids ]);
	Map<ID,Account> updateMap = new Map<ID,Account>();
	for(Account ac :Acc.values())
	{
		Integer count = 0;
		for(Contact c:Trigger.New){
			if(ac.Id == c.AccountId)
				count = count + 1;
			
		}
		ac.count__c= count;
		updateMap.put(ac.Id,ac);
	}

	if(!updateMap.isEmpty())
		update updateMap.values();
}

try this one. I had a couple of errors
manjunath vivekmanjunath vivek
Hi Sandeep,

I have tried with your code, still Iam getting the error message
Error: Compile Error: unexpected token: 'from' at line 7 column 45
manjunath vivekmanjunath vivek
Hi John,

Still the same, it doesn't count contacts,but code gets saved.
John PipkinJohn Pipkin
Make sure you are attaching the correct account to the contact. Also, please note that triggers are not retroactive. They will only work going forward. I just tested my code in my dev org and it is working.
John PipkinJohn Pipkin
manjunath, 

Did you get this working?
Dan NapolitanoDan Napolitano
John, I tried your code, but I receive an error saying, "Compile Error: Incorrect SObject type: Contact should be Account at line 1 column 1." I'm very new to writing triggers. If you have any suggestion, I would appreciate it. I'm not even sure if I needed to create a class first before trying to create this trigger. Thanks.
John PipkinJohn Pipkin
Did you create a new Trigger with "Contact" as the assigned SObject? This error normally happens when you try to edit an existing trigger that is assigned to another SObject.
Dan NapolitanoDan Napolitano
I did not, but perhaps I am creating the trigger in the wrong area? I was trying to create the trigger underneath Accounts, since I wanted to count the number of contacts in any given account. (See? I'm like, this new to this.) Should I be trying this by creating the trigger under Contacts?
Dan NapolitanoDan Napolitano
Yup, that's how newbie I am. Now I'm good. THANK YOU!
Dan NapolitanoDan Napolitano
So I hate to ask, but how do I design a test class against this trigger? For day one, anyway, I'm in over my head...
Dan NapolitanoDan Napolitano
So I wrote the following, which seems to have worked. Presumably, I have to deploy it with the trigger to Production:

@isTest 
private class testContactCount {
    static testMethod void testContactCount() {
    Account acc = new Account(Name = 'Testy Account');
insert acc;
 
Contact con = new Contact (LastName = 'Test Contact', AccountId = acc.Id);
insert con;
 
acc = [Select Id, Name, TotContacts__c from Account where Id = :acc.Id];
 
System.assertEquals(1, acc.TotContacts__c);
}
}
John PipkinJohn Pipkin
Dan, 

Use this test class:
 
@isTest 
public class testContactCount {
    static testMethod void testContactCount() {

	    Account acc1 = new Account(Name = 'Testy Account 1');
	    Account acc2 = new Account(Name = 'Testy Account 2');
	    Account acc3 = new Account(Name = 'Testy Account 3');
	    Account acc4 = new Account(Name = 'Testy Account 3');
	    insert new Account[] {acc1,acc2,acc3,acc4};
	    Set<ID> aIds = new Set<ID>();
	    aIds.addAll(new ID[] {acc1.Id,acc2.Id,acc3.Id,acc4.Id});
	 
		Contact con1 = new Contact (LastName = 'Test Contact1', AccountId = acc1.Id);
		Contact con2 = new Contact (LastName = 'Test Contact2', AccountId = acc2.Id);
		Contact con3 = new Contact (LastName = 'Test Contact3', AccountId = acc2.Id);
		Contact con4 = new Contact (LastName = 'Test Contact4', AccountId = acc3.Id);
		Contact con5 = new Contact (LastName = 'Test Contact5', AccountId = acc3.Id);
		Contact con6 = new Contact (LastName = 'Test Contact6', AccountId = acc3.Id);
		insert con1;insert con2;insert con3;insert con4;insert con5;insert con6;
		 
		for(Account a :[Select Id,TotContacts__c from Account where Id in :aIds]){
			if(a.Id == acc1.Id)
				System.assertEquals(1, a.TotContacts__c);
			else if(a.Id == acc2.Id)
		 		System.assertEquals(2, a.TotContacts__c);
		 	else if(a.Id == acc3.Id)
		 		System.assertEquals(3, a.TotContacts__c);
		 	else if(a.Id == acc4.Id)
		 		System.assertEquals(0, a.TotContacts__c);
		
		}
	}
}

This test covers more scenarios. 

Yes, you should deploy this along with the trigger. 

Thanks
Dan NapolitanoDan Napolitano
John, thank you so kindly. Your test case is of course much better than mine! Happy to report, though, that my test case registered 91% code coverage, and I was able to use it to release to Production. I'm going to save yours, though, because Murphy's Law says I will need to create additional triggers, and you just gave me a great template for learning. (I'm a SQL guy with no background in JavaScript, C, etc.) Really appreciate it!