Android Room多层嵌套关联实现及no such column报错修复
问题原因
报错的核心是@Relation关联配置存在链路断层:
- 你需要实现的层级关系为:
Training → 关联多个Exercise → 每个Exercise关联多个Set → 每个Set关联对应SetType - 原代码在
TrainingWithExerciseWithSets中配置@Relation时直接指定entity = Set::class,意味着Room会从set_table表读取全量字段来映射返回值。但返回值类型是List<ExerciseWithSets>,该类型依赖的exerciseName等字段存储在exercise_table中,set_table没有对应列,查询时就会触发no such column的报错。 - 原配置的本质问题是跳过了Exercise层级,直接让Room从Set表读数据硬映射为Exercise类型的对象,根本无法拿到Exercise表存储的字段。
修复方法
由于Set表同时持有trainingId和exerciseId两个外键,是连接Training和Exercise的天然中间表,可以通过Room提供的Junction桥接能力打通正确的关联链路,无需改动原有ExerciseWithSets、SetAndSetType的正确配置:
- 调整
TrainingWithExerciseWithSets的@Relation参数,将关联目标改为Exercise实体,通过Junction指定桥接的Set表,正确映射两边的关联列
修改后的代码如下:
@Parcelize data class TrainingWithExerciseWithSets( @Embedded val training: Training, @Relation( parentColumn = "trainingId", // Training实体的主键 entityColumn = "exerciseId", // Exercise实体的主键 associateBy = Junction( value = Set::class, // 作为桥接的中间表实体 parentColumn = "trainingId", // 桥接表中关联Training的列 entityColumn = "exerciseId" // 桥接表中关联Exercise的列 ) ) val exercises: List<ExerciseWithSets> ) : Parcelable
配套排查点
- 修改完成后Room生成的查询逻辑会按层级递归执行:先查询当前Training的基础信息 → 遍历Set表匹配和当前Training关联的所有不重复ExerciseId → 查询Exercise表拿到包括
exerciseName在内的完整Exercise数据 → 对每个Exercise递归解析嵌套关联,拿到对应的Set列表、每个Set关联的SetType信息,不会再出现列不存在的问题 - 建议将Room数据库版本号自增1,避免旧版本数据库结构、错误生成的查询逻辑残留引发二次报错
内容的提问来源于stack exchange,提问作者Octane
相关产品推荐
相关产品推荐

