Keeping your Salesforce data aligned across related records is not just good practice—it’s essential for maintaining trust in your CRM. One common but impactful scenario involves keeping the Contact records updated when key information changes on the parent Account.
In this blog, we explore an Apex trigger that uses Parent-to-Child SOQL to automatically update the HomePhone
field of all related Contacts whenever the Phone
field of an Account is modified. This solution ensures your Contact records always reflect the latest account-level phone number—without relying on users to manually update anything.
The trigger is optimized using relationship queries (also known as nested SOQL or subqueries), making it efficient and easy to scale for orgs with standard parent-child object relationships.
🧠 Why This Trigger Matters
In Salesforce, the Phone
field on the Account often represents the central business number or primary contact line. In many business setups, this number should also reflect on the Contacts—especially for roles like receptionists, billing contacts, or general-purpose support representatives.
Manually updating this field on every related Contact is tedious, error-prone, and inefficient. With this trigger in place:
-
Any change to the Account phone number is automatically cascaded to its Contacts
-
Your CRM records stay clean, accurate, and consistent
-
You save time, reduce manual data entry, and eliminate oversight
-
Every team (sales, service, operations) stays in sync when contacting the customer
This automation is a perfect example of making Salesforce smarter with minimal code.
🔍 What This Blog Covers
-
How to detect field-level changes using
Trigger.oldMap
-
How to write Parent-to-Child SOQL (relationship queries) to fetch Contacts under updated Accounts
-
How to conditionally update Contact records based on a parent’s field change
-
Best practices for writing bulk-safe Apex code
-
Where this pattern fits in your org’s data alignment strategy
-
How to use handler classes for clean logic separation
This solution provides a scalable way to maintain accurate child record data based on parent changes—an essential need in multi-object CRM relationships.
🎯 Real-World Use Cases for This Trigger
-
Sales teams needing consistent phone numbers across Account and Contact pages
-
Customer service reps who rely on Contact records for outreach
-
Operations teams who generate documents or emails using Contact fields
-
Admin teams who want automatic data propagation across related objects
-
Organizations with data integration tools that use Contact fields in sync jobs
This pattern is especially helpful when using exports, mass email campaigns, or customer outreach tools that pull directly from Contact-level fields.
👨💻 Developer & Admin Tips
The trigger runs in the after update context to ensure the Account’s Phone
value has already been committed and is available for downstream logic.
Here’s how the logic works:
-
First, we loop through all incoming Account records and compare their
Phone
field with the old value fromTrigger.oldMap
-
If the phone has changed, we collect the relevant
Account Ids
into aSet<Id>
-
Using Parent-to-Child SOQL, we query the related
Contacts
using a subquery:SELECT Id, Phone, (SELECT HomePhone FROM Contacts) FROM Account WHERE Id IN :accIds
-
Then, we loop through the subquery results and update each related Contact’s
HomePhone
with the new AccountPhone
value -
Finally, we update all changed Contact records in a single DML statement
This approach is fully bulk-safe and avoids hitting governor limits by batching the logic and minimizing queries.
Keep in mind:
-
You should only run this logic when the
Phone
field is actually changed -
The trigger is written in a handler method (
updateRelatedContsWithoutMap
) to promote reusability and better test coverage -
You can easily extend this pattern to support syncing additional fields such as Fax, Website, or Billing Address if needed
🎥 Visual Walkthrough – YouTube Playlist Available
Prefer learning by doing? We’ve included this trigger walkthrough in the Salesforce Makes Sense YouTube playlist. You’ll see:
-
How Parent-to-Child SOQL works
-
How the trigger logic is structured
-
How to test the result in your dev org or sandbox
The playlist offers a clean, visual approach to understanding real-time Salesforce automation—perfect for admins, developers, and learners at any level.
Solution:
trigger AccountTrigger on Account (after update) {
if(Trigger.isUpdate){ if(Trigger.isAfter){
AccountTriggerHandler.updateRelatedConts(Trigger.New, Trigger.oldMap);
}
}
}
public class AccountTriggerHandler {
public static void updateRelatedContsWithoutMap(List<Account> accList,Map<Id,Account> oldMap){
List<Contact> conList=new List<Contact>(); Set<Id> accIds = new
Set<Id>(); for(Account acc:accList){ if((acc.Phone!=null &&
acc.Phone!=(oldMap.get(acc.Id).Phone))
&& oldMap!=null){ accIds.add(acc.Id);
}
}
for(Account acc : [SELECT Id, Phone, (SELECT HomePhone FROM
Contacts) FROM Account WHERE Id IN:
accIds]){ if(acc.Contacts != null){
for(Contact con : acc.Contacts){ con.HomePhone=acc.Phone;
conList.add(con);
}
}
} if(!conList.isEmpty()){ update
conList;
}
}
}