Use Validate() instead of direct field assignment
When a value is assigned to a record field with :=, the AL runtime writes the value directly without executing the field’s OnValidate trigger. Any event subscribers attached to that trigger — from Microsoft, partners, or per-tenant extensions — are silently skipped.
On the Sales Line table, for instance, the OnValidate trigger on "Unit Price" recalculates "Line Amount" from Quantity * "Unit Price". A direct assignment to "Unit Price" leaves "Line Amount" stale — the posted invoice carries the wrong total.
Use Validate() to assign field values so the full validation chain executes regardless of which extensions are installed.
Example
procedure SetUnitPrice(var SalesLine: Record "Sales Line"; NewPrice: Decimal)
begin
SalesLine."Unit Price" := NewPrice; // Use Validate() instead of direct field assignment [PC0037]
SalesLine.Modify(true);
end;Replace the direct assignment with Validate():
procedure SetUnitPrice(var SalesLine: Record "Sales Line"; NewPrice: Decimal)
begin
SalesLine.Validate("Unit Price", NewPrice);
SalesLine.Modify(true);
end;Code fix
The code fix replaces Record."Field" := Value with Record.Validate("Field", Value) preserving the original value expression as the second argument.
Exceptions
The rule is not raised when:
- The record variable is declared as
temporaryand the table is a normal (persisted) table. A real table used as a scratch buffer may carryOnValidatelogic with side effects the caller never intended, so bypassing it is a legitimate choice. - The table is an externally-backed integration table (
TableType = CRM,CDS,ExternalSQL,ExchangeorMicrosoftGraph). TheirOnValidateonly runs for AL-side changes, never for changes coming from the external system, soValidate()would suggest a guarantee that does not exist.
Tables with TableType = Temporary
Tables declared with TableType = Temporary are in scope, whether or not the variable also carries the temporary keyword (the keyword is redundant on such a table). Whoever writes an OnValidate trigger on an inherently temporary table knows it is temporary, so that logic is designed to run — in the Base Application such triggers modify other records, raise integration events and ask for confirmation. Like any other table, a TableType = Temporary table can also be extended with OnBeforeValidate/OnAfterValidate triggers from another app. This mirrors PC0027
, which does not warn about Validate() on TableType = Temporary records.
For trigger-less buffer tables where the warning adds nothing, disable the rule for that block or in a ruleset.
Use a pragma when you have a documented reason to bypass validation:
#pragma warning disable PC0037 // Justify why we don't execute the validation on the "Unit Price" field
SalesLine."Unit Price" := NewPrice;
#pragma warning restore PC0037