As a leading CRM platform, Salesforce allows extensive customization to meet diverse business needs. One such powerful feature of Salesforce is Apex Triggers, which are used to perform operations before or after record modifications. However, to ensure optimal performance and avoid hitting governor limits, it’s crucial to understand and implement bulkification of triggers. This article will delve into the concept of bulkification, its importance, and how to implement it with practical examples.
What is Bulkification in Salesforce?
Bulkification refers to the practice of designing Apex code to handle multiple records at once, rather than one record at a time. This approach is essential in Salesforce due to the platform’s multi-tenant architecture, where resources are shared among many users. Governor limits are set to ensure no single user monopolizes shared resources. Bulkification helps in adhering to these limits and ensures that your code runs efficiently even when processing large data volumes.
Why is Bulkification Important?
- Performance Optimization: Handling multiple records in a single transaction minimizes the number of database operations, leading to faster execution.
- Governor Limits Compliance: Salesforce imposes limits on the number of DML operations, SOQL queries, and other resources. Bulkified code is less likely to exceed these limits.
- Scalability: As one’s organization grows and data volume increases, bulkified triggers will scale better and maintain performance.
Bulkification Best Practices
- Use Collections: Instead of operating on single records, use collections like lists, sets, or maps to process multiple records in one go.
- Avoid SOQL/DML in Loops: Placing SOQL queries or DML operations inside loops can quickly exceed governor limits. Always move these operations outside loops.
- Efficient Querying: Retrieve all necessary data in a single SOQL query to minimize the number of queries and avoid hitting the query limit.
Learn more about Salesforce Apex Best Practices.
Bulkification of Apex Triggers Example: Update Contact
Let’s consider an example scenario where the field ‘Description’ in the Contact object gets updated whenever the value in the field ‘Phone’ in the Account object is changed. A non-bulkified trigger for the above scenario would be:
Non-Bulkified Trigger:
trigger UpdateContactsNoBulk on Account (after update) {
for (Account acc : Trigger.new) {
Account oldAcc = Trigger.oldMap.get(acc.Id);
if (acc.Phone != oldAcc.Phone) {
List<Contact> contacts = [SELECT Id, AccountId FROM Contact
WHERE AccountId = :acc.Id];
for (Contact con : contacts) {
con.Description = 'Phone number is updated. Check the
related Account Phone field.';
update con;
}
}
}
}
The UpdateContactsNoBulk trigger is executed on Account when the value of ‘Phone’ is updated. First, the trigger collects the Id of the account whose phone number has been changed in a list called ‘contacts’. Then it updates the ‘Description’ field of the related contacts of that particular account by iterating the ‘contacts’ list.
Though the above trigger works fine, there are a few problems with this trigger:
- The SOQL query is inside a loop.
- The DML operations are performed inside a loop.
- The trigger is inefficient and likely to hit governor limits with large data volumes.
Now let’s take a look at how to write a trigger with bulkification for the same scenario:
Bulkified Trigger:
trigger UpdateContactsBulkified on Account (after update) {
Set<Id> accountIds = new Set<Id>();
for (Account acc : Trigger.new) {
Account oldAcc = Trigger.oldMap.get(acc.Id);
if (acc.Phone != oldAcc.Phone) {
accountIds.add(acc.Id);
}
}
if (!accountIds.isEmpty()) {
List<Contact> contactsToUpdate = new List<Contact>();
List<Contact> contacts = [SELECT Id, AccountId FROM Contact
WHERE AccountId IN :accountIds];
for (Contact con : contacts) {
con.Description = 'Phone number is updated. Check the
related Account Phone field.';
contactsToUpdate.add(con);
}
if (!contactsToUpdate.isEmpty()) {
update contactsToUpdate;
}
}
}
In the improved trigger UpdateContactsBulkified, we have made the following modifications:
- The SOQL query is outside the loop and uses a collection to handle multiple records.
- The DML operation is performed once on a collection of records.
- The trigger is efficient and adheres to governor limits, even with large data volumes.
Conclusion
Bulkification is a fundamental concept in Salesforce Apex programming, crucial for maintaining the performance and scalability of your applications. By following best practices such as using collections, avoiding SOQL/DML in loops, and efficient querying, you can ensure your triggers are optimized and compliant with Salesforce governor limits. Implementing these practices not only enhances the performance of your code but also ensures a seamless experience for users as your data volume grows.