HomeOur TeamContact

Salesforce Trigger Context Variables Explained

By Nick Huber
Published in Developer
October 20, 2024
2 min read
Salesforce Trigger Context Variables Explained

Salesforce Trigger Context Variables Explained

Understanding trigger context variables is essential for any Salesforce developer working with Apex triggers. These variables provide valuable information about the state of records and the context in which the trigger is executing. In this blog post, we’ll explore the various trigger context variables, how to use them effectively, and best practices for leveraging them in your Apex triggers.

What Are Trigger Context Variables?

Trigger context variables are special variables that are available within Apex triggers. They provide context about the records and the operation that is being performed. These variables help you write logic that responds appropriately to different trigger events and scenarios.

Common Trigger Context Variables

Here are some of the most commonly used trigger context variables:

  • Trigger.isInsert: Returns true if the trigger was fired due to an insert operation.
  • Trigger.isUpdate: Returns true if the trigger was fired due to an update operation.
  • Trigger.isDelete: Returns true if the trigger was fired due to a delete operation.
  • Trigger.isBefore: Returns true if the trigger is a before trigger.
  • Trigger.isAfter: Returns true if the trigger is an after trigger.
  • Trigger.new: Returns a list of the new versions of the sObject records.
  • Trigger.old: Returns a list of the old versions of the sObject records.
  • Trigger.newMap: Returns a map of IDs to the new versions of the sObject records.
  • Trigger.oldMap: Returns a map of IDs to the old versions of the sObject records.
  • Trigger.size: Returns the total number of records in the trigger invocation.

Using Trigger Context Variables

Let’s explore how to use these context variables in your Apex triggers with practical examples.

1. Determining the Trigger Event

You can use context variables to determine the type of operation that caused the trigger to fire.

trigger ContactTrigger on Contact (before insert, before update, before delete) {
if (Trigger.isInsert) {
// Logic for insert operation
} else if (Trigger.isUpdate) {
// Logic for update operation
} else if (Trigger.isDelete) {
// Logic for delete operation
}
}

2. Accessing New and Old Records

In update triggers, you might need to compare the new and old values of records.

trigger OpportunityTrigger on Opportunity (before update) {
for (Opportunity opp : Trigger.new) {
Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
// Check if the 'StageName' field has changed
if (opp.StageName != oldOpp.StageName) {
// Implement logic when the stage changes
}
}
}

3. Using Trigger.new and Trigger.old

Trigger.new and Trigger.old are available in different trigger contexts:

  • Trigger.new: Available in before and after insert and update triggers, and undelete triggers.
  • Trigger.old: Available in update and delete triggers.

4. Working with Maps

Using Trigger.newMap and Trigger.oldMap provides efficient access to records by their IDs.

trigger AccountTrigger on Account (before update) {
Map<Id, Account> oldAccounts = Trigger.oldMap;
for (Account acc : Trigger.new) {
Account oldAcc = oldAccounts.get(acc.Id);
// Compare old and new values
if (acc.Name != oldAcc.Name) {
// Name has changed
}
}
}

Best Practices for Using Trigger Context Variables

1. Bulkify Your Code

Always design your triggers to handle multiple records efficiently.

trigger LeadTrigger on Lead (after insert) {
List<Task> tasksToCreate = new List<Task>();
for (Lead lead : Trigger.new) {
Task task = new Task(
Subject = 'Follow up',
WhoId = lead.Id,
OwnerId = lead.OwnerId
);
tasksToCreate.add(task);
}
if (!tasksToCreate.isEmpty()) {
insert tasksToCreate;
}
}

2. Avoid Hardcoding IDs and Values

Use dynamic methods to reference metadata instead of hardcoding.

// Avoid hardcoding
String recordTypeId = '01230000000ABC';
// Use dynamic retrieval
String recordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Business').getRecordTypeId();

3. Use Conditional Logic Wisely

Ensure your trigger logic executes only under the correct conditions.

if (Trigger.isBefore && Trigger.isInsert) {
// Logic specific to before insert
}

4. Handle Null Values

Always check for null values to prevent runtime exceptions.

for (Case c : Trigger.new) {
if (c.ContactId != null) {
// Logic when ContactId is not null
}
}

5. Leverage Trigger.size

Use Trigger.size to get the number of records being processed.

System.debug('Number of records in this trigger: ' + Trigger.size);

Understanding Trigger Execution Order

Knowing the order of execution helps in designing triggers that work harmoniously with other automation tools like workflows and process builders.

  1. System Validation Rules
  2. Before Triggers
  3. Custom Validation Rules
  4. After Triggers
  5. Assignment Rules
  6. Auto-response Rules
  7. Workflow Rules
  8. Processes
  9. Escalation Rules
  10. Entitlement Rules

Common Pitfalls to Avoid

1. Recursive Trigger Execution

Triggers that update records can cause themselves to re-execute indefinitely.

Solution: Implement logic to prevent recursion.

public class TriggerUtility {
public static Boolean isFirstRun = true;
}
trigger ContactTrigger on Contact (before update) {
if (TriggerUtility.isFirstRun) {
TriggerUtility.isFirstRun = false;
// Your logic here
}
}

2. Exceeding Governor Limits

Performing SOQL queries or DML operations inside loops can quickly exceed Salesforce governor limits.

Solution: Move queries and DML operations outside loops.

// Bad Practice
for (Account acc : Trigger.new) {
List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
// Process contacts
}
// Best Practice
Set<Id> accountIds = new Set<Id>();
for (Account acc : Trigger.new) {
accountIds.add(acc.Id);
}
List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds];
// Process contacts outside the loop

Testing Triggers with Context Variables

Writing robust unit tests ensures your triggers function as expected.

@isTest
private class OpportunityTriggerTest {
@isTest static void testStageChange() {
Opportunity opp = new Opportunity(
Name = 'Test Opportunity',
StageName = 'Prospecting',
CloseDate = Date.today().addDays(30)
);
insert opp;
opp.StageName = 'Qualification';
update opp;
// Retrieve the updated opportunity
Opportunity updatedOpp = [SELECT StageName FROM Opportunity WHERE Id = :opp.Id];
System.assertEquals('Qualification', updatedOpp.StageName);
}
}

Conclusion

Trigger context variables are powerful tools that provide critical information about the execution context of your Apex triggers. By mastering these variables, you can write more efficient, reliable, and maintainable code.

Key Takeaways:

  • Understand the purpose of each context variable and when it is available.
  • Use Trigger.new and Trigger.old to access the new and old versions of records.
  • Employ conditional logic to execute code in the appropriate trigger context.
  • Bulkify your code to handle multiple records and stay within governor limits.
  • Prevent recursive triggers and handle exceptions gracefully.

By applying these principles, you’ll enhance your ability to create sophisticated automation solutions within Salesforce.

Learn more about Apex Triggers

Happy coding on your Salesforce journey!


Share

Previous Article
Apex Triggers: Best Practices and Common Pitfalls
Nick Huber

Nick Huber

Architect

Related Posts

Apex Triggers: Best Practices and Common Pitfalls
October 20, 2024
2 min
© 2024, All Rights Reserved.
Made with ❤️

Quick Links

Advertise with usAbout UsContact Us

Social Media