Room 2.6.1自连接异常求助:LEFT JOIN触发空指针错误
Room自连接LEFT JOIN触发UUID空指针异常的解决方案
问题场景
使用Room进行单表自连接LEFT JOIN时,抛出空指针异常:
java.lang.NullPointerException: Parameter specified as non-null is null: method androidx.room.util.UUIDUtil.convertByteToUUID, parameter bytes
跨表JOIN功能正常,但普通JOIN会丢失无关联子项的父记录,结果不符合预期;用WHERE语句实现自连接逻辑不够直观。
问题原因
LEFT JOIN会返回所有父表记录,包括没有匹配子项的记录——此时子表对应的所有字段值为null。但实体类Answer中的id和qTypeId是非空UUID类型,Room尝试将null字节数组转换为UUID时触发空指针异常。同时原查询使用SELECT *会导致父、子表列名冲突,Room无法正确映射字段。
解决方案
方案1:使用可空子实体类+中间映射类
创建允许字段为空的子实体类,通过别名区分父、子表字段,再手动映射为目标Map结构:
- 定义可空子实体与中间映射类
// 允许字段为空的子实体 data class ChildAnswer( val id: UUID?, val qTypeId: UUID?, val parentId: UUID?, // 其他字段对应设为可空类型 ) // 接收JOIN结果的中间类,用别名区分父、子字段 data class AnswerWithChild( // 父实体字段(非空) val id: UUID, val qTypeId: UUID, val parentId: UUID?, // 子实体字段(全部可空) val child_id: UUID?, val child_qTypeId: UUID?, val child_parentId: UUID?, // 其他子字段需对应添加别名,如child_xxx )
- 修改DAO查询语句
@Query( """SELECT PARENT.id, PARENT.qTypeId, PARENT.parentId, ..., CHILD.id AS child_id, CHILD.qTypeId AS child_qTypeId, CHILD.parentId AS child_parentId, ... FROM table AS PARENT LEFT JOIN table AS CHILD ON PARENT.id = CHILD.parent_id AND PARENT.qTypeId = CHILD.qTypeId WHERE PARENT.qTypeId = :qTypeId """ ) fun getRawAnswerWithChildren(qTypeId: UUID): List<AnswerWithChild>
- 手动转换为目标Map结构
fun convertToAnswerMap(rawList: List<AnswerWithChild>): Map<Answer, List<Answer>> { return rawList.groupBy( keySelector = { parent -> Answer(parent.id, parent.qTypeId, parent.parentId, ...) // 构建父实体 }, valueTransform = { pair -> // 仅当子字段非空时构建子实体 if (pair.child_id != null && pair.child_qTypeId != null) { Answer(pair.child_id, pair.child_qTypeId, pair.child_parentId, ...) } else { null } } ).mapValues { (_, children) -> children.filterNotNull() } }
方案2:调整查询逻辑,过滤null子项(不推荐)
如果业务允许忽略无关联子项的父记录,可改用INNER JOIN,但这会导致结果缺失,仅适用于特定场景。
关键说明
- 避免使用
SELECT *进行自连接:父、子表列名重复会导致Room字段映射混乱,必须通过别名区分。 - 非空字段需匹配数据实际情况:LEFT JOIN必然产生null子记录,对应实体字段必须设为可空,或通过中间类中转处理。
内容的提问来源于stack exchange,提问作者Person Person
相关产品推荐
相关产品推荐

