How to define a "Has Many" reference between models
Please refer to here for general information about models.
If you define a "Has Many" reference between models, you are creating a Master/Detail relationship. You have to operate in both master and detail models:
- Master model: define the
DetailReferencesnode listing detail references - Detail model: define a reference field that points back to the master model.
Example from TasKitto:
# model PROJECT.yaml
ModelName: PROJECT
Fields:
PROJECT_ID: String(32) not null primary key
IsVisible: False
DefaultValue: %COMPACT_GUID%
PROJECT_NAME: String(40) not null
CUSTOMER: Reference(CUSTOMER) not null
Fields:
CUSTOMER_ID:
STATUS: String(12)
AllowedValues:
Offered: Offered
Open: Open
Stopped: Stopped
Terminated: Terminated
DetailReferences:
PHASE: PHASE
# model PHASE.yaml
ModelName: PHASE
Fields:
PHASE_ID: String(32) not null primary key
IsVisible: False
DefaultValue: %COMPACT_GUID%
PHASE_NAME: String(40) not null
PROJECT: Reference(PROJECT) not null
Fields:
PROJECT_ID:
START_DATE: Date
END_DATE: Date
STATUS: String(12)
AllowedValues:
Started: Started
Finished: Finished
Invoiced: Invoiced
Killed: Killed
Waiting: WaitingField names, column names and the order of the key
The Model above uses the same identifier for the field and for the column, which is the common case when the schema was designed for Kittox. It is not a requirement: a Model imported from an existing database usually looks like this, with beautified field names and a prefixed foreign key column in the detail.
# model Palazzi.yaml (master)
Fields:
PalId: Integer not null primary key
PhysicalName: PAL_ID
# model Uffici.yaml (detail)
Fields:
UffPal: Reference(Palazzi) not null
PhysicalName: UFF_PAL_FK
Fields:
UffPalId:
PhysicalName: UFF_PAL_IDBoth work, and you do not need to rename the master key field to match its column.
Two rules are worth knowing when you write this metadata by hand:
- The reference in the detail must carry the
Fields:sub-node naming the local foreign key column.Reference(Palazzi)alone says which Model is pointed at, not which column holds the link, and a detail can legitimately point at the same master more than once. - Master and detail are paired by position: key field i of the master corresponds to sub-field i of the reference. With a single-column key there is nothing to get wrong; with a composite key, declare the sub-fields in the same order as the master's key fields, or the grid will show the rows of a different master record. The Model Wizard writes the right order, and keeps it aligned when the database changes: re-running Update models reorders both the master's key and the reference's sub-fields to follow the primary key and the foreign key as the database declares them.
The DetailReferences entry on the master carries no key information: it declares that the relationship is navigated as a grid, and the pairing is derived from the reference in the detail. ReferenceField: is only needed when the detail points at the master more than once.
Deleting the master
By default the master cannot be deleted while details refer to it: the database refuses on the foreign key, and the application reports it by naming the record and counting what holds it back, for instance Project "Conferest Kitto3" cannot be deleted: 2 Phases still refer to it.
To have the details go with it, say so on the relationship — as a subnode of the detail reference, one level in:
# model PROJECT.yaml (master)
DetailReferences:
PHASE: PHASE
CascadeDelete: TrueThe details are then deleted first, inside the master's own transaction, so either the whole delete happens or none of it does. It applies per relationship, so two details of the same master can behave differently, and it nests: a detail's own details go before it, deepest first.
It is off unless asked for. On by default, a single delete would take an unknown number of rows with it in every application without anyone having decided that.
Note that the cascade follows the detail tables the view declares. A relationship the view does not mention is not deleted, and the database refuses as before — with the readable message rather than a constraint name.
Rendering master/detail in views
To display the master/detail relationship in the UI, define the MainTable/DetailTables node in the view:
# view Projects.yaml
Type: Data
Controller: List
MainTable:
Model: PROJECT
DetailTables:
Table:
Model: PHASE
Controller:
Form:
Layout: Phases_FormWhen editing a master record, detail tables appear as additional tabs in the form dialog, merged into the same tab bar as any PageBreak tabs from the form layout. For example, if the Project form layout has no page breaks, the tab bar shows [Project | Phases].
The detail grid has its own CRUD toolbar (Add, Edit, Delete) and supports double-click to open the detail record form.
Auto-built vs. explicit views
By default, when you specify only Model: PHASE, Kittox auto-builds a list view with a standard grid, toolbar, and search filter. If you need more control over the detail's columns, filters, or toolbar, you can reference an explicit view:
DetailTables:
Table:
ViewName: PhasesFK field handling
When a detail form is opened from the master, the foreign key field (e.g., PROJECT in a PHASE record) is automatically:
- Read-only in all modes (edit, view, add) — the user cannot change the master link.
- Pre-filled when adding a new record — set to the current master record's key.
Nested details
Detail tables can themselves have detail tables:
# view Customers.yaml
MainTable:
Model: CUSTOMER
DetailTables:
Table:
Model: PROJECT
DetailTables:
Table:
Model: PHASE
Controller:
Form:
Layout: Phases_Form
Controller:
PreventAdding: False
PreventDeleting: False
AllowDuplicating: TrueIn this example, editing a Customer shows a PROJECT tab; editing a Project shows a PHASE tab.
Custom form layout for details
You can specify a form layout for the detail record dialog:
DetailTables:
Table:
Model: PHASE
Controller:
Form:
Layout: Phases_FormThe layout file (e.g., Phases_Form.yaml under Metadata/Views/Layouts/) controls which fields appear and how they are arranged:
# Phases_Form.yaml
Row:
Field: PROJECT
CharWidth: 40
Field: PHASE_NAME
Row:
Field: START_DATE
Field: END_DATE
Field: STATUSSee Form for full details on form layouts and the master/detail feature.
