mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-08-06 09:26:52 +01:00
Cover non-obvious platform behaviors a capable LLM reliably gets wrong: hidden FlowFields still calculate, LockTable scopes to the whole table, query objects bypass the primary-key cache, table-event subscribers disable bulk ModifyAll/DeleteAll, Blob fields are uncached, OnCompanyOpen subscribers block every session creation, and the test framework disables bulk insert mode. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
24 lines
1.9 KiB
Markdown
24 lines
1.9 KiB
Markdown
---
|
|
bc-version: [all]
|
|
domain: performance
|
|
keywords: [event, subscriber, modifyall, deleteall, bulk, row-by-row]
|
|
technologies: [al]
|
|
countries: [w1]
|
|
application-area: [all]
|
|
---
|
|
|
|
# Table event subscribers force ModifyAll and DeleteAll to run row-by-row
|
|
|
|
## Description
|
|
|
|
`ModifyAll` and `DeleteAll` normally compile to a single set-based SQL UPDATE or DELETE. That optimization is conditional: if any subscriber is bound to the table's modify or delete events — `OnBeforeModifyEvent`, `OnAfterModifyEvent`, `OnBeforeDeleteEvent`, `OnAfterDeleteEvent`, and their Rec counterparts — the server must invoke AL per affected row so the subscriber sees each record. The operation falls back to a row-by-row loop, one SQL statement per row, inside the same transaction.
|
|
|
|
The slowdown is invisible in the caller's source: the call site still reads as a bulk operation. It only shows up under load, and adding an apparently cheap subscriber (even an empty one, or one that guards on a condition and returns) is enough to trigger the fallback for every caller of ModifyAll/DeleteAll on that table across the system. Central tables — Item Ledger Entry, G/L Entry, Sales Line — are the worst places to attach such subscribers because every extension's bulk operation pays the cost.
|
|
|
|
## Best Practice
|
|
|
|
Before subscribing to a table's modify or delete events, consider whether the logic can live elsewhere — on the triggering action, on a specific OnValidate, or on a business-event publisher. If the subscriber is unavoidable, scope it as narrowly as possible and document that it forces row-by-row execution so future maintainers understand the cost. Watch PRs that add such subscribers to heavily-modified tables.
|
|
|
|
## Anti Pattern
|
|
|
|
An empty or nearly-empty `OnAfterModifyEvent` subscriber on `Sales Line` added as a placeholder for future integration. Every `ModifyAll` on `Sales Line` — in the base app, in every extension, in every tenant — now runs one SQL UPDATE per row.
|