Use ReadIsolation instead of LockTable (LC0031)

This rule flags calls to LockTable() and suggests replacing them with ReadIsolation := IsolationLevel::UpdLock.

While the change in code is small, the difference at the platform level is significant. LockTable() modifies the global session state: once called on any record variable, every subsequent read against that table — on any variable instance — will acquire an update lock for the remainder of the transaction. This means an event subscriber, a FlowField calculation, or unrelated code further down the call stack can end up locking rows it never intended to touch.

ReadIsolation, introduced in Business Central 2023 wave 1 (v22), works differently. It sets the isolation level on the specific record variable only. Other variables of the same table remain unaffected, keeping lock scope tight and predictable.

There is another reason to make the switch: tri-state locking (default from v25 onward) falls back to pessimistic two-state locking the moment LockTable() is called anywhere in the transaction. Replacing LockTable() with ReadIsolation preserves the tri-state benefits — fewer locks, higher concurrency, and fewer lock timeouts across the system.

A code fix is available for this diagnostic.

Example

The following procedure locks the entire G/L Entry table for the rest of the transaction just to read the last entry number:

codeunit 50100 MyCodeunit
{
    procedure GetNextEntryNo(): Integer
    var
        GLEntry: Record "G/L Entry";
    begin
        GLEntry.LockTable();
        GLEntry.FindLast();
        exit(GLEntry."Entry No." + 1);
    end;
}

With ReadIsolation, only this specific variable acquires the lock. Any other code reading from G/L Entry later in the transaction remains unaffected:

codeunit 50100 MyCodeunit
{
    procedure GetNextEntryNo(): Integer
    var
        GLEntry: Record "G/L Entry";
    begin
        GLEntry.ReadIsolation(IsolationLevel::UpdLock);
        GLEntry.FindLast();
        exit(GLEntry."Entry No." + 1);
    end;
}

Deep dive

The articles below explore the locking differences in detail, including real-world examples, SQL-level traces, and the interaction with tri-state locking: