You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room数据库Kotlin中实现Cascade delete级联删除的方法

Room数据库实现删除用户时级联删除关联数据方案

实现级联删除需要对子表添加外键约束并配置级联规则,具体操作步骤如下:


步骤1:为关联子表添加带级联删除的外键约束

你不需要修改UserInfo实体类,只需要给所有关联子表(Transactions、LOANS表)的@Entity注解添加外键配置即可,以Transactions表为例:

// 导入依赖包
import androidx.room.ForeignKey
import androidx.room.ForeignKey.CASCADE

@Entity(
    tableName = "transactions",
    // 添加外键约束
    foreignKeys = [ForeignKey(
        entity = UserInfo::class,
        parentColumns = ["user_id"], // 父表(user_info)的关联字段名
        childColumns = ["user_id"], // 子表(transactions)的关联字段名
        onDelete = CASCADE // 父表数据删除时,同步删除对应子表数据
    )]
)
data class Transactions(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "trans_id")
    var transId: Long = 0L,
    // 建议把userId改为非空,避免出现无主的无效数据
    @ColumnInfo(name = "user_id")
    var userId: Long,
    // 其余原有属性保持不变
    @ColumnInfo(name = "create_date")
    var createDate: String?,
    @ColumnInfo(name = "bank_id")
    var bankId: Long?,
    @ColumnInfo(name = "description")
    var description: String?,
    @ColumnInfo(name = "increase")
    var increase: String?,
    @ColumnInfo(name = "decrease")
    var decrease: String?,
    @ColumnInfo(name = "loan_number")
    var loanNumber: String?,
    @ColumnInfo(name = "total")
    var total: Long?,
    @ColumnInfo(name = "type")
    var type: String?
)

LOANS表按照相同逻辑添加foreignKeys配置即可。


步骤2:处理数据库版本迁移

修改表结构后需要升级数据库版本,分两种场景处理:

开发阶段(可接受数据丢失)

直接在数据库构建代码中添加fallbackToDestructiveMigration,直接重建所有表:

Room.databaseBuilder(context, AppDatabase::class.java, "你的数据库名")
    .fallbackToDestructiveMigration()
    .build()

线上版本(需要保留用户数据)

编写迁移逻辑,重建子表并导入原有数据:

// 1、2替换为你实际的旧版本号和新版本号
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // 创建带外键约束的新transactions表
        database.execSQL("""
            CREATE TABLE IF NOT EXISTS `transactions_new` (
                `trans_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
                `user_id` INTEGER NOT NULL,
                `create_date` TEXT,
                `bank_id` INTEGER,
                `description` TEXT,
                `increase` TEXT,
                `decrease` TEXT,
                `loan_number` TEXT,
                `total` INTEGER,
                `type` TEXT,
                FOREIGN KEY(`user_id`) REFERENCES `user_info`(`user_id`) ON DELETE CASCADE
            )
        """.trimIndent())
        // 导入旧表数据到新表
        database.execSQL("""
            INSERT INTO transactions_new (trans_id, user_id, create_date, bank_id, description, increase, decrease, loan_number, total, type)
            SELECT trans_id, user_id, create_date, bank_id, description, increase, decrease, loan_number, total, type FROM transactions
            WHERE user_id IS NOT NULL
        """.trimIndent())
        // 删除旧表,重命名新表
        database.execSQL("DROP TABLE transactions")
        database.execSQL("ALTER TABLE transactions_new RENAME TO transactions")
        // 如果有LOANS表,按照相同逻辑处理LOANS表的迁移
    }
}

// 把迁移逻辑添加到数据库构建器
Room.databaseBuilder(context, AppDatabase::class.java, "你的数据库名")
    .addMigrations(MIGRATION_1_2)
    .build()

步骤3:验证删除逻辑

你原有DAO中的deleteUser方法不需要做任何修改,调用该方法删除用户时,Room会自动删除该用户关联的所有Transactions、LOANS记录。如果需要按用户ID直接删除,也可以新增如下查询,同样会触发级联删除:

@Query("DELETE FROM user_info WHERE user_id = :userId")
suspend fun deleteUserById(userId: Long)

注意事项

  • 外键的parentColumns和childColumns字段数据类型必须完全一致,否则约束不生效
  • 避免配置循环级联规则,防止出现意外的批量数据删除
  • 如果后续不需要级联删除,把onDelete的值改为NO_ACTION或者RESTRICT即可

内容的提问来源于stack exchange,提问作者AmirHossein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 18:24:10