Create a link table
Updated
A link table is an M:N set of rows between records. Files live in
LinkTables/ of your model. The physical table is LT_{Name}. The
generated class is LT_{Name}. Kind:
Link table.
Note
A link table is not a child list. If one side owns the other and cascade delete is required, use a dictionary list or a document table part.
How to#
1. The file — LinkTables/<Name>.json, kind: "LinkTable". A new GUID
in metaId. modelId is your model's. Names are PascalCase Latin.
tableName is LT_{Name}.
Each side is a property with isReference: true, referenceKind: "Dictionary" (or a document), and referenceMetaId of the target. Extra
columns are scalars (baseType plus length / precision+scale). One
fieldName once.
isPrimaryKey on a reference keeps the card tab on that side only:
PriceTypeHistory hangs off the item, not the price type.
Dated intervals with a closed window (EffectiveFrom / EffectiveTo) live
here — PriceTypeHistory in Inventory is the worked example. An
information register is a slice: the
last value continues until a later Period.
A simple M:N with no window is CountryCurrency in Common (Country,
Currency, IsPrimary).
2. Use it from a script — GetService<ILinkTableManager>(). By name:
AddAsync / EnsureAsync / GetAsync / DeleteAsync. Typed over the
generated row class:
var links = GetService<ILinkTableManager>();
var outlets = await links.GetRecordsAsync<LT_SalesContractOutlet>(
"SalesContract", contractId);
await links.ReplaceRecordsAsync("SalesContract", contractId, rows);
await links.SaveRecordAsync(new LT_PriceTypeHistory
{
Item = itemId,
PriceType = typeId,
Unit = unitId,
Price = price,
EffectiveFrom = from,
});
ReplaceRecordsAsync makes that side exactly the given set: rows of
(keyField = keyValue) missing from the set are deleted.
A data package can ship link-table rows
(kind: LinkTable, key = the reference pair).
3. Bump modelVersion in the same change.
Warning
ReplaceRecordsAsyncdeletes every row of that side that you did not pass. Build the full set, then replace.EnsureAsyncis the idempotent add: it returns the existing row when one already matches all the given values.
The dictionary card shows the link table whose column points at it. There is no menu item: the user opens the tab on the card.
What's not there yet#
There is no catalog card in Reference that lists every LT_ table. Look in
LinkTables/ of the model. A link table is not a totals register and not a
slice.