Your query of Contact where clause uses AccountId instead of id
public class Contact_Phone_Handler{
public static void perform_AfterUpdate(List<Account>newList, Map<Id,Account>oldMapAcc){
Map<Id,Account> AccID = new Map<Id,Account>();
for(Account acc : newList){
Account oldAcc=oldMapAcc.get(acc.id);
if(acc.phone != oldAcc.phone){
AccId.put(acc.id,acc);
}
}
List<Contact> Con = [SELECT Id, phone, AccountId
FROM Contact where AccountId IN : AccId.KeySet()];
for(Contact c : Con){
Account acc=AccId.get(c.accountId);
c.phone = acc.phone;
}
if(Con.size()>0 && Con != null){
update Con;
}
}
}
There are couple of logical issues
The addError
needs to be on the object's trigger context. In this scenario add the Error on the Account Trigger and not on the contact. In your Contact trigger context, addError won't throw an error unless you add an error on the triggered contact record. I would simply move the addError part of the logic to a before update trigger on the Account.
trigger triggerContact on Account ( before update) {
Integer maxChildRecord = 5;
for(Account acc: trigger.new) {
if(dbChildCount > maxChildRecord) {
acc.addError('can not add more child!'');
}
}
}
The above logic could also be a simple validation rule.
- Make sure your trigger context is after Insert, after update and after delete, and your trigger code logic for contact count should not run on before triggers.
Few code pointers, do not have logic inside Trigger and try to move your logic to a Helper class or adopt a Trigger Framework for better maintainability.
Update
Now since your preference is to keep all the logic on Contact itself here is how I would modify the code,
trigger triggerContact on Contact (before insert, before update, after insert, after update, after delete) {
Integer maxChildRecord = 5;
List<Contact> contacts = Trigger.isDelete ? Trigger.old : Trigger.new;
Map<Id, List<Contact>> mapAcctIdContactList = new Map<Id, List<Contact>>();
for(Contact c : contacts) {
if(String.isNotBlank(c.AccountId)){
if(!mapAcctIdContactList.containsKey(c.AccountId)) {
mapAcctIdContactList.put(c.AccountId, new List<Contact>());
}
mapAcctIdContactList.get(c.AccountId).add(c);
}
}
Map<Id, Account> accountMap = new Map<Id, Account>();
for (AggregateResult ar : [SELECT AccountId AcctId, Count(id) ContactCount
FROM Contact
WHERE AccountId in: mapAcctIdContactList.keyset()
GROUP BY AccountId]){
accountMap.put((Id)ar.get('AcctId'), new Account(Id = (Id)ar.get('AcctId'), Contact_Count__c = (Integer)ar.get('ContactCount')));
}
List<Account> acctsToRollup = new List<Account>();
for(Account account : accountMap.values()) {
Integer dbChildCount = (Integer)account.Contact_Count__c;
Account a = new Account();
a.Id = account.Id;
a.Contact_Count__c = (Integer)account.Contact_Count__c;
if (dbChildCount > maxChildRecord){
for(Contact c: mapAcctIdContactList.get(account.Id) {
c.addError('can not add more child!');
}
}else {
acctsToRollup.add(a);
}
}
if (acctsToRollup.size() > 0) {
update acctsToRollup;
}
Carefully note how I am storing all contacts for the Account that came in through (trigger.new/trigger.old) using the data structure Map<Id, List<Contact>>
Best Answer
I think the issue is with your handler class: if there are no Subject Visits left when you delete then you need to query the parent Site record not the child records. One approach I've seen is to query the parent records with a subquery of the child records and setting the parent record to the size of the child list.