如何在DAO中高效定义嵌套关系的删除函数?
在Room DAO中实现嵌套关系的批量删除
方法一:利用Room外键级联删除(推荐)
这是最简洁高效的方式,让数据库自动处理关联数据的删除,不需要手动编写多步删除逻辑。
步骤1:修改实体类,添加外键与级联规则
给Exercise和TrainingSet实体添加外键约束,并设置onDelete = CASCADE,这样当父实体被删除时,关联的子实体也会自动被删除。
修改后的实体代码:
@Entity( tableName = "workouts" ) data class Workout( @PrimaryKey(autoGenerate = true) @ColumnInfo("workout_id") val workoutId: Long = 0, val name: String, @ColumnInfo(name = "set_count") val setsCount: Int, ) @Entity( tableName = "exercises", foreignKeys = [ ForeignKey( entity = Workout::class, parentColumns = ["workout_id"], childColumns = ["workout_id"], onDelete = ForeignKey.CASCADE // 删除Workout时自动删除关联的Exercise ) ] ) data class Exercise( @PrimaryKey(autoGenerate = true) @ColumnInfo("exercise_id") val exerciseId: Long = 0, @ColumnInfo("workout_id") val workoutId: Long, @ColumnInfo("exercise_name") val exerciseName: String ) @Entity( tableName = "training_sets", foreignKeys = [ ForeignKey( entity = Exercise::class, parentColumns = ["exercise_id"], childColumns = ["exercise_id"], onDelete = ForeignKey.CASCADE // 删除Exercise时自动删除关联的TrainingSet ) ] ) data class TrainingSet ( @PrimaryKey(autoGenerate = true) @ColumnInfo("training_set_id") val trainingSetId: Long = 0, @ColumnInfo("exercise_id") val exerciseId: Long, val weight: Int, val repetitions: Int ) // 嵌套关系类保持不变 data class ExerciseWithTrainingSets( @Embedded val exercise: Exercise, @Relation( parentColumn = "exercise_id", entityColumn = "exercise_id" ) val trainingSets: List<TrainingSet> ) data class WorkoutWithExercisesAndSets( @Embedded val workout: Workout, @Relation( entity = Exercise::class, parentColumn = "workout_id", entityColumn = "workout_id" ) val exercisesWithTrainingSets: List<ExerciseWithTrainingSets> )
步骤2:在DAO中定义单个删除方法
只需要删除目标Workout,数据库会自动级联删除所有关联的Exercise和TrainingSet:
@Dao interface WorkoutDao { // 删除指定Workout,级联删除关联的Exercise和TrainingSet @Delete suspend fun deleteWorkout(workout: Workout) // 或者通过ID删除 @Query("DELETE FROM workouts WHERE workout_id = :workoutId") suspend fun deleteWorkoutById(workoutId: Long) }
方法二:手动事务删除(适合无法修改实体的场景)
如果不能修改实体添加外键,可以通过Room的@Transaction注解,手动按顺序删除关联数据,确保操作的原子性(要么全部成功,要么全部回滚)。
在DAO中定义事务方法:
@Dao interface WorkoutDao { // 手动事务删除:先删最底层的TrainingSet,再删Exercise,最后删Workout @Transaction suspend fun deleteWorkoutWithRelations(workoutId: Long) { // 1. 删除该Workout下所有Exercise对应的TrainingSet deleteTrainingSetsByWorkoutId(workoutId) // 2. 删除该Workout下的所有Exercise deleteExercisesByWorkoutId(workoutId) // 3. 删除目标Workout deleteWorkoutById(workoutId) } // 辅助方法:通过WorkoutID删除关联的TrainingSet @Query("DELETE FROM training_sets WHERE exercise_id IN (SELECT exercise_id FROM exercises WHERE workout_id = :workoutId)") suspend fun deleteTrainingSetsByWorkoutId(workoutId: Long) // 辅助方法:通过WorkoutID删除关联的Exercise @Query("DELETE FROM exercises WHERE workout_id = :workoutId") suspend fun deleteExercisesByWorkoutId(workoutId: Long) // 辅助方法:通过ID删除Workout @Query("DELETE FROM workouts WHERE workout_id = :workoutId") suspend fun deleteWorkoutById(workoutId: Long) }
两种方法对比
- 级联删除:代码简洁,数据库层面自动处理,性能更优,推荐优先使用。需要注意添加外键后,数据库结构会有约束,确保数据一致性。
- 手动事务删除:无需修改实体,但需要手动编写多步删除逻辑,适合已有项目无法修改实体的场景,同样能保证操作的原子性。
内容的提问来源于stack exchange,提问作者Giuseppe D'arrò
相关产品推荐
相关产品推荐

