Cascade policies¶
Nested fields use Map.nested(..., cascade=...) to define what happens on save().
Policies¶
| Policy | On save | Use when |
|---|---|---|
link (default) |
Updates parent FK only; nested row must already exist | Shared reference data (many people → same org) |
upsert |
Insert or update nested row; set parent FK | Owned nested data, shared updates OK |
replace |
Delete old nested row when association changes; then upsert new; on root delete(), removes exclusive nested rows |
Sole ownership of nested row |
ignore |
Skip nested persistence | Read-only or externally managed nested |
Always set fk_column= when cascade is not ignore.
Example: link (default)¶
employer = Map.nested(
Organization,
join=PersonRow.org_id == OrgRow.id,
nested_map=OrganizationMap,
property="schema:worksFor",
fk_column=PersonRow.org_id,
cascade=CascadePolicy.LINK,
)
Saving a Person with employer=Organization(id=10, ...) sets people.org_id = 10. The org row must exist.
Example: replace¶
employer = Map.nested(
Organization,
...,
cascade=CascadePolicy.REPLACE,
fk_column=PersonRow.org_id,
)
When the employer changes from org 10 to org 20, OntoSQL deletes org 10 only if no other parent row still references it. Otherwise ExecuteError is raised.
Do not use REPLACE for nested rows shared across multiple parents — use LINK or IGNORE.
Execution order (replace)¶
On REPLACE with FK change:
- Parent FK is nulled
- Old nested row is deleted (if exclusively owned)
- New nested row is upserted
- Parent FK is updated
Delete behavior¶
delete() always removes the root mapped row. With CascadePolicy.REPLACE, exclusive nested rows and collection member rows (when no other parent references them) are deleted in the same transaction. link and upsert do not delete nested rows on root delete — use database ON DELETE rules or explicit cleanup if needed.