2

All of the information that I've read about triggers seems to indicate that they only work in 'bulk' - ie, if I build an update trigger on an Account object, whenever an Account is updated, the trigger will affect all Account objects.

I want to send an external HTTP request when an Account is updated, containing the Salesforce Object Id of the updated Account: is there a way within the trigger to access only the object that was updated?

3
  • 7
    The trigger will only run for the updated records.
    – Akram G
    Aug 2, 2016 at 15:35
  • 3
    ... meaning as few records as 1 record. The point is to code for both 1 or many records.
    – Keith C
    Aug 2, 2016 at 16:15
  • Voting to leave open because I think this User could still have a useful answer for them by explaining what is wrong with their logic.
    – dphil
    Aug 2, 2016 at 18:25

3 Answers 3

4

Triggers operate in collections of 200 records.

  • If you update one record in a DML statement, the trigger will have that one record in its collection.

  • If you update 100 records in a DML statement, the trigger will have 100 records in its collection.

  • If you update 200 records in a DML statement, the trigger will have 200 records in its collection.

  • If you update 1000 records in a DML statement, the platform will chunk the 1000 records into groups of 200. Your trigger will run 5 times, with 200 records in each invocation.

Triggers must be written to handle records in collections of 200. Your use case currently might only be that one record will be updated and one HTTP Request will be made to an external system but there are plenty of ways that more than one Account can be updated at a time and your code needs to handle those scenarios gracefully.

Your unit tests for this trigger's behavior should also address the scenario of updating 200 records in one transaction and that the external callout behaves as you intend.


Some info about using Queueables instead of @future methods to perform a callout to an external system invoked from a trigger, which might be useful to you.

https://developer.salesforce.com/blogs/developer-relations/2015/05/queueable-apex-future.html

1
  • Thanks Mark - you're right - I was thinking about a single use case, not about multiple records being updated at the same time. Kudos to Nick Cook below for the note about Trigger.new always being a list of objects.
    – dbcn
    Aug 2, 2016 at 20:43
1

All of the information that I've read about triggers seems to indicate that they only work in 'bulk' - ie, if I build an update trigger on an Account object, whenever an Account is updated, the trigger will affect all Account objects.

You're half right. It's recommended, if not essential that triggers are "bulkified" meaning they can handle more than one record and won't hit a govenor limit (e.g. query in a for loop). However, updating the Account "Universal Containers" Account will only affect that one particular account.

I want to send an external HTTP request when an Account is updated, containing the Salesforce Object Id of the updated Account: is there a way within the trigger to access only the object that was updated?

Absolutely. A standard Trigger will do just this once the HTTP request is processed.

The way I personally like to do this is to have a Trigger called AccountTrigger, ContactTrigger, MyObjectTrigger and reference a class that does the actual processing (e.g. AccountAction, ContactAction, MyObjectAction).

For example:

AccountTrigger

trigger AccountTrigger on User (before insert, before update, after insert, after update) {
  if (Trigger.isAfter) {
    if (Trigger.isUpdate) {
      AccountAction.myCustomMethod(Trigger.newMap.keySet());
    }
  }
}

AccountAction

public class AccountAction {
  public static void myCustomMethod(Set<Id> accs) {
    // Do stuff before the actual method is called...
    doMyCustomMethod(accs);
  }

  private static void doMyCustomMethod(Set<Id> accs) {
    List<Account> accountList = [SELECT Id FROM Account WHERE Id IN: accs];
    // Process the accounts "caught" in the Trigger
  }
}

I'm not saying this is the best way of doing things, but it is definitely a way of doing things.

1

A trigger will always process all records that are part of that insert/update/delete. This means the Trigger.new variable will always be a list.

Having said this, when a user creates or inserts an Account, the trigger will still run on a list of Account records, however there will only be one item within that list.

If you're expecting to only receive a single record, and perhaps only want to perform actions when there is only one record, you can always check how many records within the trigger.

Keep in mind that this can't differentiate between a single record being loaded via the data loader, a single record being updated via some web service, or a single record being updated via the Salesforce UI.

You could use code such as:

if(Trigger.new.size() == 1)
{
    Account theAccount = Trigger.new[0];
    // perform actions on theAccount
}
2
  • I would avoid recommending this approach for the reason you stated - Data Loader. Triggers should always be coded for bulk operations, even callouts as suggested by OP. @MarkPond has the right idea here to use queueables when more than governor limit of callouts per trigger list size
    – cropredy
    Aug 2, 2016 at 16:59
  • Thanks Nick - your statement about Trigger.new always being a list was very helpful and clarified a lot, but I agree with cropredy that MarkPond's answer is probably best practice.
    – dbcn
    Aug 2, 2016 at 20:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .