Example : On Lead we have custom lookup field named Company Owner(User), also Company(Account) field. On Account we have custom field called CEO(User), While creating Lead If Linked Company has SEO then populate that in Company Owner.
Solution
LeadTriggerHandler
public class LeadTriggerHandler {
// Approach 1 Single Record
public static void updateLeadBeforeInsert(List<Lead> leadDetails) {
System.debug(leadDetails);
Id accId = leadDetails[0].Company__c;
System.debug(leadDetails[0].Company__c);
List<Account> account = [Select Id, CEO__c From Account where Id=: accId];
System.debug(account);
leadDetails[0].Company_Owner__c = account[0].CEO__c;
}
// Approach 2 Bulk Records
public static void updateBulkLeadsBeforeInsert(List<Lead> leadDetails){
// Prepare all Account Ids
Set<id> accIds = new Set<Id>();
For(Lead lead: leadDetails) {
accIds.add(lead.Company__c);
}
List<Account> accounts = [Select Id, CEO__c From Account where Id in: accIds];
Map<Id, Account> accountsRecMap = New Map<Id, Account>(accounts);
System.debug(accountsRecMap);
For(Lead lead: leadDetails) {
if(accountsRecMap.containsKey(lead.Company__c)) {
Account acc = accountsRecMap.get(lead.Company__c);
lead.Company_Owner__c = acc.CEO__c;
}
}
}
} LeadTrigger
trigger LeadTrigger on Lead (before insert) {
if(trigger.isBefore && trigger.isInsert) {
LeadTriggerHandler.updateLeadBeforeInsert(trigger.new);
}
} How the code works
The goal is to copy a value from a parent record (the CEO of the Account) to a child record (the Company Owner on the Lead) before the Lead is saved. The handler gives two approaches.
- Approach 1 (single record) reads only the first Lead in the list, queries its Account and copies
CEO__ctoCompany_Owner__c. - Approach 2 (bulk) collects all Account Ids, queries the Accounts once, stores them in a Map and then sets the owner on every Lead.
Problems to know about
- The trigger in this post calls the single-record method. If you import 200 Leads, only the first one is updated.
- Approach 1 fails with a List index out of bounds error when a Lead has no Company, because the query returns no rows and
account[0]does not exist. - Approach 2 works for many Leads, but it adds a null Id to the Set when a Lead has no Company.
Improved bulk handler
public class LeadTriggerHandler {
public static void updateBulkLeadsBeforeInsert(List<Lead> leadDetails) {
Set<Id> accIds = new Set<Id>();
for (Lead l : leadDetails) {
if (l.Company__c != null) {
accIds.add(l.Company__c);
}
}
Map<Id, Account> accountsRecMap = new Map<Id, Account>([SELECT Id, CEO__c FROM Account WHERE Id IN :accIds]);
for (Lead l : leadDetails) {
Account acc = accountsRecMap.get(l.Company__c);
if (acc != null) {
l.Company_Owner__c = acc.CEO__c;
}
}
}
} trigger LeadTrigger on Lead (before insert) {
LeadTriggerHandler.updateBulkLeadsBeforeInsert(Trigger.new);
} Why before insert
In a before trigger you can change the fields of the records in Trigger.new directly. No extra DML statement is needed, because Salesforce saves the changed values for you.
How to test
- Create an Account and set its CEO__c to a user.
- Create a Lead with that Account in Company__c. Company_Owner__c should be filled with the same user.
- Create a Lead without a Company. It should save without an error.
- Import 200 Leads with Data Loader and check that all of them were updated.
FAQ
Why use a Map?
The Map lets each Lead find its Account instantly, without another query.
Do I need an update statement?
No. In a before trigger, changes to Trigger.new are saved automatically.