Dictionary — dictionary
Updated
What it is#
Master data: an entity with an independent life cycle (it is created, edited, and referenced by documents and registers). It may be hierarchical (isHierarchical; then the server creates the ParentId field itself). It may be isSingleton — exactly one record per tenant, usually for "module settings" (InventorySettings, CommonSettings, and so on).
JSON envelope#
Pair of files: <Name>.object.json (design) + Events/<Name>EventHandler.script.json + Events/<Name>EventHandler.cs (event code).
<Name>.object.json, "kind": "Dictionary":
{
"kind": "Dictionary",
"object": {
"caption": { "en": "Countries", "ru": "Страны", "uk": "Країни" },
"isHierarchical": false,
"isSingleton": false,
"isVersioned": false,
"isCached": false,
"numberSequenceMetaId": "<GUID NumberSequence>",
"defaultSearchProperty": "Name",
"displayFormat": "{Name} - ({CodeISO2})",
"metaId": "<GUID Dictionary>",
"name": "Country",
"modelId": "<GUID Model>"
},
"fields": [
{
"dictionaryMetaId": "<GUID Dictionary>",
"fieldName": "CodeISO2",
"baseType": "String", "length": 2,
"isRequired": false, "displayOrder": 2, "isVisible": true,
"caption": { "en": "ISO2 code", "ru": "Код ISO2" },
"metaId": "<GUID Field>", "name": "CodeISO2", "modelId": "<GUID Model>"
},
{
"dictionaryMetaId": "<GUID Dictionary>",
"fieldName": "Currency",
"edtMetaId": "<GUID EDT Reference>",
"isRequired": false, "displayOrder": 5, "isVisible": true,
"caption": { "en": "Currency", "ru": "Валюта" },
"metaId": "<GUID Field>", "name": "Currency", "modelId": "<GUID Model>"
}
]
}
A field is either scalar (baseType + length/precision/scale) or a reference (edtMetaId to a Reference EDT — see EDT); there is no third option (EDT-first, see the root CLAUDE.md). The server creates ID itself on import (and a number sequence for it if you do not declare your own). You do not need to write this field; it appears in the file after the first export from the database.
C# base#
<Name>EventHandler : TypedDictionaryEventHandler<Name> — the base is declared manually (the first chain link, does not call next). A typed record (record.SomeField) arrives in every hook.
Events / Chain of Command#
The full set of life-cycle hooks: OnBeforeCreateAsync, OnBeforeSaveAsync/OnAfterSaveAsync (any save), operational OnBefore/AfterInsert/UpdateAsync (an override is used instead of the Before/AfterSave call for this operation), OnBeforeDeleteAsync/OnAfterDeleteAsync, OnBeforeCloneAsync, OnAfterLoadAsync, OnValidateFieldAsync, OnSaveFailedAsync/OnDeleteFailedAsync (replacing a raw database error with friendly text). Extension from another model uses [ExtensionOf("Country")] on the class + next(...) in every override, with the suffix Ext<Model>EventHandler.
Example#
Country in Common — no hierarchy, reference to Currency; a settings singleton dictionary is InventorySettings in Inventory.