Cascade Delete

This article will guide you on how to use the cascade delete feature in Kronos.

Cascade delete strategy

@Cascade annotations support setting strategies for cascading delete operations, please refer to:📚Cascade delete strategy。

Setting Default Values

When using the SET_DEFAULT strategy, you need to specify the defaultValue attribute in the annotation

defaultValue accepts a string array, such as ["a", "b"], corresponding to the default values of multiple reference columns of the associated entity

Please ensure that the lengths of defaultValue, properties, and targetProperties arrays are consistent

If a reference column does not need to be modified, you can set it to RESERVED. Kronos will ignore the reference column when the cascade delete is set to SET_DEFAULT, such as:

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
)

Logical deletion

If the top-level delete function uses the logical delete function, and if the cascade delete strategy of the cascade delete sub-level is CASCADE, then logical delete will also be used when deleting the child table data.

Partially enable or disable cascade delete

Turn off cascading delete

Kronos enables the cascading delete function by default, which needs to be explicitly turned off in the delete function:

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

Partially enable cascade delete

When there are multiple cascade declarations in KPojo, but only some of them need to be deleted by cascade, the attributes that need to be deleted by cascade can be passed into the cascade function, and the remaining attributes and sub-attributes will not trigger cascade deletion.

// If only property1 and property2 in KPojo need to be cascaded deleted, then it is as follows:
KPojo.delete().cascade { [KPojo::property1, KPojo::property2] }.execute()

You can limit the cascade deletion of its sub-attributes as follows:

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

1. One-to-one cascading relationship

This section describes how to use cascade delete for a pair of cascade relationships defined in Kronos.

Data class definition

We define two entity classes, User and Profile. The User entity class contains a reference to the Profile entity class, and the Profile entity class contains a reference to the User entity class.

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
)

Cascade delete

Deleting a User or Profile entity will trigger a cascade delete

User(id = 1).delete().by { it.id }.execute()
// This will delete all User records with id=1 and all Profile records with userId=1

Or:

Profile(id = 1).delete().by { it.id }.execute()
// This will delete all Profile records with id=1 and all User records with userId=1

2. One-to-many cascading relationship

The usage of one-to-many relationships is similar to that of one-to-one relationships.

Data class definition

First, we define the following two entity classes, Parent and Child. The Parent entity class contains a collection of Child entity classes, and the Child entity class contains a reference to the Parent entity class.

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
)

Cascade delete

Use the KPojo.delete() method to implement cascading deletion of one-to-many cascading relationships.

In Kronos, only cascading deletion in the Parent -> Child direction is supported. When deleting, the Child is deleted first, then the Parent. If any level of the multi-level relationship has a Restrict cascading deletion policy, the deletion will not be triggered.

Parent(id = 1).delete().by { it.id }.execute()
// This will delete the Parent record with id 1 and also delete the Child record with parentId 1.

Here is a more complex example with more layers:

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()
// This will cascade delete all GroupClass and Student records with name="school"

3. Many-to-many cascading relationships

Through the manyToMany delegation, Kronos simplifies many-to-many relationships into one-to-many relationships and automatically creates association table records for you. For details, see: 📚cascade relationship definition - Using delegation to implement cascading many-to-many relationships across intermediate tables.

Data class definition

First, we define three entity classes: User, Role, and Relation. The Relation entity class contains references to the User and Role entity classes. User and Role are associated through manyToMany delegation.

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
)

Cascade delete

Deleting a User or Role entity can perform cascade deletion. According to the cascade deletion strategy defined by the annotation, the cascade deletion will automatically delete the associated table records.

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

Or:

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