Salesforce Developer – Apex Triggers Questions

Apex triggers are essential for implementing complex business logic that cannot be achieved through declarative tools. These questions cover trigger purpose and use cases, trigger events and execution order, before vs. after trigger differences, trigger context variables, bulk pattern importance, recursive execution prevention, trigger architecture best practices, handler class implementation, trigger framework benefits, new record creation in triggers, cross-object field updates, trigger testing strategies, mixed DML error handling, trigger performance optimization, and future considerations. Understanding triggers is crucial for any Salesforce Developer working with complex data operations.

Apex Triggers - Q&A

  1. Q1. What is an Apex trigger and when would you use it?
    Ans: An Apex trigger is a piece of code that executes before or after specific data manipulation events (insert, update, delete, merge, etc.) occur on Salesforce records. Triggers are used when: - Complex validation beyond declarative tools is needed - Cross-object updates are required - Asynchronous processing is necessary - Custom logging or auditing is implemented
  2. Q2. Explain the different trigger events and their execution order.
    Ans: Trigger events include: - before insert, after insert - before update, after update - before delete, after delete - after undelete Execution order for insert/update: 1. before triggers 2. Validation rules 3. after triggers 4. Assignment rules 5. Auto-response rules 6. Workflow rules 7. Process Builder 8. Commits to database
  3. Q3. What is the difference between before and after triggers?
    Ans: Key differences: - Before triggers: Execute before saving to database, used to modify field values (no ID available) - After triggers: Execute after saving (ID available), used for cross-object updates - Before triggers are more efficient for validation as they prevent unnecessary DML
  4. Q4. Explain the concept of trigger context variables.
    Ans: Special variables available in triggers: - Trigger.isBefore/Trigger.isAfter - Trigger.isInsert/Trigger.isUpdate/etc. - Trigger.new (new versions of records) - Trigger.old (old versions in update/delete) - Trigger.newMap/Trigger.oldMap (record ID maps) - Trigger.size (number of records)
  5. Q5. What is the trigger execution bulk pattern and why is it important?
    Ans: The bulk pattern ensures triggers handle multiple records efficiently: - Process all records in collections, not individually - Move queries/DML outside loops - Use maps for efficient lookups This prevents hitting governor limits when processing large datasets.
  6. Q6. How do you prevent recursive trigger execution?
    Ans: Common techniques: - Static boolean flags to track execution state - Handler class pattern with execution control - Custom settings to track processed records - Platform Cache for complex scenarios
  7. Q7. What are the best practices for trigger architecture?
    Ans: Recommended practices: - One trigger per object (logic in handler classes) - Logic-free triggers (delegate to handler classes) - Bulk-safe processing - Proper error handling - Test coverage > 75%
  8. Q8. How do you implement a trigger handler class?
    Ans: Example pattern:
    public class AccountTriggerHandler {
      public static void onBeforeInsert(List newAccounts) {
        for(Account acc : newAccounts) {
          // Validation logic
          if(acc.Name == null) {
            acc.addError('Account name is required');
          }
        }
      }
      
      public static void onAfterInsert(List newAccounts) {
        // Cross-object update logic
        updateRelatedRecords(newAccounts);
      }
    }
  9. Q9. What are the benefits of using a trigger framework?
    Ans: Framework advantages: - Consistency: Standardized trigger structure - Maintainability: Centralized logic - Testability: Easier unit testing - Control: Execution control and monitoring - Reusability: Common utility methods
  10. Q10. How do you create new records in a trigger without causing recursion?
    Ans: Best practices: - Use static variables to track creation state - Create records in after triggers (ID available) - Use separate handler methods for creation logic - Implement proper error handling Example:
    if(Trigger.isAfter && Trigger.isInsert) {
      List contactsToCreate = new List();
      for(Account acc : Trigger.new) {
        contactsToCreate.add(new Contact(
          LastName = 'Primary',
          AccountId = acc.Id
        ));
      }
      insert contactsToCreate;
    }
  11. Q11. How do you handle cross-object field updates in triggers?
    Ans: Cross-object update pattern:
    // After update trigger on Opportunity
    if(Trigger.isAfter && Trigger.isUpdate) {
      Map accountsToUpdate = new Map();
      
      for(Opportunity opp : Trigger.new) {
        Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
        // Check if relevant field changed
        if(opp.StageName != oldOpp.StageName && opp.StageName == 'Closed Won') {
          accountsToUpdate.put(opp.AccountId, new Account(
            Id = opp.AccountId,
            Last_Won_Opportunity_Date__c = System.today()
          ));
        }
      }
      
      if(!accountsToUpdate.isEmpty()) {
        update accountsToUpdate.values();
      }
    }
  12. Q12. How do you test triggers effectively?
    Ans: Testing strategies: - Test all trigger events (insert, update, delete) - Test bulk operations (200+ records) - Test positive and negative scenarios - Test error handling - Use @testSetup for common data Example:
    @isTest
    static void testAccountTrigger() {
      // Test data
      List testAccounts = new List();
      for(Integer i = 0; i < 200; i++) {
        testAccounts.add(new Account(Name = 'Test ' + i));
      }
      
      // Test insert
      Test.startTest();
      insert testAccounts;
      Test.stopTest();
      
      // Verify results
      List insertedAccounts = [SELECT Id, Status__c FROM Account WHERE Id IN :testAccounts];
      for(Account acc : insertedAccounts) {
        System.assertEquals('Active', acc.Status__c);
      }
    }
  13. Q13. How do you handle mixed DML errors in triggers?
    Ans: Mixed DML solutions: - Future methods: Separate user and setup object operations - Queueable Apex: Chain operations asynchronously - Platform Events: Event-driven processing Example with future method:
    // Trigger handler
    if(Trigger.isAfter && Trigger.isUpdate) {
      List usersToUpdate = new List();
      // Collect user updates
      System.enqueueJob(new UserUpdateQueueable(usersToUpdate));
    }
    
    // Queueable class
    public class UserUpdateQueueable implements Queueable {
      private List users;
      public UserUpdateQueueable(List users) {
        this.users = users;
      }
      public void execute(QueueableContext qc) {
        update users; // Now allowed in async context
      }
    }
  14. Q4. What are the performance considerations for triggers?
    Ans: Optimization techniques: - Selective queries: Use indexed fields in WHERE clauses - Bulk processing: Process collections, not individual records - Efficient collections: Use Maps for lookups, Sets for uniqueness - Limit DML: Combine operations, use Database methods - Avoid SOQL/SOSL in loops: Move outside trigger context - Use custom indexes: For frequently queried fields
  15. Q15. What should you consider when migrating from workflow rules to triggers?
    Ans: Migration considerations: - Execution order: Triggers execute before/after, workflows after - Bulk processing: Ensure workflow logic works in bulk - Error handling: Workflows don't cause trigger rollbacks - Field updates: Replace with Apex logic - Email alerts: Implement with Messaging.SingleEmailMessage - Testing: Create comprehensive test coverage

Back to Developer Home