React to Changes with Apex Triggers

To automate your business with external change events, use Apex triggers.

Codey Outfitters can customize Salesforce to send email or SMS notifications on items that are low on stock or have been updated to an attractive price. Gear and other items that are in high demand can be monitored for low stock and automatically ordered. Before customizing Salesforce, make sure that you’re tracking data changes on the external object that you want to track. To track items that are running low on stock, Codey Outfitters creates an Apex trigger named LowOnStock. Next, the company selects the trigger’s sObject and the change event that publishes changes for the external object Products__x: Products__ChangeEvent.

Here’s an example of a simple rule that sends a notification when an item is low on stock.

trigger LowOnStock on Products__ChangeEvent (after insert) {
    // Get the change event’s product ID for added and updated products
    Set<Id> productIds = new Set<Id>();
    for (Products__ChangeEvent event: Trigger.new) {
        if (event.ChangeEventHeader.getChangeType() != 'DELETE') {
            String productId = event.ChangeEventHeader.getRecordIds()[0];
            productIds.add(productId);
        }
    }
    if (productIds.size() > 0) {
        ProductNotifications.notifyOnLowOnStockProductUpdates(productIds);
    }
}

The product notifications class queries the external Product objects for the given changed product IDs and LowOnStock threshold value. Looking up the current Product records on the external system for qualifying products is a callout and is scheduled as an Apex future.

public class ProductNotifications {    
    // Notify subscribers on product updates that are low on stock.
    // This method is run asynchronously as it is performing a callout to the external
    // system to get the latest product details
    @future (callout=true)
    public static void notifyOnLowOnStockProductUpdates(Set<Id> productIds) {
        // Look up the current stock threshold to filter the products with
        Integer productStockThreshold = ...;
        List<Products__x> lowOnStockProducts =
            getProductsLowOnStock(productIds, productStockThreshold);
        // Notify subscribers
        notifySubscribers(lowOnStockProducts,
            ‘These items are running out of stock. Act soon!’);
    }
    
    // Get the external Product objects for each Product ID
    public static List<Products__x>
    getProductsLowOnStock(Set<Id> productIds, Integer productStockThreshold) {
        return [SELECT Id, ExternalId, Name__c, ProductId__c, Stock__c, UnitPrice__c  
            FROM Products__x
            WHERE Stock__c < :productStockThreshold  AND Stock__c > 0 AND 
                Id IN :productIds];
    }
    
    // Notify subscribers by sending an email or SMS
    public static void notifySubscribers(String message, List<Products__x> products) {
        ...
    }
}

You can discover the metadata for change events through the sObject describe API. For example, the sObject describe for Products__ChangeEvent shows the following standard change event fields.

Field Type Description
Id String The change event’s Salesforce ID. This ID isn’t the Salesforce ID of the record that changed, but the event that carries the record’s changes.
ReplayId String The position of the event notification in the event stream on a channel.
ChangeEventHeader Complex Type The type of data change event.

Each change event object defines fields that hold the updated value at the time the record was updated. The OData producer can also include fields that haven’t changed. To see the current values, query the external object using the record ID in the change event header.

The following table shows sample Products__x fields. Event change objects are tailored to their tracked external object. For a change event, not all fields are necessarily present.

Field Type Description
Id String Product record’s Salesforce ID in your org
ExternalId String Product record’s external ID
DisplayUrl String URL representing the record in the external system
CreatedOn__c DateTime When the record was created in the external system
UpdatedOn__c DateTime When the record was last updated on the external system
Name__c String Product name in Product__x
OrderLimit__c Integer Number of items that can be ordered at a time
Stock__c Integer Number of items in stock
UnitPrice__c Decimal(8,2) Item’s unit price

The following fields are change event header complex type fields. To access ChangeEventHeader fields from Apex, use its getter method. For example, to access the field ChangeType, use eventObject.ChangeEventHeader.getChangeType().

Field Type Description
commitUser String User who published the event.
sequenceNumber Integer Change event sequence number. Each change is listed in the order in which it’s received.
entityName String API name of the external object.
changeType ChangeType enum Specifies whether a record was updated, created, or deleted. The enum values for external change events are Create, Update, and Delete.
changeOrigin String Delta link that’s used to request the changes made since the previous or initial change request. The OData producer calculates the delta token while executing the previous change request.
transactionKey String Unique identifier for the transaction.
commitTimestamp Long Specifies when the change event notification is published in milliseconds since January 1, 1970.
recordIds Array of type String Salesforce ID of the external object record that is updated, created, or deleted. To see the current values of the record fields, query the external object using this record ID. This array always has exactly one Salesforce ID.
nulledFields Array of type String List of field names set to null.