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
相关产品推荐
相关产品推荐

