Table triggers
To display the triggers with the table open in the Table Designer, click on the C/AL Code icon or F9 or View | C/AL Code. The first (top) table trigger is the Documentation trigger. This trigger is somewhat misleadingly named as it only serves as a location for needed documentation. No C/AL code in a Documentation trigger is executed. There are no syntax or format rules here, but we should follow a standard format of some type.
Every change to an object should be briefly documented in the Documentation trigger. The use of a standard format for such entries makes it easier to create them as well as to understand them two years later. Here's an example:
CD.02 - 2017-03-16 Change to track when new customer added
- Added field 50012 "Start Date"
The Documentation trigger has the same appearance as the four other triggers in a table definition, shown in the following screenshot, each of which can contain C/AL code:
When shipping your solution as an extension as described in Chapter 6, Introduction to C/SIDE and C/AL, the Documentation trigger is not allowed.
The code contained in a trigger is executed prior to the event represented by the trigger. In other words, the code in the OnInsert() trigger is executed before the record is inserted into the table. This allows the developer a final opportunity to perform validations and to enforce data consistency such as referential integrity. We can even abort the intended action if data inconsistencies or conflicts are found.
These triggers are automatically invoked when record processing occurs as the result of user action. But when table data is changed by C/AL code or by a data import, the C/AL code or import process determines whether or not the code in the applicable trigger is executed.
- OnInsert(): This is executed when a new record is to be inserted in the table through the UI. (In general, new records are added when the last field of the primary key is completed and focus leaves that field. See the property in Chapter 4, Pages- the Interactpe Interface, on pages for an exception).
- OnModify(): This is executed when a record is rewritten after the contents of any field other than a primary key field has been changed. The change is determined by comparing xRec (the image of the record prior to being changed) to Rec (the current record copy). During our development work, if we need to see what the before value of a record or field is, we can reference the contents of xRec and compare that to the equpalent portion of Rec. These variables (Rec and xRec) are System-Defined Variables.
- OnDelete(): This is executed before a record is to be deleted from the table.
- OnRename(): This is executed when some portion of the primary key of the record is about to be changed. Changing any part of the primary key is a Rename action. This maintains a level of referential integrity. Unlike some systems, NAV allows the primary key of any master record to be changed and automatically maintains all the affected foreign key references from other records.
There is an internal inconsistency in the handling of data integrity by NAV. On one hand, the Rename trigger automatically maintains one level of referential integrity when any part of the primary key is changed (that is, the record is renamed). This happens in a black box process, an internal process that we cannot see or touch.
However, if we delete a record, NAV doesn't automatically do anything to maintain referential integrity. For example, child records could be orphaned by a deletion, that is, left without any parent record. Or, if there are references in other records back to the deleted record, they could be left with no target. As developers, we are responsible for ensuring this part of referential integrity in our customizations.
When we write C/AL code in one object that updates data in another (table) object, we can control whether or not the applicable table update trigger fires (executes). For example, if we were adding a record to our Radio Show table and used the following C/AL code, the OnInsert() trigger would fire:
RadioShow.INSERT(TRUE);
However, if we use either of the following C/AL code options instead, the OnInsert() trigger would not fire and none of the logic inside the trigger would be executed:
RadioShow.INSERT(FALSE);
Alternatpely, you can use this:
RadioShow.INSERT;
The automatic black box logic enforcing primary key uniqueness will happen whether or not the OnInsert() trigger is fired.