Apex Triggers in Salesforce
Apex Triggers in Salesforce
As companies begin to expand the number of ways in which they use Salesforce within their organization, they look for more in-depth and automated ways to take care of specific tasks in the system. And ever-expanding reliance on Salesforce means that manual tasks can become a huge slow down across your organization. Apex triggers within
Salesforce are designed to help you automate certain tasks. Apex triggers allow you to perform custom actions before and after events in Salesforce. These events can include things such as data insertions, updates to existing data, or deletions.
Let's take a look at what Apex triggers are in Salesforce, how they are typically used, and why they may be a benefit to your organization. What are Apex Triggers in Salesforce?
A Salesforce trigger is an apex script that executes either before or after a data manipulation language (DML) event occurs. Some examples of what data manipulation language events include are actions like inserting new records into a database, deleting records from a database, updating records within your sales force, or generally manipulating
data through the system. Apex triggers allow you to perform tasks that are not possible using the point-and-click tools in the Salesforce user interface. Apex triggers are designed to allow you to perform custom actions either before or after the data manipulation language event takes place. Apex scripts are written in the Apex language, triggered
either before or after the data manipulation takes place.
There are two different types of Apex triggers within Salesforce: “Before” Apex Triggers. These are used to update or validate the value in a record before you save it to your Salesforce database. “After” Apex Triggers. These are used to access the values contained within a record and use that value to make changes to other records in your Salesforce
database. Unlike “Before” triggers, “After” triggers are read-only. Both types of triggers are useful for managing records and executing additional actions after manipulating data within your Salesforce database.
Here is what an Apex Trigger script looks like: Trigger trigger Name on sObject(Trigger event) { //logic } That is a default setting. They are able to process multiple different records simultaneously. Both triggers can handle single or book operations including data Imports, bulk API calls, and bulk actions. Apex triggers can be executed after a
number of different actions are taken within the Salesforce system including: before insert before update before delete after insert after update after delete after undelete Triggers can be defined for any top-level standard objects including accounts, contacts, and custom objects.
Those triggers are activated by default when created. Where is Apex Trigger Code Written in Salesforce? If you’ve never used Apex Triggers in the past, figuring out where to place the actual triggers within the Salesforce system can be a bit confusing. Additionally, you don’t want to start by launching codes to your live system. If it is your first time
using Apex Triggers, you’ll want to run some tests before deploying anything live. There are two places where you can practice writing Apex Trigger codes in Salesforce without the changes affecting your live database: Sandbox – A vast majority of people code their triggers here. Sandboxes are developer-friendly copies of your normal org and can be
created at any time. Developer Edition – A perfect place to practice if you don’t want to use sandboxes. No matter what version you are using — your live Salesforce database, a sandbox, or the Developer Edition — you can access the “Triggers” section by navigating to: Setup >> Custom Code >> Apex Triggers Here you can view all of your existing
Apex Triggers, but cannot create new triggers. You can find the Triggers for specific object types under the Object Manager menu. You can also delete Triggers from the Salesforce user interface. For example, here is what navigating to the Apex Triggers for the Account object looks like in the Salesforce user interface: Salesforce Apex Trigger
Example Let’s look at some examples of different types of Apex Triggers, to give you an idea of how they can be used. This is a simple example, meant to provide an easily understood overview of what is possible through Salesforce triggers. Apex Trigger Example #1: HelloWorld In the Developer Console, click “File > New > Apex Trigger.” Name the
trigger “HelloWorldTrigger” and choose “Account” as the sObject. The developer console will show the default code that all Apex Triggers show before you make changes. Instead, enter the following Apex Trigger script: trigger HelloWorldTrigger on Account (before insert) { System.debug('Hello World!'); } Then you can save it. To test if the
script is working, create a new account. You can also add the account manually through the debug system. When complete, you should see “Hello World!” in the debug window.
Let’s take a look at some more real-world applications for Apex Triggers. Apex Trigger Example #2: Mark Accounts in Specific Industries as ‘Hot’ Your business probably prioritizes accounts and prospects in certain industries.
It makes sense. Industries that are growing or are a particularly good fit for your offer should receive more attention from your internal teams. But often, that means that someone at your organization has to keep an eye on new accounts to mark them appropriately in Salesforce. This can be done automatically using Apex triggers. In the example
below, we show how you can use Apex Triggers to mark new accounts that are from the technology or finance industries as “hot” in the system, helping your sales team to prioritize those accounts. trigger AccountRatingTrigger on Account (before insert, before update) { for(Account account : Trigger.New) { if (account.Industry != null &&
(account.Industry == 'Technology' || account.Industry == 'Finance')){ account.Rating = 'Hot'; } } } This is a great example of a simple and effective way to identify priority accounts for salespeople within your Salesforce database.
Trigger Context Variables Here is a complete list of all of the Apex Trigger context variables that can be utilized in Salesforce. Variable Usage isExecuting Returns true if the current context for the Apex code is a trigger, not a Visualforce page, a Web service, or an executeanonymous() API call. isInsert Returns true if this trigger was fired due to an
insert operation isUpdate Returns true if this trigger was fired due to an update operation isDelete Returns true if this trigger was fired due to a delete operation. isBefore Returns true if this trigger was fired before any record was saved. isAfter Returns true if this trigger was fired after all records were saved.
isUndelete If a record is recovered from the recycle bin it returns trigger true. new Returns a list of the new versions of the sObject records. This sObject list is only available in insert, update, and undelete triggers. newMap A map of IDs to the new versions of the sObject records. old Returns a list of the old versions of the sObject records. oldMap A
map of IDs to the old versions of the sObject records. size The total number of records in a trigger invocation, both old and new. Salesforce Apex Triggers — Beyond the Basics Apex Triggers can be a powerful tool for companies to automate complex processes that otherwise would have to be handled manually, making it a vital tool for data
management practices. Let’s dive a bit deeper and look at some of the more advanced considerations for Apex Triggers: Apex Trigger Best Practices Using Apex Triggers becomes a whole lot easier if you follow a few simple best practices. In following these, you can help to cut down on the learning curve and avoid mistakes that are common among
new apex trigger users. Best Practice #1: Bulkify Your Code Bulkifying Apex code ensures that the code that you are running is able to effectively handle more than a single record at once. When a collection of records initiates Apex, a single instance of that code is executed. Still, that Apex Trigger code needs to be able to handle all of the records
that were a part of that collection.
Best Practice #2: Avoid SOQL Queries or DML statements inside FOR Loops A common mistake with Apex Triggers is having queries or DML statements that are placed within a “for” loop. This causes issues because there is a governor limit that enforces a maximum number of SOQL queries. Additionally, there is another governor limit that affects
the number of DML statements — including inserts, updates, deletes, and undeletes. These statements should be outside of loops. Best Practice #3: Bulkify Helper Methods Like our previous best practices, Helper Methods need to be able to run in a bulk manner and not execute within an iteration or a “for” loop. These actions increase the risk that
you will go beyond the governor limit. This APEX best practices article explains in more depth, providing examples of how to use SOQL and DML statements correctly and incorrectly. Triggers and Callouts for Integration with Third-Party Apps Apex allows you to make callouts to integrate Apex code with third-party apps. For example, you could make
a callout to a third-party data provider to update records within Salesforce. When you make a callout from an Apex trigger in Salesforce, the callout should typically not block other actions while waiting for the external service’s response. Apex callout limits and limitations ensure that a transaction is not held open for a potentially long period of time,
in order to avoid locking the records. Triggers can also be used to build upon Salesforce's robust validation rules and create your own customer validation rules. To make a callout, call a class method that executes asynchronously. These methods are called future methods and are annotated with “@future(callout=true). Apex Triggers Can Be a Key
Tool for Data Management in Salesforce Apex Triggers make a natural complement to Insycle for any company that is looking to improve their data management operations and data management workflows. Apex triggers can help you to avoid costly data-related mistakes inside of Salesforce while streamlining and automating actions that otherwise
would have had to be performed manually.
Apex triggers help you to manage how specific types of data are handled internally, helping you to execute a broader overall data maintenance and management strategy. With Apex triggers and Insycle paired, you can effectively identify, handle, and fix common data management issues — such as merging duplicate accounts, standardizing job titles,
and formatting address and phone number fields consistently. Insycle is a complete data management platform for Salesforce. Insycle can help you to take control of your data management processes and deduplicate, cleanse, and standardize your data in bulk, and automatically at set intervals. Learn more about ways to put your Salesforce data
maintenance on autopilot and improve data quality in your CRM. After completing this unit, you'll be able to: Write a trigger for a Salesforce object. Use trigger context variables. Call a class method from a trigger. Use the sObject addError() method in a trigger to restrict save operations. Apex triggers are useful, fun, and groovy. While this module
helps you get started with them, it also references other Salesforce features to show you the power of Apex triggers.
To get the most out of this module, we highly recommend you check out these modules first: Apex triggers enable you to perform custom actions before or after events to records in Salesforce, such as insertions, updates, or deletions. Just like database systems support triggers, Apex provides trigger support for managing records. Typically, you use
triggers to perform operations based on specific conditions, to modify related records or restrict certain operations from happening. You can use triggers to do anything you can do in Apex, including executing SOQL and DML or calling custom Apex methods. Use triggers to perform tasks that can’t be done by using the point-and-click tools in the
Salesforce user interface. For example, if validating a field value or updating a field on a record, use validation rules and flows. Use Apex triggers if performance and scale is important, if your logic is too complex for the point-and-click tools, or if you're executing CPU-intensive operations. Triggers can be defined for top-level standard objects, such as
Account or Contact, custom objects, and some standard child objects. Triggers are active by default when created. Salesforce automatically fires active triggers when the specified database events occur. The syntax of a trigger definition is different from a class definition’s syntax. A trigger definition starts with the trigger keyword. It is then followed
by the name of the trigger, the Salesforce object that the trigger is associated with, and the conditions under which it fires. A trigger has the following syntax: trigger TriggerName on ObjectName (trigger_events) { code_block } To execute a trigger before or after insert, update, delete, and undelete operations, specify multiple trigger events in a
comma-separated list. The events you can specify are: before insert before update before delete after insert after update after delete after undelete This simple trigger fires before you insert an account and writes a message to the debug log. In the Developer Console, click File | New | Apex Trigger. Enter HelloWorldTrigger for the trigger name, and
then select Account for the sObject. Click Submit. Replace the default code with the following.trigger HelloWorldTrigger on Account (before insert) { System.debug('Hello World!'); } To save, press Ctrl+S. To test the trigger, create an account. Click Debug | Open Execute Anonymous Window. In the new window, add the following and then click
Execute.Account a = new Account(Name='Test Trigger'); insert a; In the debug log, find the Hello World! statement. The log also shows that the trigger has been executed. There are two types of triggers. Before triggers are used to update or validate record values before they’re saved to the database. After triggers are used to access field values
that are set by the system (such as a record's Id or LastModifiedDate field), and to affect changes in other records. The records that fire the after trigger are read-only. To access the records that caused the trigger to fire, use context variables. For example, Trigger.new contains all the records that were inserted in insert or update triggers.
Trigger.old provides the old version of sObjects before they were updated in update triggers, or a list of deleted sObjects in delete triggers. Triggers can fire when one record is inserted, or when many records are inserted in bulk via the API or Apex. Therefore, context variables, such as Trigger.new, can contain only one record or multiple records.
You can iterate over Trigger.new to get each individual sObject. This example is a modified version of the HelloWorldTrigger example trigger. It iterates over each account in a for loop and updates the Description field for each. trigger HelloWorldTrigger on Account (before insert) { for(Account a : Trigger.new) { a.Description = 'New description'; }
} Some other context variables return a Boolean value to indicate whether the trigger was fired due to an update or some other event. These variables are useful when a trigger combines multiple events. For example: trigger ContextExampleTrigger on Account (before insert, after insert, after delete) { if (Trigger.isInsert) { if (Trigger.isBefore) { //
Process before insert } else if (Trigger.isAfter) { // Process after insert } } else if (Trigger.isDelete) { // Process after delete } } The following table is a comprehensive list of all context variables available for triggers. Variable Usage isExecuting Returns true if the current context for the Apex code is a trigger, not a Visualforce page, a Web service, or
an executeanonymous() API call. isInsert Returns true if this trigger was fired due to an insert operation, from the Salesforce user interface, Apex, or the API. isUpdate Returns true if this trigger was fired due to an update operation, from the Salesforce user interface, Apex, or the API. isDelete Returns true if this trigger was fired due to a delete
operation, from the Salesforce user interface, Apex, or the API. isBefore Returns true if this trigger was fired before any record was saved. isAfter Returns true if this trigger was fired after all records were saved. isUndelete Returns true if this trigger was fired after a record is recovered from the Recycle Bin. This recovery can occur after an undelete
operation from the Salesforce user interface, Apex, or the API. new Returns a list of the new versions of the sObject records.This sObject list is only available in insert, update, and undelete triggers, and the records can only be modified in before triggers. newMap A map of IDs to the new versions of the sObject records.This map is only available in
before update, after insert, after update, and after undelete triggers. old Returns a list of the old versions of the sObject records.This sObject list is only available in update and delete triggers. oldMap A map of IDs to the old versions of the sObject records.This map is only available in update and delete triggers. operationType Returns an enum of type
System.TriggerOperation corresponding to the current operation.Possible values of the System.TriggerOperation enum are: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE, AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, and AFTER_UNDELETE. If you vary your programming logic based on different trigger types, consider using the
switch statement with different permutations of unique trigger execution enum states. size The total number of records in a trigger invocation, both old and new. You can call public utility methods from a trigger. Calling methods of other classes enables code reuse, reduces the size of your triggers, and improves maintenance of your Apex code. It also
allows you to use object-oriented programming. The following example trigger shows how to call a static method from a trigger. If the trigger was fired because of an insert event, the example calls the static sendMail() method on the EmailManager class. This utility method sends an email to the specified recipient and contains the number of contact
records inserted. In the Developer Console, click File | New | Apex Trigger. Enter ExampleTrigger for the trigger name, and then select Contact for the sObject. Click Submit. Replace the default code with the following, and then modify the email address placeholder text in sendMail()to your email address.trigger ExampleTrigger on Contact (after
insert, after delete) { if (Trigger.isInsert) { Integer recordCount = Trigger.new.size(); // Call a utility method from another class EmailManager.sendMail('Your email address', 'Trailhead Trigger Tutorial', recordCount + ' contact(s) were inserted.'); } else if (Trigger.isDelete) { // Process after delete } } To save, press Ctrl+S. To test the trigger, create
a contact. Click Debug | Open Execute Anonymous Window. In the new window, add the following and then click Execute.Contact c = new Contact(LastName='Test Contact'); insert c; In the debug log, check that the trigger was fired.
Toward the end of the log, find the debug message that was written by the utility method: DEBUG|Email sent successfully Now check that you received an email with the body text 1 contact(s) were inserted.With your new trigger in place, you get an email every time you add one or more contacts! Triggers are often used to access and manage records
related to the records in the trigger context—the records that caused this trigger to fire. This trigger adds a related opportunity for each new or updated account if no opportunity is already associated with the account. The trigger first performs a SOQL query to get all child opportunities for the accounts that the trigger fired on. Next, the trigger
iterates over the list of sObjects in Trigger.new to get each account sObject. If the account doesn’t have any related opportunity sObjects, the for loop creates one. If the trigger created any new opportunities, the final statement inserts them. Add the following trigger using the Developer Console (follow the steps of the HelloWorldTrigger example but
use AddRelatedRecordfor the trigger name).trigger AddRelatedRecord on Account(after insert, after update) { List oppList = new List(); // Get the related opportunities for the accounts in this trigger Map acctsWithOpps = new Map( [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.new]); // Add an opportunity for
each account if it doesn't already have one. // Iterate through each account.
for(Account a : Trigger.new) { System.debug('acctsWithOpps.get(a.Id).Opportunities.size()=' + acctsWithOpps.get(a.Id).Opportunities.size()); // Check if the account already has a related opportunity. if (acctsWithOpps.get(a.Id).Opportunities.size() == 0) { // If it doesn't, add a default opportunity oppList.add(new Opportunity(Name=a.Name + '
Opportunity', StageName='Prospecting', CloseDate=System.today().addMonths(1), AccountId=a.Id)); } } if (oppList.size() > 0) { insert oppList; } } To test the trigger, create an account in the Salesforce user interface and name it Apples & Oranges. In the Opportunities related list on the account’s page, find the new opportunity. The trigger added
this opportunity automatically! Using Trigger Exceptions You sometimes need to add restrictions on certain database operations, such as preventing records from being saved when certain conditions are met. To prevent saving records in a trigger, call the addError() method on the sObject in question. The addError() method throws a fatal error
inside a trigger. The error message is displayed in the user interface and is logged.
The following trigger prevents the deletion of an account if it has related opportunities. By default, deleting an account causes a cascade delete of all its related records. This trigger prevents the cascade delete of opportunities. Try this trigger for yourself! If you’ve executed the previous example, your org has an account called Apples & Oranges with
a related opportunity. This example uses that sample account. Using the Developer Console, add the following trigger.trigger AccountDeletion on Account (before delete) { // Prevent the deletion of accounts if they have related opportunities. for (Account a : [SELECT Id FROM Account WHERE Id IN (SELECT AccountId FROM Opportunity) AND Id IN
:Trigger.old]) { Trigger.oldMap.get(a.Id).addError( 'Cannot delete account with related opportunities.'); } } In the Salesforce user interface, navigate to the Apples & Oranges account’s page and click Delete. In the confirmation popup, click OK.Find the validation error with the custom error message Cannot delete account with related opportunities.
Disable the AccountDeletiontrigger. If you leave this trigger active, you can’t check your challenges. From Setup, search for Apex Triggers. On the Apex Triggers page, click Edit next to the AccountDeletion trigger. Deselect Is Active. Click Save. Apex allows you to make calls to and integrate your Apex code with external Web services. Apex calls to
external Web services are referred to as callouts. For example, you can make a callout to a stock quote service to get the latest quotes.
When making a callout from a trigger, the callout must be done asynchronously so that the trigger process doesn’t block you from working while waiting for the external service's response. The asynchronous callout is made in a background process, and the response is received when the external service returns it. To make a callout from a trigger,
call a class method that executes asynchronously. Such a method is called a future method and is annotated with @future(callout=true). This example class contains the future method that makes the callout. public class CalloutClass { @future(callout=true) public static void makeCallout() { HttpRequest request = new HttpRequest(); // Set the
endpoint URL. String endpoint = ' ; request.setEndPoint(endpoint); // Set the HTTP verb to GET. request.setMethod('GET'); // Send the HTTP request and get the response. HttpResponse response = new HTTP().send(request); } } This example shows the trigger that calls the method in the class to make a callout asynchronously. trigger
CalloutTrigger on Account (before insert, before update) { CalloutClass.makeCallout(); } This section offers only an overview of callouts and is not intended to cover callouts in detail. For more information, see Invoking Callouts Using Apex in the Apex Developer Guide.