Build a Bulk-Safe Trigger
By the end of this lesson, you'll be able to:
- Write the thin trigger and handler skeleton for Leave_Request__c
- Query every existing leave request for the affected employees, once
- Explain why this query happens before, not during, the per-record validation loop
Prerequisites: "Design the Approval Workflow"
The thin trigger
trigger LeaveRequestTrigger on Leave_Request__c (before insert) {
new LeaveRequestTriggerHandler().beforeInsert(Trigger.new);
}
trigger LeaveRequestTrigger on Leave_Request__c (before insert) {— exactly Module 24's thin-trigger pattern —before insert, since overlap validation must block the save (Module 26'saddError()lesson), which only works in abeforecontext.new LeaveRequestTriggerHandler().beforeInsert(Trigger.new);— hands off to the handler.}— closes the trigger.
Fetching existing requests in one query
public void beforeInsert(List<Leave_Request__c> newRequests) {
Set<String> employeeNames = new Set<String>();
for (Leave_Request__c req : newRequests) {
employeeNames.add(req.Employee_Name__c);
}
List<Leave_Request__c> existingRequests = [
SELECT Id, Employee_Name__c, Start_Date__c, End_Date__c
FROM Leave_Request__c
WHERE Employee_Name__c IN :employeeNames AND Status__c != 'Rejected'
];
// ... validation logic uses existingRequests (next lessons) ...
}
public void beforeInsert(List<Leave_Request__c> newRequests) {— the method.Set<String> employeeNames = new Set<String>();— this is Module 16'sSetdeduplication.for (Leave_Request__c req : newRequests) {— loops over the new requests, in memory.employeeNames.add(req.Employee_Name__c);— collects every affected employee's name once.}— closes the loop.- (blank line)
List<Leave_Request__c> existingRequests = [— one upfront query.SELECT Id, Employee_Name__c, Start_Date__c, End_Date__c— the fields needed.FROM Leave_Request__c— the object.WHERE Employee_Name__c IN :employeeNames AND Status__c != 'Rejected'— all of their existing, non-rejected requests in a single statement.];— closes the query.// ... validation logic uses existingRequests (next lessons) ...— the next step, before any per-record comparison starts.}— closes the method.
Why the query happens before the validation loop
// WRONG — a query per new request, exactly the anti-pattern from Module 25
for (Leave_Request__c req : newRequests) {
List<Leave_Request__c> existing = [SELECT Id FROM Leave_Request__c WHERE Employee_Name__c = :req.Employee_Name__c];
// ...
}
// WRONG — a query per new request, exactly the anti-pattern from Module 25— the label says it all.for (Leave_Request__c req : newRequests) {— loops over the new requests.List<Leave_Request__c> existing = [SELECT Id FROM Leave_Request__c WHERE Employee_Name__c = :req.Employee_Name__c];— querying inside the per-record loop would be the SOQL-in-a-loop problem from Module 25, at exactly the scale this feature is most likely to face — a bulk data load inserting hundreds of leave requests at once.// ...— the rest of the loop body.}— closes the loop.
Fetching everything needed before the loop begins is what keeps the actual comparison loop (next lesson) free of any database operation at all.
Exercise
Given a List<Leave_Request__c> newRequests, write the Set<String> collection of unique Employee_Name__c values.
Show hint
Loop over newRequests, adding each Employee_Name__c to a Set<String>.
Build a Bulk-Safe Trigger Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
This lesson sets up the trigger, handler, and — critically — the single upfront query that fetches every existing leave request the validation logic will need, before any per-record checking begins.