Creating a dictionary
:::info Status
Outline — expand into a full step-by-step walkthrough with a real worked example (e.g. adding
a new flat dictionary and a new hierarchical dictionary to KandraWms).
:::
:::tip Use the shipped skill
If you're working in a scaffolded configuration with Claude Code, prefer invoking the
create-dictionary skill (ships in your repo's .claude/skills/) over hand-rolling the four
pieces below — it does the mechanical work for you, flat or hierarchical. Turning an
existing flat dictionary into a hierarchical one later, without losing its data, is a
separate skill: convert-dictionary-to-hierarchical. This page is the conceptual background
the skill assumes.
:::
A Dictionary is reference/master data with no posting behavior: items, warehouses, counterparties, price types. There are two shapes:
- Flat — a plain list (e.g.
Counterparty). - Hierarchical — supports a folder/parent structure (e.g. an
ItemNodetree). Hierarchy is opt-in per dictionary, not a separate base type family.
The four pieces
(Named here after KandraWms, the platform team's own reference configuration — in your own
scaffolded repo these are Acme.Domain/Acme.Forms/Acme.Application, whatever -n you
scaffolded with.)
*Base : DictionaryBaseinKandraWms.Domain,[KandraDictionaryEntity].*DtoinKandraWms.Forms,[KandraDictionaryForm(ValidatorType=...)], redeclaringCode/Nameasoverride.*BehaviorinKandraWms.Application(OnNewAsync/OnOpenAsync/OnBeforeSaveAsync/OnSaveAsync— dictionaries have no submit/unsubmit).*ValidatorinKandraWms.Forms, mandatory even if it only callsbase.Validate(...).
What the generators give you for free
Controller, client DI (Refit client + service wrapper), EF Core IEntityTypeConfiguration<T>,
DI registration blocks, Equals/GetHashCode/ToString. See
Source Generators for which generator does which.
Gotchas worth knowing before you start
[Search]/[Dropdown]on a hierarchical dictionary field must target the abstract root Dto, not the leaf subclass — pointing at a leaf silently drops the field from the generated UI, and referencing the root doesn't loosen the node-selection default (still leaf-only unless you say otherwise).- Computed get-only properties are excluded from field discovery — if a property needs to show up in the generated UI, it needs a real backing setter path, not just a getter.
See also
- Register transactions viewer if this dictionary participates in posting as a subconto dimension.
- Reference: Entities and Reference: DTOs & Validators.