Cascading Deletion Action
This chapter will guide you on how to configure a cascade deletion action in Kronos.
Cascade delete action
Use the onDelete parameter of @Cascade to decide what happens to related records when the root record is deleted. The full delete workflow is described in 📚Cascade Delete.
| name | description | type |
|---|---|---|
NO_ACTION | Do not create a child delete or update task. This is the default. | CascadeDeleteAction |
CASCADE | Delete matching child records before deleting the root record. | CascadeDeleteAction |
RESTRICT | Reject the delete when matching child records exist. | CascadeDeleteAction |
SET_NULL | Set the child reference columns to null before deleting the root record. | CascadeDeleteAction |
SET_DEFAULT | Set the child reference columns to values from defaultValue before deleting the root record. | CascadeDeleteAction |
Declare a delete action
Put onDelete = CascadeDeleteAction.CASCADE on the child-side reference when the child rows should be removed with the parent.
kotlin
@Table("dept")
data class Dept(
@PrimaryKey
var id: Int? = null,
var users: List<User> = listOf()
) : KPojo
@Table("user")
data class User(
@PrimaryKey
var id: Int? = null,
var deptId: Int? = null,
@Cascade(["deptId"], ["id"], onDelete = CascadeDeleteAction.CASCADE)
var dept: Dept? = null
) : KPojo
Dept(id = 7).delete().by { it.id }.execute()mysql
SELECT `id` FROM `dept` WHERE `id` = :id;
SELECT `id`, `dept_id` AS `deptId` FROM `user` WHERE `dept_id` = :deptId;
DELETE FROM `user` WHERE `id` = :id AND `dept_id` = :deptId;
DELETE FROM `dept` WHERE `id` = :id;Result shape:
result
Kronos queries the root row, queries matching child rows, deletes child rows first, then deletes the root row.Use SET_NULL
Use SET_NULL when child rows should stay in the database but stop pointing to the deleted root record.
kotlin
@Table("dept")
data class Dept(
@PrimaryKey
var id: Int? = null,
var users: List<User> = listOf()
) : KPojo
@Table("user")
data class User(
@PrimaryKey
var id: Int? = null,
var deptId: Int? = null,
@Cascade(["deptId"], ["id"], onDelete = CascadeDeleteAction.SET_NULL)
var dept: Dept? = null
) : KPojo
Dept(id = 7).delete().by { it.id }.execute()mysql
UPDATE `user`
SET `dept_id` = :deptIdNew
WHERE `id` = :id AND `dept_id` = :deptId;
DELETE FROM `dept` WHERE `id` = :id;Result shape:
result
The child row remains. Its dept_id parameter is updated to null before the parent delete runs.Use SET_DEFAULT
Use SET_DEFAULT with defaultValue when a child reference should be moved to a known value.
kotlin
@Table("dept")
data class Dept(
@PrimaryKey
var id: Int? = null,
var users: List<User> = listOf()
) : KPojo
@Table("user")
data class User(
@PrimaryKey
var id: Int? = null,
var deptId: Int? = null,
@Cascade(["deptId"], ["id"], onDelete = CascadeDeleteAction.SET_DEFAULT, defaultValue = ["0"])
var dept: Dept? = null
) : KPojo
Dept(id = 7).delete().by { it.id }.execute()mysql
UPDATE `user`
SET `dept_id` = :deptIdNew
WHERE `id` = :id AND `dept_id` = :deptId;
DELETE FROM `dept` WHERE `id` = :id;result
Before deleting dept, Kronos updates matching user.deptId to "0".For multi-column references, keep properties, targetProperties, and defaultValue in the same order. Use Cascade.RESERVED for a column that should keep its current value.
reserved
@Cascade(
["deptId", "tenantId"],
["id", "tenantId"],
onDelete = CascadeDeleteAction.SET_DEFAULT,
defaultValue = [Cascade.RESERVED, "0"]
)
var dept: Dept? = nullUse RESTRICT
Use RESTRICT when the parent can be deleted only after related rows are removed or detached.
kotlin
@Cascade(["deptId"], ["id"], onDelete = CascadeDeleteAction.RESTRICT)
var dept: Dept? = null
Dept(id = 7).delete().by { it.id }.execute()result
UnsupportedOperationException: The record cannot be deleted because it is restricted by a cascade.
NO_ACTIONonly means Kronos does not create an extra child task for that relationship. Database foreign-key constraints still behave according to the database schema.