Trigger features and rules
In the previous section, we saw that the order of execution of Salesforce automation has to deal with all of the available automation tools within the Salesforce platform and that Apex triggers are called twice, before and after the record is saved to the database.
This is one of the pros of using Apex triggers:
- Before save events are not available on Process Builder actions. That is, on Process Builder, any action or logic is done only after the record has already been saved to the database; with before triggers, we can implement complex logic that deals with unrelated objects and that can be used to validate records in a better way. The example I usually use is validating Italian fiscal code: the code is composed of characters that come from the first name, last name, date of birth, a code that refers to the town of birth (called the Belfiore Code), and a check character (more details at https://en.wikipedia.org/wiki/Italian_fiscal_code_card). The algorithm is quite complex, so it is not suitable to be developed using validation rules (I bet there is an awesome administrator out there someone who can do it, but believe me, it would be easier using Apex code): that’s why the before trigger is the best place to validate whether your Italian customer has a valid fiscal code. If you try to make a SOQL query asking for the current record from within the before trigger, you won’t find anything, as the record has not been saved yet. The before trigger is also used to fill in current record fields without the need for further DML operations, just like setting a default value or a formula value in a custom way: if you change a value or a field in a before trigger, the system considers it as a new value that comes from the original save request.
- After save events happen only after the record has already been saved to the database (but not yet committed).
Another important feature of triggers is the possibility of accessing new and previous values of a given record: that is, if you update the Account.Name field, you are able to get the old and new values at once (we’ll see it shortly), and this allows a more complex scenario of record validation.
When a trigger is executed (whether it is in a before or update event), all records for the given save action are passed through: this can be easily tested using some Apex code (running anonymously from the Developer Console, as we have seen in Chapter 2, Auditing and Monitoring) or using Data Loader by creating/updating more than one record at once. While in tools like Process Builder we have an all or none approach, that is, if something goes wrong everything is rolled back, while using Apex triggers you can selectively make a record pass the save process (while the rest of records won’t), so partial success is possible and easily achievable.
Finally, delete and undelete operations are only available through Apex triggers: you can develop a complex cascading delete action (for example, by deleting the parent record or even physically unrelated records), or simply restore a record with an undelete operation and simultaneously alter the record itself to keep track of the undeletion (for example, undeleting an opportunity may need the close date to be postponed to a future date).
One last thing that’s useful for developers is that, using triggers, you can get a full and precise debug log that allows a developer to uncover a bug easily, while using Process Builder and Lightning Flow error messages are more generic and usually more difficult to address (and even worse if automation logic simultaneously involves multiple automation tools).
One of the main rules when using Apex triggers is to have only one trigger per object: if you have more than one, you won’t know which trigger is executed first. For example, let’s say you have two triggers on an opportunity object, both related to the after save event:
- The first trigger gets all the opportunities related to an account and updates a field on that account, setting it to the overall sum of opportunities (without considering their stage or closure status) created in the last month.
- The second trigger is used to delete a set of opportunities related to the same account that in the last month has been lost.
As there is no way to determine which trigger is run first, you can have trigger 1 executing before trigger 2 or vice versa, delivering a significantly different result.
In fact, if trigger 1 is executed first, it will sum all the opportunities of the last month, including the lost ones, which are then deleted by trigger 2.
If trigger 2 is executed first, the lost opportunities are deleted before trigger 1 sums the amounts, delivering a potentially lower sum.
The solution is to merge the code into one trigger, delivering a more stable and predictable code.