使用Room构建时触发StackOverflowError问题求助
我之前也碰到过这个问题,这是Room处理自引用关联时的典型坑——你的Category实体类同时承担了数据库表模型(带@Entity注解)和关联查询结果模型(带@Relation的subcategories字段)的角色,形成了循环依赖,导致KAPT在编译分析时无限递归,最终触发栈溢出。
问题根源
你的Category类里,subcategories是List<Category>,而Category本身又包含subcategories,这种自引用结构让Room的注解处理器在生成代码时陷入无限递归,超过了JVM的栈深度限制,抛出StackOverflowError。
解决方案:拆分实体与关联模型
正确的做法是把数据库表实体和带关联的查询结果模型分开,避免同一个类同时承担两种角色:
1. 创建纯数据库实体类
这个类只负责定义数据库表的结构,不包含任何@Relation字段:
@Entity( foreignKeys = [ ForeignKey( entity = CategoryEntity::class, parentColumns = ["id"], childColumns = ["parentId"] ) ] ) data class CategoryEntity( val type: Byte, val name: String, val description: String, var parentId: Long? = null, var remoteId: Long? = null, @PrimaryKey(autoGenerate = true) val id: Long = 0L )
2. 创建带关联的查询结果模型
单独定义一个类,用来封装实体和它的子分类关联,这个类不需要@Entity注解:
data class CategoryWithSubcategories( @Embedded val category: CategoryEntity, @Relation( parentColumn = "id", entityColumn = "parentId" ) val subcategories: List<CategoryWithSubcategories>? = null )
3. 修改Dao层查询方法
在Dao中使用新的查询模型,并且必须加上@Transaction注解(因为@Relation需要在事务中执行关联查询):
@Dao interface CategoryDao { @Transaction @Query("SELECT * FROM CategoryEntity WHERE parentId IS NULL") suspend fun getRootCategoriesWithSubcategories(): List<CategoryWithSubcategories> }
为什么这样能解决问题?
拆分后,Room的注解处理器处理@Relation时,递归的是CategoryWithSubcategories而非数据库实体本身,打破了原有的循环依赖链。同时,这种设计也更符合Room的架构理念:实体类只映射数据库表,关联模型专门处理查询结果的层级结构。
如果需要更新或插入数据,直接操作CategoryEntity即可;CategoryWithSubcategories仅用于查询和展示层级化的分类数据。
内容的提问来源于stack exchange,提问作者Dr.Zoidberg

