Use SetAutoCalcFields for loops
When CalcFields is called inside a loop, each iteration issues a separate SQL query per FlowField. For a table with 10,000 records and 3 FlowFields, that is 30,000 additional round trips on top of the data retrieval itself. SetAutoCalcFields called before the loop tells the runtime to include the FlowField calculations in the main SELECT query, eliminating the per-iteration overhead entirely.
Example
The following code calls CalcFields on every iteration of a FindSet loop:
procedure MyProcedure()
var
Customer: Record Customer;
begin
Customer.FindSet();
repeat
Customer.CalcFields("Balance (LCY)"); // Use SetAutoCalcFields for loops [PC0035]
until Customer.Next() = 0;
end;To fix this, replace the CalcFields call with SetAutoCalcFields before the loop:
procedure MyProcedure()
var
Customer: Record Customer;
begin
Customer.SetAutoCalcFields("Balance (LCY)");
Customer.FindSet();
repeat
// Balance (LCY) is now automatically calculated on each record fetch
until Customer.Next() = 0;
end;Reports
A report dataitem loops over its records, so OnAfterGetRecord runs once per row. A CalcFields call there issues one SQL query per FlowField on every row, the same per-iteration cost as a repeat loop:
report 50100 "Customer Balances"
{
dataset
{
dataitem(Customer; Customer)
{
column(Balance; "Balance (LCY)") { }
trigger OnAfterGetRecord()
begin
CalcFields("Balance (LCY)"); // Use SetAutoCalcFields for loops [PC0035]
end;
}
}
}Move the calculation to SetAutoCalcFields in OnPreDataItem. It runs once, before the dataitem iterates, and includes the FlowField in the main query:
report 50100 "Customer Balances"
{
dataset
{
dataitem(Customer; Customer)
{
column(Balance; "Balance (LCY)") { }
trigger OnPreDataItem()
begin
SetAutoCalcFields("Balance (LCY)");
end;
}
}
}When the diagnostic is reported
The rule fires when all of the following conditions are true:
- A
CalcFieldsinvocation is found inside a loop body - The
CalcFieldscall is on the same record variable that drives the loop - The loop is one of:
FindSet/Find+repeat...until,while...do, or a reportOnAfterGetRecordtrigger
The rule does not track CalcFields calls across method boundaries — a CalcFields inside a helper procedure called from a loop is not detected.
The rule is not reported on temporary records, because SetAutoCalcFields rewrites the SQL SELECT and is a no-op for in-memory data. This covers both forms of temporary: a variable declared with the temporary keyword (Record Customer temporary) and a table object declared with TableType = Temporary. CalcFields still works on such records (it evaluates each FlowField’s CalcFormula against the real source tables), so no swap is suggested.
Code fix
The ALCops: Use SetAutoCalcFields before loop code fix applies to FindSet/Find + repeat...until and while...do loops:
- Inserts a
SetAutoCalcFieldscall with the same field arguments before the loop (or before theFindSet/Findstatement) - Removes the
CalcFieldscall from inside the loop body
When multiple CalcFields calls exist for the same variable in the same loop, each is handled individually by the fix-all provider.
The fix is not offered for report OnAfterGetRecord triggers. There is no loop statement to insert before, and the correct location is OnPreDataItem, a different trigger. Move SetAutoCalcFields there manually, as shown above.
See also
- Record.SetAutoCalcFields on Microsoft Learn
- RecordRef.SetAutoCalcFields on Microsoft Learn
- CalcFields vs SetAutoCalcFields by Luc van Vugt
- AutoCalcField Property on Microsoft Learn