Bypass Apex Trigger in Flow Transaction

Each flow interview runs in the context of a transaction. A transaction is a collection of operations that are performed as a single unit. In addition to a flow interview, a transaction can execute Apex triggers and escalation rules.

💼 Use Case

You’ve developed a flow that executes whenever something changes in the Account object and you’re updating its associated contact object. There is an Apex Trigger written on the contact object, which you do not want to execute when updating records from the flow.

✅ Solution

Create an Apex class

/***********************************************************************************
Class Name : TriggerSwitchCls
Description : This class can be used to stop the trigger execution for a transaction.
Created By : SFDC Lessons
Created Date : 09/06/2022
Modification Logs:
------------------------------------------------------------------------------------
Developer Date Descriptions
-------------------------------------------------------------------------------------
Arun Kumar 09/06/2022 Initial version
*************************************************************************************/
public class TriggerSwitchCls {
public static Boolean accountTriggerRunFlag = true;
public static Boolean opportunityTriggerRunFlag = true;
public static Boolean contactTriggerRunFlag = true;
public static Boolean opportunityLineItemTriggerRunFlag = true;
public static Boolean userTriggerRunFlag = true;
public static Boolean leadTriggerRunFlag = true;
//Account Trigger Switch Logic
public static Boolean canAccountTriggerExecute(){
return accountTriggerRunFlag;
}
public static void stopAccccountTrigger(){
accountTriggerRunFlag = false;
}
public static void allowAccountTrigger(){
accountTriggerRunFlag = true;
}
//Opportunity Trigger Switch Logic
public static Boolean canOpportunityTriggerExecute(){
return opportunityTriggerRunFlag;
}
public static void stopOpportunityTrigger(){
opportunityTriggerRunFlag = false;
}
public static void allowOpportunityTrigger(){
opportunityTriggerRunFlag = true;
}
//Contact Trigger Switch Logic
public static Boolean canContactTriggerExecute(){
return contactTriggerRunFlag;
}
public static void stopContactTrigger(){
contactTriggerRunFlag = false;
}
public static void allowContactTrigger(){
contactTriggerRunFlag = true;
}
//OpportunityLineItem Trigger Switch Logic
public static Boolean canOLITriggerExecute(){
return opportunityLineItemTriggerRunFlag;
}
public static void stopOLITrigger(){
opportunityLineItemTriggerRunFlag = false;
}
public static void allowOLITrigger(){
opportunityLineItemTriggerRunFlag = true;
}
//User Trigger Switch Logic
public static Boolean canUserTriggerExecute(){
return userTriggerRunFlag;
}
public static void stopUserTrigger(){
userTriggerRunFlag = false;
}
public static void allowUserTrigger(){
userTriggerRunFlag = true;
}
//Lead Trigger Switch Logic
public static Boolean canLeadTriggerExecute(){
return leadTriggerRunFlag;
}
public static void stopLeadTrigger(){
leadTriggerRunFlag = false;
}
public static void allowLeadTrigger(){
leadTriggerRunFlag = true;
}
//** Duplicate the above methods for other objects */
}

The above class method can be used to stop the trigger execution.

Advertisements

Contact Trigger

In line 11, you can see that I used the TriggerSwitchCls method to determine whether the trigger code should be executed or not. This method returns TRUE or FALSE depending on the static boolean variable set in the method.

/**
* @description ContactTrigger.
* @Created By: Arun Kumar
* @Created Date : 26-06-2022
* @Last Modified Date : 26-06-2022
*/
trigger ContactTrigger on Contact (before insert,before update, before delete, after insert, after update, after delete,after undelete) {
// This "TriggerSwitchCls.canContactTriggerExecute()" will return TRUE or FALSE. By default it will return TRUE and
//if we bypass this in flow then it will return FALSE and trigger will be bypassed.
if(TriggerSwitchCls.canContactTriggerExecute()){
System.debug('Inside Contact Trigger');
TriggerHandler handler = new ContactTriggerHandler(Trigger.isExecuting, Trigger.size);
switch on Trigger.operationType {
when BEFORE_INSERT {
//call before insert handler method
handler.beforeInsert(Trigger.new);
}
when BEFORE_UPDATE {
//call before update handler method
handler.beforeUpdate(Trigger.new, Trigger.old, Trigger.newMap, Trigger.oldMap);
}
when BEFORE_DELETE{
//call before delete handler method
handler.beforeDelete(Trigger.old, Trigger.oldMap);
}
when AFTER_INSERT{
//call after insert handler method
handler.afterInsert(Trigger.new,Trigger.newMap);
}
when AFTER_UPDATE{
//call after update handler method
handler.afterUpdate(Trigger.new, Trigger.old, Trigger.newMap, Trigger.oldMap);
}
when AFTER_DELETE{
//call after delete handler method
handler.afterDelete(trigger.old, Trigger.oldMap);
}
when AFTER_UNDELETE{
//call after undelete handler method
handler.afterUndelete(trigger.new, Trigger.newMap);
}
}
}
}
Advertisements

Now create two different classes to stop and allow the trigger from flow transaction. Each class will have an invocable method that calls the TriggerSwitchCls method to set the static boolean variable to TRUE or FALSE.

StopTriggerHandler.cls

/***********************************************************************************
Class Name : StopTriggerHandler
Description : This class can be used in the PB, flow to do the actions defined in the methods.
Created By : SFDC Lessons
Created Date : 09/06/2022
Modification Logs:
------------------------------------------------------------------------------------
Developer Date Descriptions
-------------------------------------------------------------------------------------
Arun Kumar 09/06/2022 Initial version
*************************************************************************************/
public class StopTriggerHandler {
/**
* @description stopTrigger method can be called from PB/FLOWs to stop the object trigger for a transaction.
* @param triggerNameToStop
*/
@InvocableMethod(label='Stop sObject Trigger' description='Stop the sObject trigger for this transaction')
Public static void stopTrigger(List<List<String>> triggerNameToStop){
for(String varTrggrName: triggerNameToStop[0]){
//switch statement checking trigger name and stoping the triggers
switch on varTrggrName {
when 'Account' {
TriggerSwitchCls.stopAccccountTrigger();
}
when 'Opportunity' {
TriggerSwitchCls.stopOpportunityTrigger();
}
when 'Contact' {
TriggerSwitchCls.stopContactTrigger();
}
when 'OpportunityLineItem' {
TriggerSwitchCls.stopOLITrigger();
}
when 'User' {
TriggerSwitchCls.stopUserTrigger();
}
when 'Lead' {
TriggerSwitchCls.stopLeadTrigger();
}
}//switch statement block ends here
}//for loop ends here
system.debug('Can Opportnity Trigger Execute ? : ' + TriggerSwitchCls.canAccountTriggerExecute());
}//mehod ends here
}

AllowTriggerHandler.cls

/***********************************************************************************
Class Name : AllowTriggerHandler
Description : This class can be used in the PB, flow to do the actions defined in the methods.
Created By : SFDC Lessons
Created Date : 09/06/2022
Modification Logs:
------------------------------------------------------------------------------------
Developer Date Descriptions
-------------------------------------------------------------------------------------
Arun Kumar 09/06/2022 Initial version
*************************************************************************************/
public class AllowTriggerHandler {
/**
* @description stopTrigger method can be called from PB/FLOWs to allow the sObject trigger for a transaction.
* @param triggerNameToAllow
*/
@InvocableMethod(label='Allow sObject Trigger to execute' description='Allow the sObject trigger for this transaction')
Public static void allowTrigger(List<List<String>> triggerNameToAllow){
for(String varTrggrName: triggerNameToAllow[0]){
//switch statement checking trigger name and stoping the triggers
switch on varTrggrName {
when 'Account' {
TriggerSwitchCls.allowAccountTrigger();
}
when 'Opportunity' {
TriggerSwitchCls.allowOpportunityTrigger();
}
when 'Contact' {
TriggerSwitchCls.allowContactTrigger();
}
when 'OpportunityLineItem' {
TriggerSwitchCls.allowOLITrigger();
}
when 'User' {
TriggerSwitchCls.allowUserTrigger();
}
when 'Lead' {
TriggerSwitchCls.allowLeadTrigger();
}
}//switch statement block ends here
}//for loop ends here
}//mehod ends here
}

To stop the object trigger execution, call the invocable method stopTrigger(objectName) in the flow. You simply need to pass the name of the object for which you want to bypass the trigger.

Advertisements

🚶Steps to Implement the Solution in Flow

Click on the New Resources button in the flow builder and create a collection variable to store the object name.

Enter the API Name, description and select the checkbox to allow multiple values (collection).

The next step is to add values to this collection.

Select the assignment element and add the string ‘Contact‘ to this variable.

Add an Action element before the Update Record element.

In the Action lookup field selects the “Stop sObject Trigger” invocable action.

Enter the label and API name, then enable the toggle button and select the collection variable in the triggerNameToStop field.

After Update Records element, add Apex action to allow the Contact trigger to execute.

Select ‘Allow sObject Trigger to execute‘ apex action.

Enter the label and API name, then enable the toggle button and select the collection variable in the triggerNameToStop field.

Finally, the flow will look like the screenshot below.

When flow updates a contact record, the contact trigger no longer executes.

Advertisements

Summary

You may have encountered the CPU time limit exceeded if you doing a bulk record upload. This is usually due to multiple automation tools (Flow, PB, Trigger) running and not being developed properly. If you look at the debug log, you might notice that the DML you’re doing in the flow again calls the apex trigger/PB. We can bypass and allow apex trigger in flow transactions with the help of the apex invocable method a boolean static variable. However, automation tools should be written in such a way that they do not call each other back and forth, and proper conditions should be added to trigger code to execute the code in the exact use case.

Join 153 other subscribers
Advertisements
Advertisements
  • The Magic of Lightning Web Components (LWC) Wire Adapter
    Salesforce LWC Wire Adapter streamlines data flow, enhances modularity, and ensures code quality through automatic updates and loose coupling principles.
  • Maximize User Interaction: GraphQL, LWC, and Toasts
    This blog proposes a solution for improving user experience in Salesforce development. It addresses the problem of unclear messages when users don’t have access to specific records. The solution includes using GraphQL for efficient data fetching, Lightning Web Components for a responsive interface, the onrowaction event in lightning-datatable for smoother interactions, and custom toast messages for clearer communication. These strategies aim to create efficient and user-friendly applications.

Arun Kumar

Arun Kumar is a Certified Salesforce developer and Salesforce Champions (Platform Champions), a Computer Science graduate, working on the Salesforce platform and providing customer solutions using force.com as a Salesforce consultant/developer. He is the founder of SFDCLessons. :)

Leave a Reply