🔒

Unlock Interview Q&A

Join the GoSalesforce community to access expert interview questions, career guides, and premium resources.

Q&A Hub

Interview Questions

Master your Salesforce skills with our curated list of interview questions and expert answers.

🔍

Apex Triggers

1. What is Database.SOQL row lock (FOR UPDATE)?

Answer :
Adding FOR UPDATE to SOQL locks the selected records so no other transaction can update them until current transaction completes. Used to prevent race conditions. UNABLE_TO_LOCK_ROW error occurs when multiple concurrent transactions try to lock the same records simultaneously. Resolution: Implement retry logic, reduce batch concurrency, or restructure data processing to avoid shared record access.

2. What are the trigger events in Salesforce?

Answer :
before insert — record not yet saved; can modify field values after insert — record saved; Id available; cannot modify triggering records before update — record not yet saved with changes; can modify fields after update — changes saved; oldMap and newMap available before delete — record not yet deleted; Trigger.old available after delete — record deleted; Trigger.old available after undelete — records restored from Recycle Bin; Trigger.new available Note: There is no 'before undelete'. Only after delete and after undelete exist for delete operations.

3. When do you choose before vs after trigger?

Answer :
Before trigger: When you need to validate or modify the triggering record's fields before it's saved — no DML needed on the same record (just assign field values). Ideal for field population, validation logic. After trigger: When you need the record Id (post-insert), need to update related records, insert child records, or perform actions that shouldn't be part of the save operation. The triggering record is read-only in after context.

4. What is Trigger Framework / Handler Pattern?

Answer :
A trigger framework separates trigger logic from the trigger file itself. The trigger file only contains event routing to a handler class. Benefits: single responsibility, easier testing, recursion control, bypass logic. // Trigger file (thin) trigger AccountTrigger on Account(before insert, after insert, before update, after update) { AccountTriggerHandler handler = new AccountTriggerHandler(); if(Trigger.isBefore && Trigger.isInsert) handler.onBeforeInsert(Trigger.new); if(Trigger.isAfter && Trigger.isInsert) handler.onAfterInsert(Trigger.new, Trigger.newMap); }

5. Write a Trigger: Roll-up count of Contacts on Account.

Answer :
trigger ContactTrigger on Contact(after insert, after update, after delete, after undelete) { Set<Id> accountIds = new Set<Id>(); List<Contact> contacts = Trigger.isDelete ? Trigger.old : Trigger.new; for(Contact c : contacts) { if(c.AccountId != null) accountIds.add(c.AccountId); } if(Trigger.isUpdate) { for(Contact c : Trigger.old) if(c.AccountId != null) accountIds.add(c.AccountId); } List<AggregateResult> results = [SELECT AccountId, COUNT(Id) cnt FROM Contact WHERE AccountId IN :accountIds GROUP BY AccountId]; Map<Id, Integer> countMap = new Map<Id, Integer>(); for(AggregateResult ar : results) countMap.put((Id)ar.get('AccountId'), (Integer)ar.get('cnt')); List<Account> toUpdate = new List<Account>(); for(Id accId : accountIds) { toUpdate.add(new Account(Id = accId, Number_of_Contacts__c = countMap.containsKey(accId) ? countMap.get(accId) : 0)); } update toUpdate; }

6. Write a Trigger: Prevent deletion of Account if related Contacts exist.

Answer :
trigger AccountTrigger on Account(before delete) { Map<Id, Account> accMap = new Map<Id, Account>([SELECT Id, (SELECT Id FROM Contacts LIMIT 1) FROM Account WHERE Id IN :Trigger.old]); for(Account acc : Trigger.old) { if(!accMap.get(acc.Id).Contacts.isEmpty()) { acc.addError('Cannot delete Account with related Contacts.'); } } }

7. Write a Trigger: When Account BillingCity is updated, update all related Contact MailingCity.

Answer :
trigger AccountTrigger on Account(after update) { List<Account> changed = new List<Account>(); for(Account acc : Trigger.new) { if(acc.BillingCity != Trigger.oldMap.get(acc.Id).BillingCity) changed.add(acc); } if(changed.isEmpty()) return; Set<Id> accIds = new Map<Id, Account>(changed).keySet(); List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accIds]; Map<Id, String> cityMap = new Map<Id, String>(); for(Account a : changed) cityMap.put(a.Id, a.BillingCity); for(Contact c : contacts) c.MailingCity = cityMap.get(c.AccountId); update contacts; }

8. Write a Trigger: Only System Admin can delete Tasks.

Answer :
trigger TaskTrigger on Task(before delete) { String profileName = [SELECT Name FROM Profile WHERE Id = :UserInfo.getProfileId()].Name; if(profileName != 'System Administrator') { for(Task t : Trigger.old) t.addError('Only System Administrators can delete tasks.'); } }

9. Write a Trigger: Prevent duplicate Contact based on Email.

Answer :
trigger ContactTrigger on Contact(before insert, before update) { Set<String> emails = new Set<String>(); for(Contact c : Trigger.new) if(c.Email != null) emails.add(c.Email); Map<String, Contact> existingMap = new Map<String, Contact>(); for(Contact c : [SELECT Id, Email FROM Contact WHERE Email IN :emails]) { existingMap.put(c.Email, c); } for(Contact c : Trigger.new) { if(c.Email != null && existingMap.containsKey(c.Email) && existingMap.get(c.Email).Id != c.Id) { c.addError('A contact with this email already exists.'); } } }

10. Write a Trigger: Sum of Opportunity Amounts on Account.

Answer :
trigger OpportunityTrigger on Opportunity(after insert, after update, after delete, after undelete) { Set<Id> accIds = new Set<Id>(); for(Opportunity o : Trigger.isDelete ? Trigger.old : Trigger.new) if(o.AccountId != null) accIds.add(o.AccountId); if(Trigger.isUpdate) for(Opportunity o : Trigger.old) if(o.AccountId != null) accIds.add(o.AccountId); Map<Id, Decimal> sumMap = new Map<Id, Decimal>(); for(AggregateResult ar : [SELECT AccountId, SUM(Amount) total FROM Opportunity WHERE AccountId IN :accIds GROUP BY AccountId]) { sumMap.put((Id)ar.get('AccountId'), (Decimal)ar.get('total')); } List<Account> toUpdate = new List<Account>(); for(Id id : accIds) toUpdate.add(new Account(Id = id, Total_Opportunity_Amount__c = sumMap.containsKey(id) ? sumMap.get(id) : 0)); update toUpdate; }

11. What is the maximum trigger depth in Salesforce?

Answer :
Salesforce allows up to 16 levels of trigger recursion. After 16 recursive calls, a runtime exception is thrown. This is separate from the recursion within a single trigger execution.

💬 Community Chatter

Loading...
🔐

Join the Community Discussion

Login to ask questions, share answers, and connect with other Salesforce professionals.

Welcome Back

OR
Don't have an account? Sign up