级联删除

本文将指导您如何使用Kronos的级联删除功能。

级联删除策略

@Cascade注解支持设置级联删除操作的策略,请参考:📚级联删除策略。

设置默认值

使用SET_DEFAULT策略时,需要在注解中指定defaultValue属性

defaultValue接受一个字符串数组,如["a", "b"],对应关联实体的多个引用列的默认值

请保证defaultValue、properties、targetProperties数组长度一致

若其中的某个引用列不需要修改,可以通过将其设置为RESERVED,Kronos在级联删除设置为SET_DEFAULT时会忽略该引用列,如:

data class Child(
    var parentId: Long? = null,
    var parentName: String? = null,
    @Cascade(
        ["parentId", "parentName"],
        ["id", "name"],
        onDelete = CascadeDeleteAction.SET_DEFAULT,
        defaultValue = [Cascade.RESERVED, "empty"]
    )
    var parent: Parent? = null
)

逻辑删除

若顶层的删除函数使用了逻辑删除功能,若级联删除子层级的级联删除策略为CASCADE,那么删除子表数据时也会使用逻辑删除。

部分开启及关闭级联删除

关闭级联删除

Kronos默认开启级联删除功能,需要在delete函数中显式关闭:

KPojo.delete().cascade(enabled = false).execute()

部分开启级联删除

当KPojo中有多个级联声明,但只有部分需要级联删除时,可以将需要级联删除的属性传入cascade函数,其余的属性及子属性将不触发级联删除。

// 若KPojo中只有property1和property2需要级联删除,那么如下:
KPojo.delete().cascade { [KPojo::property1, KPojo::property2] }.execute()

可以限制其子属性级联删除,如下:

KPojo.delete()
    .cascade {
        [
            KPojo::property1,
            KPojo::property2,
            Property1::subProperty1,
            Property1::subProperty2
        ]
    }
    .execute()

1. 一对一级联关系

本节将介绍如何使用Kronos中定义的一对一级联关系的级联删除。

数据类定义

我们定义User和Profile两个实体类,User实体类中包含了一个Profile实体类的引用,Profile实体类中包含了一个User 实体类的引用。

User.kt

data class User(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var profileId: Long? = null,
    @Cascade(["profileId"], ["id"], CASCADE)
    var profile: Profile? = null
)

Profile.kt

data class Profile(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var userId: Long? = null,
    @Cascade(["userId"], ["id"], CASCADE)
    var user: User? = null
)

级联删除

删除User或Profile实体都会触发级联删除

User(id = 1).delete().by { it.id }.execute()
// 这将删除所有id=1的User记录和所有userId=1的Profile记录

或者:

Profile(id = 1).delete().by { it.id }.execute()
// 这将删除所有id=1的Profile记录和所有userId=1的User记录

2. 一对多级联关系

一对多关系和一对一关系的用法类似。

数据类定义

首先,我们定义以下的Parent和Child两个实体类,Parent实体类中包含了一个Child实体类的集合,Child实体类中包含了一个 Parent实体类的引用。

Parent.kt

data class Parent(
    @PrimaryKey(identity = true)
    var id: Long? = null,
    var name: String? = null,
    var children: List<Child> = listOf()
)

Child.kt

data class Child(
    @PrimaryKey(identity = true)
    var id: Long? = null,
    var name: String? = null,
    var parentId: Long? = null,
    @Cascade(["parentId"], ["id"], CASCADE)
    var parent: Parent? = null
)

级联删除

使用KPojo.delete()方法,可以实现一对多级联关系的级联删除。

在Kronos中,仅支持Parent -> Child方向的级联删除,删除时先删除Child,再删除Parent,若多层级的任意一层级的关系存在Restrict级联删除策略,则不触发删除。

Parent(id = 1).delete().by { it.id }.execute()
// 这会删除id为1的Parent记录,同时删除parentId为1的Child记录

以下是一个更加复杂的、层级更深的例子:

School.kt

data class School(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var groupClasses: List<GroupClass> = listOf()
)

GroupClass.kt

data class GroupClass(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var schoolId: Long? = null,
    @Cascade(["schoolId"], ["id"], CASCADE)
    var school: School? = null,
    var students: List<Student> = listOf()
)

Student.kt

data class Student(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var groupClassId: Long? = null,
    var schoolId: Long? = null,
    @Cascade(["groupClassId", "schoolId"], ["id", "schoolId"], CASCADE)
    var groupClass: GroupClass? = null
)
School(name = "school").delete().by { it.name }.execute()
// 这会级联删除所有name="school"的GroupClass和Student记录

3. 多对多级联关系

通过manyToMany委托,Kronos简化多对多关系为一对多关系,并为您自动创建关联表记录,详见:📚级联关系定义 - 使用委托实现级联多对多跨中间表关系。

数据类定义

首先我们定义User、Role、Relation三个实体类,其中Relation实体类中包含了User和Role两个实体类的引用,User和Role 通过manyToMany委托关联。

User.kt

data class User(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var relations: List<Relation> = listOf()
) {
    var roles: List<Role> by manyToMany(::relations)
}

Role.kt

data class Role(
    @PrimaryKey
    var id: Long? = null,
    var name: String? = null,
    var relations: List<Relation> = listOf()
) {
    var users: List<User> by manyToMany(::relations)
}

Relation.kt

data class Relation(
    @PrimaryKey
    var id: Long? = null,
    var userId: Long? = null,
    var roleId: Long? = null,
    @Cascade(["userId", "roleId"], ["id", "id"])
    var user: User? = null,
    @Cascade(["userId", "roleId"], ["id", "id"])
    var role: Role? = null
)

级联删除

删除User或Role实体都可以进行级联删除,根据注解定义的级联删除策略,级联删除会自动删除关联表记录。

User(name = "user")
    .apply { roles = listOf(Role(name = "role")) }
    .delete().by { it.name }.execute()

或者:

Role(name = "role")
    .apply { users = listOf(User(name = "user")) }
    .delete().by { it.name }.execute()