Designing an Equipment Rental extension for scale
A partner is building an Equipment Rental per-tenant extension. Requirements: on the Customer card, a "Rental Blocked" boolean and "Max Open Rentals" integer; a new "Rental Contract" header and line table; the Customer list must display an "Open Rental Count"; the rental line page must only offer items in the Rental Item category; and the Customer card must warn the user when Max Open Rentals is exceeded at contract release. Current data volume is 400,000 customers and 2,000,000 rental lines. A first prototype added a FlowField that sums line amounts onto Customer, and the customer list page now takes 20 seconds to open.
1. Which AL object types should be used for each requirement, and why?
Read the worked answer
- Customer fields →
tableextensionon Customer, plus apageextensionon the Customer Card and Customer List to surface them. Never modify the base table; the extension travels with the app and survives upgrades. - Rental Contract header and lines → new tables in the 50100+ range with a
TableRelationfrom line to header on "No.", and aLookupPageId/DrillDownPageIdon the header so lookups work. - Item category restriction → a
TableRelationwith afilteron the line's Item No. field, or anOnLookuptrigger if the rule needs to consider contract context. Prefer declarativeTableRelationwhen the rule is static - it also protects programmatic assignment viaValidate. - Warning at release → a codeunit that subscribes to the release event of the sales/rental document; not a page trigger, because the rule must hold for any caller, including APIs and job queue entries.
- Option vs Enum → use
Enumfor the category and any new status field; Enums are extensible by other extensions and avoid the Option-extension limitations.
Judgment being tested: choose the object type by who must be protected from the rule, and prefer declarative validation over UI-level code.
2. The prototype's FlowField makes the customer list take 20 seconds. Diagnose the cause and propose a design that scales.
Read the worked answer
A SumFlowField over 2,000,000 lines is computed per visible row on a list page. With 400,000 customers, the page issues an aggregate query for each row rendered, and each aggregate has to scan the line table. Twenty seconds is the expected consequence, not a bug.
Options, in order of preference:
- Denormalize a counter. Store
Open Rental Counton the Customer table and maintain it in the same transaction that creates, releases or closes a rental contract. Reads become a single field fetch; writes cost oneModify. Choose this when the counter is read constantly and changed rarely relative to reads. - Keep a FlowField but make it cheap. A
Countformula with a properly indexed key on the line table (Customer No. as the leading key field) is far cheaper than a sum across many columns - but it is still N queries per page. - Compute on demand. Do not put the FlowField on the list page by default; show it on the card and calculate when the user opens it (
CalcFields). Good when the number is informational. - Avoid FlowFilter on a huge table - a filtered FlowField is the most expensive variant of an already expensive pattern.
Also check the page: if a FlowField is displayed, ensure only the fields actually needed are calculated, and keep the list page's source table narrow. The exam judgment is recognizing that a FlowField is a query, and a list page multiplies it by row count.
3. Where should the "blocked" and "max open rentals" validation live, and should the release check raise an error or a warning?
Read the worked answer
Split the rule by consequence:
- Field-level rules (for example: Max Open Rentals cannot be negative, or cannot be set while Rental Blocked is true) belong in the
OnValidatetrigger of the table field, so every write path - page, API, job queue - is covered. Put the rule in the table, not in the page's trigger, and let the page inherit it. - Cross-record rules (open rentals exceed the maximum) cannot be enforced on
OnValidateof a single field, because contract lines are not yet saved at that point. Enforce them in an event subscriber at the point where the contract is released or confirmed.
Error vs warning:
- If releasing an over-limit contract would produce an operation the business considers invalid, raise an error so the transaction rolls back and there is no half-released document.
- If it is a policy that a supervisor may override, use a confirm dialog and record who overrode it. A confirm in an event subscriber that is not handled correctly can still let the base logic continue - verify the event's
IsHandledsemantics rather than assuming.
Judgment point: the same business rule may need error at release and warning at entry. Decide by whether a partial state is acceptable, and put each rule where it cannot be bypassed.