What Is Trigger?
Apex can be invoked through the use of triggers. A trigger is Apex code that executes before or after the following types of operations:
Apex can be invoked through the use of triggers. A trigger is Apex code that executes before or after the following types of operations:
- insert
- update
- delete
- merge
- upsert
- undelete
The after undelete trigger event only works with recovered records—that is, records that were deleted and then recovered from the Recycle Binthrough the undelete DML statement. These are also called undeleted records.
The after undelete trigger events only run on top-level objects. For example, if you delete an Account, an Opportunity may also be deleted. When you recover the Account from the Recycle Bin, the Opportunity is also recovered. If there is an after undelete trigger event associated with both the Account and the Opportunity, only the Account after undelete trigger event executes.
Merge events do not fire their own trigger events. Instead, they fire delete and update events as follows:
- Deletion of losing records
- A single merge operation fires a single delete event for all records that are deleted in the merge. To determine which records were deleted as a result of a merge operation use the MasterRecordId field in Trigger.old. When a record is deleted after losing a merge operation, itsMasterRecordId field is set to the ID of the winning record. The MasterRecordId field is only set in after delete trigger events. If your application requires special handling for deleted records that occur as a result of a merge, you need to use the after delete trigger event.
- Update of the winning record
- A single merge operation fires a single update event for the winning record only. Any child records that are reparented as a result of the merge operation do not fire triggers.
For example, if two contacts are merged, only the delete and update contact triggers fire. No triggers for records related to the contacts, such as accounts or opportunities, fire.
The following is the order of events when a merge occurs:
- The before delete trigger fires.
- The system deletes the necessary records due to the merge, assigns new parent records to the child records, and sets the MasterRecordId field on the deleted records.
- The after delete trigger fires.
Trigger Context Variable:
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 (that is, after an undelete operation from the Salesforce user interface, Apex, or theAPI.) |
new | Returns a list of the new versions of the sObject records.
Note that this sObject list is only available in insert and update triggers, and the records can only be modified in before triggers.
|
newMap | A map of IDs to the new versions of the sObject records.
Note that this map is only available in before update, after insert, and after update triggers.
|
old | Returns a list of the old versions of the sObject records.
Note that this sObject list is only available in update and delete triggers.
|
oldMap | A map of IDs to the old versions of the sObject records.
Note that this map is only available in update and delete triggers.
|
size | The total number of records in a trigger invocation, both old and new. |
Example:
Trigger t on Account (after insert) {
for (Account a : Trigger.new) {
// Iterate over each sObject
}
// This single query finds every contact that is associated with any of the
// triggering accounts. Note that although Trigger.new is a collection of
// records, when used as a bind variable in a SOQL query, Apex automatically
// transforms the list of records into a list of corresponding Ids.
Contact[] cons = [SELECT LastName FROM Contact
WHERE AccountId IN :Trigger.new];
}
Be aware of the following considerations for trigger context variables:
- trigger.new and trigger.old cannot be used in Apex DML operations.
- You can use an object to change its own field values using trigger.new, but only in before triggers. In all after triggers, trigger.new is not saved, so a runtime exception is thrown.
- trigger.old is always read-only.
How to avoid Recursive trigger:
Example:
Suppose there is a scenario where in one trigger perform update operation, which results in invocation of second trigger and the update operation in second trigger acts as triggering criteria for trigger one.
Suppose there is a scenario where in one trigger perform update operation, which results in invocation of second trigger and the update operation in second trigger acts as triggering criteria for trigger one.
Solution:
Class:
public class Utility
{
public static boolean isFutureUpdate;
}
Trigger:
trigger updateSomething on Account (after insert, after update)
{
/* This trigger performs its logic when the call is not from @future */
if(Utility.isFutureUpdate != true)
{
Set<Id> idsToProcess = new Se<Id>();
for(Account acct : trigger.new)
{
if(acct.NumberOfEmployees > 500)
{
idsToProcess.add(acct.Id);
}
}
/* Sending Ids to @future method for processing */
futureMethods.processLargeAccounts(idsToProcess);
}
}
Class:
public class FutureMethods
{
@future
public static void processLargeAccounts(Set<Id> acctIDs)
{
List<Account> acctsToUpdate = new List<Account>();
/* isFutureUpdate is set to true to avoid recursion */
Utility.isFutureUpdate = true;
update acctsToUpdate;
}
}
{
public static boolean isFutureUpdate;
}
Trigger:
trigger updateSomething on Account (after insert, after update)
{
/* This trigger performs its logic when the call is not from @future */
if(Utility.isFutureUpdate != true)
{
Set<Id> idsToProcess = new Se<Id>();
for(Account acct : trigger.new)
{
if(acct.NumberOfEmployees > 500)
{
idsToProcess.add(acct.Id);
}
}
/* Sending Ids to @future method for processing */
futureMethods.processLargeAccounts(idsToProcess);
}
}
Class:
public class FutureMethods
{
@future
public static void processLargeAccounts(Set<Id> acctIDs)
{
List<Account> acctsToUpdate = new List<Account>();
/* isFutureUpdate is set to true to avoid recursion */
Utility.isFutureUpdate = true;
update acctsToUpdate;
}
}