Friday, June 1, 2012

Handling Governor Limits through Trigger


1. Bulkify your code:
Bad Code
trigger accTrggr on Account (before insert, before update) {
//This only handles the first record in the Trigger.new collection
//But if more than one Account initiated this trigger, those additional records
//will not be processed
Account acct = Trigger.new[0];
acct.Description = acct.Name + ':' + acct.BillingState;
}
Correct Code
trigger accTrggr on Account (before insert, before update) {
List accountNames = new List{};
//Loop through all records in the Trigger.new collection
for(Account a: Trigger.new) {
//Concatenate the Name and billingState into the Description field a.Description = a.Name + ':' + a.BillingState;
}}
2. Avoid SOQL Queries inside FOR Loops
Move SOQL queries outside FOR loop
Bad Code
trigger accountTestTrggr on Account (before insert, before update) {
for(Account a: Trigger.new) {
List contacts = [select id, salutation, firstname, lastname, email from Contact where accountId = :a.Id];
for(Contact c: contacts){
c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname;
update c;
} } }
Good Code
trigger accountTestTrggr on Account (before insert, before update) {
List accountsWithContacts = [select id, name, (select id, salutation, description, firstname, lastname, email from Contacts) from Account where Id IN :Trigger.newMap.keySet()];
List contactsToUpdate = new List{};
for(Account a: accountsWithContacts){
for(Contact c: a.Contacts){
c.Description=c.salutation + ' ' + c.firstName + ' ' + c.lastname; contactsToUpdate.add(c);
} }
update contactsToUpdate;
}
3. Bulkify your Helper Methods
  • Similar to the Previous One.
  • All Helper Methods should also be handling Bulk records.
  • For Eg: A inside a method should receive a bulk set of inputs, process in bulk and return the List of Records.
4. Using Collections, Streamlining Queries, and Efficient For Loops
Bad Code
trigger accountTrigger on Account (before delete, before insert, before update) {
//This code inefficiently queries the Opportunity object in two seperate queries
List opptysClosedLost = [select id, name, closedate, stagename from Opportunity where accountId IN :Trigger.newMap.keySet() and StageName='Closed - Lost'];
List opptysClosedWon = [select id, name, closedate, stagename from Opportunity where accountId IN :Trigger.newMap.keySet() and StageName='Closed - Won'];
for(Account a : Trigger.new){
//This code inefficiently has two inner FOR loops
//Redundantly processes the List of Opportunity Lost
for(Opportunity o: opptysClosedLost){
if(o.accountid == a.id)
System.debug('Do more logic here...'); }
//Redundantly processes the List of Opportunity Won
for(Opportunity o: opptysClosedWon){
if(o.accountid == a.id) System.debug('Do more logic here...'); } } }
Good Code
trigger accountTrigger on Account (before delete, before insert, before update) {
/*This code queries all related Closed Lost & Closed Won oppor in a single query. */
List accountWithOpptys = [select id, name, (select id, name, closedate, stagename from Opportunities where accountId IN :Trigger.newMap.keySet() and (StageName='Closed - Lost' or StageName = 'Closed - Won')) from Account where Id IN :Trigger.newMap.keySet()];
//Loop through Accounts only once
for(Account a : accountWithOpptys){
//Loop through related Opportunities only once
for(Opportunity o: a.Opportunities){
if(o.StageName == 'Closed - Won'){
System.debug('Opportunity Closed Won...do some more logic here...');
}else if(o.StageName =='Closed - Lost'){
System.debug('Opportunity Closed Lost...do some more logic here...');
} } } }
5. Streamlining Multiple Triggers on the Same Object
  • Many Triggers for a single Object
  • Order of execution cant be defined
  • All Triggers executing in a single transaction will SHARE the governor limits.
  • Add appropriate conditions for trigger executions
  • Handling of Governor Limits across all the triggers
  • If possible, join the triggers
6. Querying Large Data Sets
Bad Code
//A runtime exception is thrown if this query returns 1001 or more records.
Account [] accts = [SELECT id FROM account];
Good Code
// Use this format for efficiency if you are executing DML statements
// within the for loop
for (List accts : [SELECT id, name FROM account WHERE name LIKE 'Acme']) {
// Your code here
update accts;
}
7. Other Best Practices
  • Use of the Limits Apex Methods to Avoid Hitting Governor Limits
  • Limits.getLimitQueries()
  • Limits.getLimitDmlRows()
  • Enable Apex Governor Limit Warning Emails
  • Write Test Methods to Verify Large Datasets
  • Avoid Hardcoding IDs

No comments:

Post a Comment