Detailed Guide to Triggers in Salesforce

Detailed Guide to Triggers in Salesforce

On June 21, 2024, Posted by , In Salesforce Apex Tutorial, With Comments Off on Detailed Guide to Triggers in Salesforce
Triggers in Apex
Triggers in Apex

Table of Contents

Triggers in Apex are like automated reactions that happen in response to changes in your Salesforce data. They allow you to add custom logic to your Salesforce objects, such as Leads, Contacts, or Opportunities, so that specific actions occur automatically when certain conditions are met. Think of them as “if this happens, do that” rules for your data.

What are Triggers in Salesforce?

Triggers in Salesforce are Apex scripts that execute before or after specific database events on Salesforce records. They are used to perform operations such as insertions, updates, deletions, and undeletions of records. Triggers are a powerful tool for implementing complex business logic and ensuring data integrity within your Salesforce organization.

Read more: Trigger framework in Salesforce

Types of Triggers

Salesforce supports two types of triggers:

  1. Before Triggers: Execute before a record is saved to the database.
  2. After Triggers: Execute after a record has been saved to the database.

Looking to ace Salesforce job interviews? These Utimate Salesforce Interview Questions will guide you to success!

Before Triggers

Before triggers are used to perform tasks or validations before a record is committed to the database. They are commonly used to ensure data consistency and to enforce business rules.

Read more: Triggers in Salesforce and Top interview Questions

Example of a Before Trigger

The following example demonstrates a before insert trigger that ensures the AnnualRevenue field is set to a default value if it is not provided:

trigger AccountBeforeInsert on Account (before insert) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000; // Default value
        }
    }
}

In this example, the trigger checks if the AnnualRevenue field is null before inserting a new account record. If it is null, it assigns a default value of 1,000,000.

After Triggers

After triggers are used to access field values that are set by the system and to make changes in other records. They are executed after the data is saved to the database.

Redmore: SOQL in Salesforce Apex

Example of an After Trigger

The following example demonstrates an after insert trigger that creates a related Contact record for each newly inserted Account record:

trigger AccountAfterInsert on Account (after insert) {
    List<Contact> contacts = new List<Contact>();
    for (Account acc : Trigger.new) {
        Contact con = new Contact(
            FirstName = 'Default',
            LastName = 'Contact',
            AccountId = acc.Id
        );
        contacts.add(con);
    }
    insert contacts;
}

Looking for a comprehensive Salesforce training course? Enroll today to advance your career!

Executing the Trigger

Following are the events on which we can execute the trigger in Salesforce:

Insert

An insert trigger is executed before or after a new record is inserted into the database.

Readmore: Arrays in Salesforce Apex

Example of an Insert Trigger

trigger AccountBeforeInsert on Account (before insert) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000; // Default value
        }
    }
}

Update

An update trigger is executed before or after an existing record is updated in the database.

Example of an Update Trigger

trigger AccountBeforeUpdate on Account (before update) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue < 500000) {
            acc.addError('Annual Revenue cannot be less than 500,000.');
        }
    }
}

Read more: SOSL Query in Salesforce

Delete

A delete trigger is executed before or after a record is deleted from the database.

Example of a Delete Trigger

trigger AccountBeforeDelete on Account (before delete) {
    for (Account acc : Trigger.old) {
        if (acc.Name == 'Protected Account') {
            acc.addError('This account cannot be deleted.');
        }
    }
}

Readmore: Custom Page Layouts in Salesforce

Merge

A merge trigger is executed before or after records are merged. Merge events are only available for accounts, contacts, and leads.

Example of a Merge Trigger

trigger AccountAfterMerge on Account (after merge) {
    for (Account masterRecord : Trigger.new) {
        // Handle logic after records are merged
        System.debug('Master record: ' + masterRecord.Id);
    }
}

Readmore: Permission Sets in Salesforce

Upsert

An upsert trigger is executed before or after a record is inserted or updated. Upsert triggers are particularly useful for handling both new and existing records.

Example of an Upsert Trigger

trigger AccountBeforeUpsert on Account (before insert, before update) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000; // Default value for both insert and update
        }
    }
}

Read more: String methods in Salesforce apex

Undelete

An undelete trigger is executed after a record is recovered from the Recycle Bin.

Example of an Undelete Trigger

trigger AccountAfterUndelete on Account (after undelete) {
    for (Account acc : Trigger.new) {
        // Perform actions after a record is undeleted
        System.debug('Undeleted account: ' + acc.Id);
    }
}

Bulky Triggers

Bulky triggers are designed to handle operations efficiently when a large number of records are processed at once. It’s important to write triggers that can handle bulk operations to avoid hitting governor limits.

Example of a Bulky Trigger

trigger AccountBulkyTrigger on Account (before insert, before update) {
    // List to collect all accounts for processing
    List<Account> accountsToProcess = new List<Account>();
    
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000; // Default value
        }
        accountsToProcess.add(acc);
    }
    
    // Perform bulk processing, e.g., making an external API call, or updating related records
    if (accountsToProcess.size() > 0) {
        // Example: Update related records in bulk
        List<Contact> contactsToUpdate = new List<Contact>();
        for (Account acc : accountsToProcess) {
            contactsToUpdate.add(new Contact(AccountId = acc.Id, Description = 'Updated by Trigger'));
        }
        update contactsToUpdate;
    }
}

Checkout: DML statements in Salesforce

Trigger Syntax

The basic syntax for writing a trigger in Salesforce is as follows:

trigger TriggerName on ObjectName (trigger_events) {
    // Trigger logic
}
  • TriggerName: The name of the trigger.
  • ObjectName: The name of the Salesforce object the trigger is associated with.
  • trigger_events: The database events that cause the trigger to execute (e.g., before insert, after update).

Example and Explanation

trigger AccountTrigger on Account (before insert, after update) {
    if (Trigger.isBefore && Trigger.isInsert) {
        // Logic for before insert
        for (Account acc : Trigger.new) {
            acc.AnnualRevenue = 1000000; // Set default annual revenue
        }
    }
    
    if (Trigger.isAfter && Trigger.isUpdate) {
        // Logic for after update
        List<Contact> contactsToUpdate = new List<Contact>();
        for (Account acc : Trigger.new) {
            contactsToUpdate.add(new Contact(
                AccountId = acc.Id,
                Description = 'Account updated'
            ));
        }
        update contactsToUpdate;
    }
}

In this example:

  • The trigger is named AccountTrigger .
  • It runs on the Account object.
  • It executes for before insert and after update events.
  • Inside the trigger, different logic is implemented based on whether it is a before insert or after update event.

Read more: Salesforce apex programming examples

How to Write Apex Triggers?

Writing Apex triggers involves the following steps:

  1. Define the trigger: Specify the object and events the trigger should run on.
  2. Implement logic: Write the logic to be executed when the trigger is fired.
  3. Handle bulk operations: Ensure the trigger can handle multiple records efficiently to avoid hitting governor limits.
  4. Use context variables: Utilize context variables to manage the flow of trigger execution.

Example

trigger OpportunityTrigger on Opportunity (before insert, after update) {
    if (Trigger.isBefore && Trigger.isInsert) {
        for (Opportunity opp : Trigger.new) {
            if (opp.StageName == null) {
                opp.StageName = 'Prospecting'; // Set default stage
            }
        }
    }
    
    if (Trigger.isAfter && Trigger.isUpdate) {
        for (Opportunity opp : Trigger.new) {
            if (opp.Amount > 100000) {
                System.debug('High-value opportunity: ' + opp.Id);
            }
        }
    }
}

Checkout: Data types in Salesforce Apex

What are Context Variables in Triggers?

Context variables provide information about the trigger context, such as whether the trigger is executing before or after the record is saved, whether it is handling an insert, update, delete, or undelete operation, and more.

Common Context Variables

  • Trigger.isInsert: Returns true if the trigger is fired due to an insert operation.
  • Trigger.isUpdate: Returns true if the trigger is fired due to an update operation.
  • Trigger.isDelete: Returns true if the trigger is fired due to a delete operation.
  • Trigger.isBefore: Returns true if the trigger is fired before the record is saved.
  • Trigger.isAfter: Returns true if the trigger is fired after the record is saved.
  • Trigger.new: Returns a list of the new versions of the sObject records.
  • Trigger.old: Returns a list of the old versions of the sObject records.
  • Trigger.newMap: A map of IDs to the new versions of the sObject records.
  • Trigger.oldMap: A map of IDs to the old versions of the sObject records.
  • Trigger.size: The total number of records in a trigger invocation.

Example Using Context Variables

trigger LeadTrigger on Lead (before insert, before update) {
    if (Trigger.isBefore) {
        for (Lead lead : Trigger.new) {
            if (lead.Status == 'New') {
                lead.Status = 'Open - Not Contacted';
            }
        }
    }
}

In this example:

  • Trigger.isBefore: Checks if the trigger is executing before the record is saved.
  • Trigger.new: Accesses the list of new versions of the Lead records being inserted or updated.

Checkout: Variables in Salesforce Apex

Handling Different Trigger Events

Let’s go through each trigger event with detailed examples and explanations.

Trigger EventDescriptionExample Use Case
InsertExecutes before or after a new record is insertedSetting default values for new records
UpdateExecutes before or after an existing record is updatedValidating field values during updates
DeleteExecutes before or after a record is deletedPreventing deletion of certain records
MergeExecutes before or after records are mergedHandling logic after merging records
UpsertExecutes before or after a record is inserted or updatedManaging both new and existing records
UndeleteExecutes after a record is recovered from the Recycle BinRe-establishing relationships after record recovery

Readmore: Permission Sets in Salesforce

Trigger Context Variables

Trigger context variables in Salesforce provide information about the state and behavior of the trigger. They help developers understand the context in which the trigger is executed, such as whether it is being executed before or after a specific event, and provide access to the records involved in the operation.

Context Variables Table

Context VariableDescription
Trigger.isInsertReturns true if the trigger is fired due to an insert operation
Trigger.isUpdateReturns true if the trigger is fired due to an update operation
Trigger.isDeleteReturns true if the trigger is fired due to a delete operation
Trigger.isBeforeReturns true if the trigger is fired before the record is saved
Trigger.isAfterReturns true if the trigger is fired after the record is saved
Trigger.newReturns a list of the new versions of the sObject records
Trigger.oldReturns a list of the old versions of the sObject records
Trigger.newMapA map of IDs to the new versions of the sObject records
Trigger.oldMapA map of IDs to the old versions of the sObject records
Trigger.sizeThe total number of records in a trigger invocation

Read more: Loops in Salesforce Apex

Using Trigger Exceptions

Trigger exceptions are used to handle errors and prevent records from being saved if certain conditions are not met.

Example of Trigger Exception Handling

trigger OpportunityBeforeUpdate on Opportunity (before update) {
    for (Opportunity opp : Trigger.new) {
        if (opp.StageName == 'Closed Won' && opp.Amount < 10000) {
            opp.addError('Opportunities with stage "Closed Won" must have an amount of at least 10,000.');
        }
    }
}

In this example, an error is thrown if an opportunity with the stage “Closed Won” has an amount less than 10,000.

Trigger Scenarios in Salesforce

Scenario 1: Creating a Default Contact for New Accounts

trigger AccountAfterInsert on Account (after insert) {
    List<Contact> contacts = new List<Contact>();
    for (Account acc : Trigger.new) {
        contacts.add(new Contact(
            FirstName = 'Default',
            LastName = 'Contact',
            AccountId = acc.Id
        ));
    }
    insert contacts;
}

Scenario 2: Preventing Deletion of Important Accounts

trigger AccountBeforeDelete on Account (before delete) {
    for (Account acc : Trigger.old) {
        if (acc.Name == 'Protected Account') {
            acc.addError('This account cannot be deleted.');
        }
    }
}

Scenario 3: Updating Related Contacts When Account is Updated

trigger AccountAfterUpdate on Account (after update) {
    Map<Id, Account> updatedAccounts = Trigger.newMap;
    List<Contact> contactsToUpdate = new List<Contact>();

    for (Contact con : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :updatedAccounts.keySet()]) {
        con.Description = 'Account updated';
        contactsToUpdate.add(con);
    }

    if (!contactsToUpdate.isEmpty()) {
        update contactsToUpdate;
    }
}

Recursive Trigger and How to Avoid It

A recursive trigger occurs when a trigger calls itself repeatedly, leading to an infinite loop and potentially hitting governor limits. To avoid recursive triggers, you can use a static variable to ensure the trigger logic only runs once per transaction.

Watch our FREE Salesforce online course video, it’s a full length free tutorial for beginners.

Example to Avoid Recursive Trigger

public class TriggerHelper {
    public static Boolean isTriggerExecuted = false;
}

trigger AccountAfterInsert on Account (after insert) {
    if (TriggerHelper.isTriggerExecuted == false) {
        TriggerHelper.isTriggerExecuted = true;
        // Trigger logic here
    }
}

What is a Bulkifying Trigger?

A bulkifying trigger is designed to handle multiple records efficiently in a single transaction, ensuring that it can process large volumes of data without hitting governor limits. This is crucial in Salesforce where governor limits enforce strict resource usage constraints.

Example of a Bulkifying Trigger

trigger AccountBulkTrigger on Account (before insert, before update) {
    List<Contact> contactsToUpdate = new List<Contact>();

    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000; // Set default annual revenue
        }
        contactsToUpdate.add(new Contact(
            AccountId = acc.Id,
            Description = 'Updated by Bulk Trigger'
        ));
    }

    if (!contactsToUpdate.isEmpty()) {
        update contactsToUpdate;
    }
}

Best Practices for Writing Triggers in Salesforce

1. One Trigger per Object

Description: It’s a good practice to have only one trigger per object to avoid conflicts and manage the logic more efficiently.

Implementation: Use a handler class to separate business logic from the trigger framework.

trigger AccountTrigger on Account (before insert, before update) {
    AccountTriggerHandler.handleTrigger(Trigger.new, Trigger.oldMap);
}

Readmore: Role in Salesforce

2. Avoid Hardcoding

Description: Avoid hardcoding IDs, names, or other values that may change.

Implementation: Use custom settings, custom metadata types, or labels to store such values.

String customSettingValue = CustomSetting__c.getInstance().Value__c;

3. Bulkify Your Code

Description: Ensure your trigger can handle bulk operations efficiently to avoid hitting governor limits.

Implementation: Always operate on collections of records.

trigger AccountBulkTrigger on Account (before insert, before update) {
    List<Contact> contactsToUpdate = new List<Contact>();
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000;
        }
        contactsToUpdate.add(new Contact(AccountId = acc.Id, Description = 'Updated by Bulk Trigger'));
    }
    if (!contactsToUpdate.isEmpty()) {
        update contactsToUpdate;
    }
}

4. Use Context-Specific Handler Methods

Description: Use specific methods in a handler class for different trigger contexts to keep the code organized.

Implementation:

trigger AccountBulkTrigger on Account (before insert, before update) {
    List<Contact> contactsToUpdate = new List<Contact>();
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000;
        }
        contactsToUpdate.add(new Contact(AccountId = acc.Id, Description = 'Updated by Bulk Trigger'));
    }
    if (!contactsToUpdate.isEmpty()) {
        update contactsToUpdate;
    }
}

Collection is one of the important concept, checkout: Collections in Salesforce Apex

5. Avoid SOQL Queries and DML Statements Inside Loops

Description: Avoid placing SOQL queries or DML statements inside loops to prevent hitting governor limits.

Implementation:

trigger AccountTrigger on Account (before insert, before update) {
    Set<Id> accountIds = new Set<Id>();
    for (Account acc : Trigger.new) {
        accountIds.add(acc.Id);
    }

    List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds];
    for (Contact con : contacts) {
        con.Description = 'Updated by Trigger';
    }

    if (!contacts.isEmpty()) {
        update contacts;
    }
}

6. Handle Recursion

Description: Prevent recursive trigger execution by using static variables.

Implementation:

public class TriggerHelper {
    public static Boolean isTriggerExecuted = false;
}

trigger AccountTrigger on Account (before insert) {
    if (TriggerHelper.isTriggerExecuted == false) {
        TriggerHelper.isTriggerExecuted = true;
        // Trigger logic here
    }
}

7. Test Thoroughly

Description: Write comprehensive test classes to cover all possible scenarios and ensure your triggers are working as expected.

Implementation:

@isTest
public class AccountTriggerTest {
    @isTest
    static void testBeforeInsert() {
        Account acc = new Account(Name = 'Test Account');
        insert acc;

        Account insertedAccount = [SELECT AnnualRevenue FROM Account WHERE Id = :acc.Id];
        System.assertEquals(1000000, insertedAccount.AnnualRevenue);
    }
}

8. Use Trigger Context Variables

Description: Use context variables to make your triggers context-aware and control the logic flow based on the trigger event.

Implementation:

trigger ContactTrigger on Contact (before insert, before update) {
    if (Trigger.isBefore) {
        for (Contact con : Trigger.new) {
            if (con.LastName == null) {
                con.LastName = 'Default';
            }
        }
    }
}

9. Manage Governor Limits

Description: Be mindful of Salesforce governor limits and design your triggers to stay within these limits.

Implementation: Combine SOQL queries and DML operations outside of loops and use collections to handle bulk operations.

trigger LeadTrigger on Lead (before insert, before update) {
    List<Lead> leadsToUpdate = new List<Lead>();
    for (Lead lead : Trigger.new) {
        if (lead.Status == 'New') {
            lead.Status = 'Open - Not Contacted';
            leadsToUpdate.add(lead);
        }
    }

    if (!leadsToUpdate.isEmpty()) {
        update leadsToUpdate;
    }
}

10. Use Frameworks and Design Patterns

Description: Use trigger frameworks and design patterns to promote code reuse, maintainability, and separation of concerns.

Implementation: Use popular trigger frameworks like Trigger Framework by Kevin O’Hara or build a custom framework.

public abstract class TriggerHandler {
    public TriggerHandler() {
        // Framework logic here
    }

    public void execute() {
        if (Trigger.isBefore && Trigger.isInsert) {
            beforeInsert();
        } else if (Trigger.isAfter && Trigger.isUpdate) {
            afterUpdate();
        }
    }

    protected abstract void beforeInsert();
    protected abstract void afterUpdate();
}

trigger AccountTrigger on Account (before insert, after update) {
    new AccountTriggerHandler().execute();
}

public class AccountTriggerHandler extends TriggerHandler {
    protected override void beforeInsert() {
        // Custom logic for before insert
    }

    protected override void afterUpdate() {
        // Custom logic for after update
    }
}

Frequently Asked Questions( FAQs)

What are the Two Types of Triggers in Salesforce?

Salesforce supports two types of triggers: before triggers and after triggers. These triggers are used to execute custom logic at different points in the lifecycle of a Salesforce record.

Before Triggers: These triggers are executed before a record is saved to the database. They are commonly used to validate or modify the values of a record before committing it to the database. For example, you might use a before trigger to ensure that a certain field is not empty or to automatically populate a field with a default value.

Read more: record types in Salesforce.

After Triggers: These triggers are executed after a record has been saved to the database. They are used when you need to access field values that are set by the system (such as record IDs) and to perform operations that depend on the record being committed to the database. After triggers are commonly used to update related records, log changes, or integrate with external systems.

How Many Triggers Are There in Salesforce?

In Salesforce, you can create multiple triggers for a single object, but it is considered a best practice to have only one trigger per object to avoid conflicts and manage the logic more efficiently. However, each trigger can handle multiple events. Specifically, a trigger can be defined to handle one or more of the following events:

  • before insert
  • before update
  • before delete
  • after insert
  • after update
  • after delete
  • after undelete

This means you can combine these events into a single trigger to handle different types of operations. Despite the ability to define multiple triggers for an object, consolidating all logic into a single trigger per object is recommended, using context-specific handler methods to maintain clean and maintainable code.

What is an Example of a Trigger on an Account in Salesforce?

Below is an example of a trigger on the Account object in Salesforce. This trigger performs two functions: setting a default value for the AnnualRevenue field before inserting a new account, and updating the description of related contacts after the account is updated.

Read more: Validation rules in salesforce.

trigger AccountTrigger on Account (before insert, after update) {
    if (Trigger.isBefore && Trigger.isInsert) {
        for (Account acc : Trigger.new) {
            if (acc.AnnualRevenue == null) {
                acc.AnnualRevenue = 1000000; // Set default annual revenue
            }
        }
    }

    if (Trigger.isAfter && Trigger.isUpdate) {
        List<Contact> contactsToUpdate = new List<Contact>();
        for (Account acc : Trigger.new) {
            for (Contact con : [SELECT Id, AccountId FROM Contact WHERE AccountId = :acc.Id]) {
                con.Description = 'Account updated on ' + Date.today();
                contactsToUpdate.add(con);
            }
        }
        if (!contactsToUpdate.isEmpty()) {
            update contactsToUpdate;
        }
    }
}

In this example:

  • The trigger is defined on the Account object and handles two events: before insert and after update .
  • In the before insert context, it checks if the AnnualRevenue field is null and sets a default value if necessary.
  • In the after update context, it retrieves all related Contact records and updates their Description field to indicate that the related account was updated.

This example demonstrates how to use a single trigger to handle different types of operations efficiently and maintain clean, organized code by separating logic based on the trigger context.

What are the Disadvantages of Triggers in Salesforce?

Triggers in Salesforce, while powerful, come with several disadvantages that developers should be aware of:

  1. Complexity and Maintainability: Triggers can quickly become complex, especially when multiple triggers exist for the same object or when the logic within a trigger is extensive. This complexity can make the code difficult to read, understand, and maintain.
  2. Performance Issues: Poorly written triggers can cause performance problems. Triggers that perform SOQL queries or DML operations inside loops can quickly exceed Salesforce’s governor limits, leading to runtime exceptions and failed operations.
  3. Debugging Challenges: Debugging triggers can be challenging because they run automatically and can be triggered by various operations. This can make it difficult to isolate the source of an issue, particularly in a complex system with many interdependencies.
  4. Testing and Deployment: Writing comprehensive test classes for triggers is essential to ensure that all possible scenarios are covered. However, this can be time-consuming and complex. Additionally, deploying triggers requires careful management of dependencies and order of execution.

Read more: Approval Process in Salesforce.

How to Create Triggers in Salesforce?

Creating triggers in Salesforce involves the following steps:

  1. Navigate to the Object: Go to the object for which you want to create the trigger. You can do this by navigating to Setup > Object Manager and selecting the desired object.
  2. Create a New Trigger: In the object’s detail page, find the Triggers section and click New to create a new trigger.
  3. Write the Trigger Code: Write the trigger code in the Apex editor. Specify the trigger events (e.g., before insert, after update) and implement the desired logic.
  4. Save and Activate: Save the trigger. By default, the trigger is active once saved. You can deactivate it if needed.

Example

Here is a step-by-step example of creating a simple trigger on the Account object:

Navigate to the Account Object:

Go to Setup > Object Manager > Account.

Create a New Trigger:

Scroll down to the Triggers section and click New.

Write the Trigger Code:

trigger AccountTrigger on Account (before insert) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000; // Set default annual revenue
        }
    }
}

Previous article, Formula Fields in Salesforce, explains about Formula Fields.

Save the Trigger:

Click Save to save and activate the trigger.

What is the Primary Purpose of a Before Trigger in Salesforce?

The primary purpose of a before trigger in Salesforce is to perform operations or validations on records before they are saved to the database. Before triggers are particularly useful for enforcing business rules, setting default values, and ensuring data integrity before the data is committed to the database.

Use Cases for Before Triggers

  1. Data Validation: Before triggers can be used to validate data before it is saved. For example, you can check if a required field is populated or if the data meets certain criteria.
trigger OpportunityBeforeInsert on Opportunity (before insert) {
    for (Opportunity opp : Trigger.new) {
        if (opp.StageName == null) {
            opp.addError('Stage Name is required.');
        }
    }
}

Setting Default Values: Before triggers can automatically set default values for fields that were not provided by the user.

trigger AccountBeforeInsert on Account (before insert) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 500000; // Set default annual revenue
        }
    }
}

Preventing DML Operations: Before triggers can prevent certain DML operations by adding errors to the records, thus stopping the save operation.

Readmore: Data Loader Management in Salesforce

trigger AccountBeforeDelete on Account (before delete) {
    for (Account acc : Trigger.old) {
        if (acc.Name == 'Protected Account') {
            acc.addError('This account cannot be deleted.');
        }
    }
}

By using before triggers, developers can ensure that records meet specific criteria and business rules before they are stored in the Salesforce database, enhancing data quality and consistency.

When Should We Use Apex Trigger?

Apex triggers should be used in Salesforce when you need to perform custom actions before or after changes to Salesforce records. Triggers are particularly useful in the following scenarios:

Complex Business Logic: When you need to implement complex business logic that cannot be achieved through declarative tools like workflows and process builders. For example, updating related records or creating new records based on certain conditions.

trigger OpportunityAfterUpdate on Opportunity (after update) {
    List<Task> tasks = new List<Task>();
    for (Opportunity opp : Trigger.new) {
        if (opp.StageName == 'Closed Won') {
            tasks.add(new Task(
                WhatId = opp.Id,
                Subject = 'Follow-up',
                Status = 'Not Started',
                Priority = 'High'
            ));
        }
    }
    insert tasks;
}

Enforcing Data Integrity: When you need to enforce data integrity rules that span multiple objects. For example, ensuring that an account has at least one associated contact.

trigger AccountBeforeDelete on Account (before delete) {
    for (Account acc : Trigger.old) {
        Integer contactCount = [SELECT COUNT() FROM Contact WHERE AccountId = :acc.Id];
        if (contactCount > 0) {
            acc.addError('Cannot delete an account with associated contacts.');
        }
    }
}

Automating Repetitive Tasks: When you need to automate repetitive tasks that require programmatic logic. For example, automatically creating a case when a new account is created.

trigger AccountAfterInsert on Account (after insert) {
    List<Case> cases = new List<Case>();
    for (Account acc : Trigger.new) {
        cases.add(new Case(
            AccountId = acc.Id,
            Subject = 'New Account Created',
            Status = 'New'
        ));
    }
    insert cases;
}

What are Triggers in CRM?

In the context of Customer Relationship Management (CRM) systems, triggers are automated pieces of code that execute before or after specific events occur on records, such as insertions, updates, deletions, or undeletions. Triggers allow for the automation of business processes, data validation, and enforcement of complex rules that cannot be handled by standard configuration options.

What is the Difference Between a Trigger and a Transaction?

Trigger: A trigger is a piece of code that runs automatically in response to specific events on records in Salesforce. Triggers can be set to run before or after operations like insert, update, delete, and undelete.

Transaction: A transaction is a unit of work that is executed in a single operation. It includes all the steps from the start of the process until its end, such as DML operations, SOQL queries, and any triggers that are executed as part of those operations. If any part of the transaction fails, the entire transaction is rolled back, ensuring data integrity.

Checkout our Latest important Ultimate list of Salesforce interview questions and answers.

Why Triggers are Not Recommended?

While triggers are powerful, they are not always recommended due to several reasons:

  1. Complexity: Triggers can quickly become complex, especially when multiple triggers exist on the same object. This complexity makes the code harder to understand, maintain, and debug.
  2. Performance Issues: Poorly written triggers can cause performance problems. For example, triggers that perform SOQL queries or DML operations inside loops can exceed Salesforce’s governor limits, leading to runtime exceptions and failed operations.
  3. Testing and Deployment Challenges: Ensuring that triggers are thoroughly tested is essential but can be difficult, particularly when dealing with complex logic and dependencies. Additionally, deploying changes involving triggers requires careful management of dependencies and order of execution.
  4. Unintended Consequences: Triggers can lead to unintended side effects if they are not carefully managed. For example, a trigger on one object might cause changes in another object, leading to a chain of events that can be difficult to predict and control.

Example to Illustrate the Complexity of Triggers

Consider a scenario where you have multiple triggers on the Account object, each performing different tasks:

trigger AccountTrigger1 on Account (before insert, before update) {
    for (Account acc : Trigger.new) {
        if (acc.AnnualRevenue == null) {
            acc.AnnualRevenue = 1000000;
        }
    }
}

trigger AccountTrigger2 on Account (after insert, after update) {
    List<Contact> contactsToUpdate = new List<Contact>();
    for (Account acc : Trigger.new) {
        for (Contact con : [SELECT Id FROM Contact WHERE AccountId = :acc.Id]) {
            con.Description = 'Account updated on ' + Date.today();
            contactsToUpdate.add(con);
        }
    }
    if (!contactsToUpdate.isEmpty()) {
        update contactsToUpdate;
    }
}

In this example, the existence of multiple triggers can create complexity and potential performance issues. Consolidating the logic into a single trigger with a handler class can help manage this complexity:

trigger AccountTrigger on Account (before insert, after update) {
    AccountTriggerHandler.handle(Trigger.new, Trigger.oldMap);
}

public class AccountTriggerHandler {
    public static void handle(List<Account> newAccounts, Map<Id, Account> oldAccounts) {
        if (Trigger.isBefore && Trigger.isInsert) {
            beforeInsert(newAccounts);
        }
        if (Trigger.isAfter && Trigger.isUpdate) {
            afterUpdate(newAccounts);
        }
    }

    private static void beforeInsert(List<Account> newAccounts) {
        for (Account acc : newAccounts) {
            if (acc.AnnualRevenue == null) {
                acc.AnnualRevenue = 1000000;
            }
        }
    }

    private static void afterUpdate(List<Account> newAccounts) {
        List<Contact> contactsToUpdate = new List<Contact>();
        for (Account acc : newAccounts) {
            for (Contact con : [SELECT Id FROM Contact WHERE AccountId = :acc.Id]) {
                con.Description = 'Account updated on ' + Date.today();
                contactsToUpdate.add(con);
            }
        }
        if (!contactsToUpdate.isEmpty()) {
            update contactsToUpdate;
        }
    }
}

Where are Salesforce Triggers can be found?

Salesforce triggers are found within the Salesforce platform, specifically tied to Salesforce objects (sObjects). To locate and manage triggers, follow these steps:

  1. Navigate to Setup: In Salesforce, click on the gear icon in the upper right corner and select “Setup”.
  2. Object Manager: In the Setup menu, go to “Object Manager”.
  3. Select the Object: Choose the object for which you want to view or create a trigger, such as Account, Contact, or Opportunity.
  4. Triggers Section: On the object’s detail page, scroll down to the “Triggers” section. Here, you can view existing triggers or create a new one.

Readmore: Workflow rules in Salesforce

What are Purpose Triggers?

The primary purpose of triggers in Salesforce is to automate and enforce business logic and data integrity rules that are not possible through declarative means like workflows, process builders, or validation rules. Triggers allow developers to perform custom actions before or after changes to Salesforce records.

Key Purposes of Triggers:

  1. Enforcing Business Rules: Triggers ensure that certain business rules are adhered to, such as preventing deletion of critical records or ensuring specific fields are populated.
  2. Automating Complex Processes: Triggers automate complex processes that involve multiple objects or require intricate logic, such as updating related records or creating new records based on specific conditions.
  3. Maintaining Data Integrity: Triggers help maintain data integrity by validating data before it is committed to the database and ensuring related records are consistent.

How Do I Schedule a Trigger in Salesforce?

In Salesforce, you cannot directly schedule a trigger to run at a specific time. However, you can schedule an Apex job that performs similar operations using the Schedulable interface. This involves creating a scheduled Apex class that contains the logic you want to execute and then scheduling this class to run at specific times using the Salesforce user interface or the System.schedule method.

Read more: Database methods – Salesforce Apex

Steps to Schedule an Apex Job:

Create an Apex Class: Write a class that implements the Schedulable interface.

Schedule the Apex Class: Schedule the class to run at a specific time using the Salesforce user interface or the System.schedule method.

Using the User Interface:

  • Go to Setup > Apex Classes > Schedule Apex.
  • Enter a job name, select the class you created, and specify the schedule.

Using the System.schedule Method:

String cronExp = '0 0 12 * * ?'; // Run daily at noon
ScheduledTriggerExample scheduledJob = new ScheduledTriggerExample();
System.schedule('Daily Job', cronExp, scheduledJob);

In this example:

  • The ScheduledTriggerExample class implements the Schedulable interface and contains the logic to update accounts.
  • The System.schedule method is used to schedule the job to run daily at noon.

By following these steps, you can effectively schedule operations that would typically be handled by a trigger, providing greater flexibility and control over when your logic is executed.

At CRS Info Solutions, our top-tier Salesforce course are crafted to help you achieve certification and excel in interviews. Our extensive training programs include Salesforce Admin, Developer, and LWC, equipping you with the essential skills for success.

With our experienced instructors and interactive learning methods, mastering Salesforce becomes both attainable and enjoyable. Enroll with us to advance your career through exceptional Salesforce training.

Comments are closed.