Let’s say – The parent object is Account, The child object is Contact, We want to update the child field Status__c to ‘Primary’ only if that contact is the only contact related to the parent Account.
Trigger:
trigger SetDefaultStatusForOnlyChild on Contact (after insert, after delete, after undelete) {
Set<Id> accountIds = new Set<Id>();
if (Trigger.isInsert || Trigger.isUndelete) {
for (Contact con : Trigger.new) {
if (con.AccountId != null) {
accountIds.add(con.AccountId);
}
}
}
if (Trigger.isDelete) {
for (Contact con : Trigger.old) {
if (con.AccountId != null) {
accountIds.add(con.AccountId);
}
}
}
if (accountIds.isEmpty()) return;
// Query all contacts grouped by account
Map<Id, List<Contact>> accountToContactsMap = new Map<Id, List<Contact>>();
for (Contact con : [
SELECT Id, AccountId, Status__c
FROM Contact
WHERE AccountId IN :accountIds
]) {
if (!accountToContactsMap.containsKey(con.AccountId)) {
accountToContactsMap.put(con.AccountId, new List<Contact>());
}
accountToContactsMap.get(con.AccountId).add(con);
}
List<Contact> contactsToUpdate = new List<Contact>();
for (Id accId : accountToContactsMap.keySet()) {
List<Contact> contacts = accountToContactsMap.get(accId);
if (contacts.size() == 1) {
Contact onlyChild = contacts[0];
if (onlyChild.Status__c != 'Primary') {
onlyChild.Status__c = 'Primary';
contactsToUpdate.add(onlyChild);
}
}
}
if (!contactsToUpdate.isEmpty()) {
update contactsToUpdate;
}
}
Key Concepts:
- Trigger Events: We use after insert, after delete, and after undelete because:
- Insert may result in the first or second child.
- Delete may leave only one child behind.
- Undelete may change the count from one to two or more.