BC AL Journey #19

All the way back in BC AL Journey #10 we started learning about triggers, specifically the OnValidate trigger of a field on a table extension. The OnValidate is one of the most useful triggers as it enabled you to respond to a user’s data input, there are other triggers that provide a lot of utility.

In this step of our journey we are going to take a deeper look at table triggers, where they go and what utility they have. This is going to be a little abstract as we aren’t going to go too deep into code-based solutions right now, but this is priming us for future concepts.

Table Triggers

Table triggers are focused on events happening at the record level. Let’s add a few triggers to the WarrantyClaim record created previously.

/*
    Customized in BC AL Journey #13
*/
namespace AardvarkLabs;
table 50001 ARDWarrantyClaim
{
    Caption = 'WarrantyClaim';
    DataClassification = CustomerContent;
    DataCaptionFields = "WarrantyClaimNo.", "CustomerNo.";
    
    fields
    {
        field(1; "WarrantyClaimNo."; Integer)
        {
            Caption = 'Warranty Claim No.';
            ToolTip = 'Warranty Claim Number';
            AutoIncrement = true;
        }
        field(2; "CustomerNo."; Code[20])
        {
            Caption = 'Customer No.';
            ToolTip = 'Associated Customer Number';
        }
        field(3; Details; Text[255])
        {
            Caption = 'Details';
            ToolTip = 'Warranty claim details';
        }
        field(4; "Date"; Date)
        {
            Caption = 'Date';
            ToolTip = 'Warranty Claim Date';
        }
        field(5; Resolved; Boolean)
        {
            Caption = 'Resolved';
            ToolTip = 'Indicate if the Claim has been resolved';
        }
    }
    keys
    {
        key(PK; "WarrantyClaimNo.","CustomerNo.")
        {
            Clustered = true;
        }
    }

    trigger OnInsert()
    begin
        Rec.Date := DT2Date(CurrentDateTime);
    end;

    trigger OnModify()
    begin
        if Rec.Date = 0D then
            Rec.Date := DT2Date(CurrentDateTime);
    end;

    trigger OnDelete()
    begin
        if Rec.Resolved then
            error('Cannot delete a resolved warranty claim');
    end;

    trigger OnRename()
    begin
        error('Cannot rename a warranty claim');
    end;
}

The OnInsert trigger runs anytime a record is added to the table. In this case we are defaulting the Date field to the current datetime. The OnInsert trigger is a good time to enforce defaults and validate that the data in the record is good. The Rec variable is a free global variable that is the data in the current record. If you throw an error, the record is not inserted.

The OnModify trigger happens when a record is modified. We have our Rec variable, there is also an xRec variable which is the record BEFORE it was changed. The modify trigger, like the OnInsert trigger is a great place to check for data validity and integrity. If you throw an error, the changes are not applied.

The OnDelete trigger is for validation and cleanup. If you have related child records that cannot be accessed without the parent record, here is where you can cascade the delete and delete the child records. In this example, we are throwing an error if the Claim Record is resolved and preventing the record from being deleted.

The OnRename trigger is only fired when you change the Primary Key of a record. This gives you the opportunity to find all the records referencing the previous primary key and update them to the new primary key. This is needed because Business Central doesn’t enforce any key relationships, and we are tasked with maintaining them ourselves. In this example I throw an error, which prevents the user from renaming the record.

With the exception of the OnRename trigger, all of these other triggers are optional. When using code to create a new record like this:

Procedure CreateWarrantyRecord()
var
    Claim: Record ARDWarrantyClaim;
begin
    Claim."WarrantyClaimNo." := 1;
    Claim."CustomerNo." := 'C00012';
    Claim.Insert(true);
end;

Note that the Clain.Insert has a “true” flag in the parameter. This indicates that I want to run the insert and fire the OnInsert trigger. If I change that flag to a false, then the trigger will not run. This is the same for the OnModify and OnDelete triggers.

Table Extensions get three times the number of triggers, as each of the four triggers we have discussed on the Table have an additional OnBefore and OnAfter version. For example, a table extension has an OnBeforeInsert, OnInsert, and OnAfterInsert trigger which allows us to do things before the Tables OnInsert, with the tables OnInsert, and after the tables OnInsert trigger.

Table triggers are the most important set of triggers for data integrity and management. Using them properly will ensure that your data is up to date and coherent. Next step we will be taking a deeper look at Page triggers and how we can utilize them to interact with users and provide active feedback.

This trigger exploration is available in GitHub here: AardvarkMan/BC-AL-Triggers

One response to “Essential Triggers for Record Management in AL Programming”

  1. […] BC AL Journey #19 we dove deeper into the world of AL Triggers and specifically the Table triggers. This was a […]

    Like

Leave a reply to Essential Triggers for Table Field Management in AL Programming – Aardvark Labs Cancel reply

Trending