级联删除策略
本文将指导您如何配置级联删除策略。
级联删除策略
使用 @Cascade 的 onDelete 参数,可以决定删除根记录时如何处理关联记录。完整删除流程见 📚级联删除。
| 名称 | 说明 | 类型 |
|---|---|---|
NO_ACTION | 不创建额外的子记录 delete 或 update 任务,默认使用该策略。 | CascadeDeleteAction |
CASCADE | 先删除匹配的子记录,再删除根记录。 | CascadeDeleteAction |
RESTRICT | 存在匹配子记录时拒绝删除。 | CascadeDeleteAction |
SET_NULL | 先将子记录引用列设置为null,再删除根记录。 | CascadeDeleteAction |
SET_DEFAULT | 先将子记录引用列设置为defaultValue中的值,再删除根记录。 | CascadeDeleteAction |
声明删除策略
子表引用属性上声明 onDelete = CascadeDeleteAction.CASCADE,表示删除父记录时同步删除子记录。
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
Kronos 先查询根记录,再查询匹配的子记录,随后先删除子记录,最后删除根记录。使用 SET_NULL
子记录需要保留但不再指向被删除的根记录时,使用 SET_NULL。
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
子记录会保留。删除父记录前,dept_id 参数会被更新为 null。使用 SET_DEFAULT
子记录引用需要改为指定值时,使用 SET_DEFAULT 并设置 defaultValue。
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
删除 dept 前,Kronos 会把匹配 user.deptId 更新为 "0"。多列引用中,properties、targetProperties 和 defaultValue 需要保持相同顺序。不希望修改某个列时,使用 Cascade.RESERVED。
reserved
@Cascade(
["deptId", "tenantId"],
["id", "tenantId"],
onDelete = CascadeDeleteAction.SET_DEFAULT,
defaultValue = [Cascade.RESERVED, "0"]
)
var dept: Dept? = null使用 RESTRICT
只有关联记录已经被删除或解除关联后才允许删除父记录时,使用 RESTRICT。
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_ACTION只表示 Kronos 不为该关系创建额外的子表任务。数据库外键约束仍按数据库表结构自身的规则生效。