0169

Import in the Right Order

Algorithm
Medium
list
graph
rapidstart

Import in the Right Order

Your team applies a RapidStart configuration package to every new company, and it keeps blowing up halfway through: Customer lines fail because their Payment Terms are not in yet, Items fail on missing Item Categories, and someone reorders the package tables by hand until it sticks. You are building the planner that computes a correct apply order once and for all.

Requirements

Create a codeunit named "Import Order Planner" with exactly these three public procedures:

procedure AddTable(TableID: Integer)
procedure AddDependency(TableID: Integer; DependsOnTableID: Integer)
procedure GetImportOrder(var ImportOrder: List of [Integer])

AddTable stages a table for import. Staging the same table ID again has no further effect.

AddDependency records that the records of TableID reference records of DependsOnTableID (a foreign key), so DependsOnTableID must be imported before TableID. Registering the same pair again has no further effect. By the time GetImportOrder is called, every table ID mentioned in a dependency pair has also been staged with AddTable — you do not need to handle unknown tables.

A pair where TableID = DependsOnTableID is legal — think of Item Category's Parent Category field — and imposes no ordering constraint: a table never waits for itself.

GetImportOrder first empties whatever is in ImportOrder, then fills it with every staged table exactly once, so that:

  1. For every dependency pair, DependsOnTableID appears before TableID.
  2. Whenever more than one staged table could legally come next, the one with the lowest table ID comes first. This makes the order fully deterministic.
  3. With no tables staged, the result is an empty list.

If at some point no remaining table can legally come next — a circular dependency — GetImportOrder must fail with exactly this error message:

No valid import order exists. Tables that cannot be imported: 50111, 50113, 50115.

The list after the colon names every staged table that can never be imported — the tables in a cycle plus every table whose dependency chain leads into one — in ascending table ID order, separated by a comma and one space, with a period at the end. Tables unaffected by the cycle must not appear in the list.

State lives in your codeunit's instance variables; each grading test uses a fresh planner variable, so no reset procedure is needed. The planner works on plain integers — do not create or read any database tables.

What the tests check

The tests stage small dependency graphs and compare the full order returned by GetImportOrder, element for element: a single table, independent tables (must come out in ascending table ID order), a parent staged after its child, a case where the lowest-ID table must wait while higher-ID tables go first, a self-referencing table, and duplicate AddTable/AddDependency calls (each table exactly once). One test builds a dependency chain over randomly generated table IDs, so hardcoding the fixed examples fails. Two tests build cycles and compare the error message exactly — including that a table stuck behind a cycle is named and an importable table is not. One test passes a non-empty list to GetImportOrder with nothing staged and expects it to come back empty.

Pick object IDs in the 50100–50199 range, and reference other objects by name, never by ID.

Learn More

Hint 1
Think of the staged tables as a to-do list: a table is ready to import once every table it depends on is already in the order. A self-reference never counts — a table cannot wait for itself.
Hint 2
Build the order one table at a time: scan the not-yet-placed tables for ready ones, take the lowest table ID among them, and repeat. If a scan finds no ready table while tables remain, the remaining set is exactly what the error message must name.
Hint 3
Keep staged tables in a List of [Integer] and each dependency pair as child/parent entries you can scan per table. Each round: a table is ready when every pair naming it as child has its parent already placed (or parent = child); append the smallest ready ID and remove it from the remaining set. On a stuck round, sort the remaining IDs ascending, join them with ', ', and raise the exact one-line error from the statement via a %1 placeholder.
ALBusiness Central 28.4
Press Compile to check your code compiles — Submit runs the tests.
The code editor is desktop-only
Open this problem on a computer to write and run code. Reading the description, tests and discussion works fine here.