如何在ObjectBox @Entity中无需关联存储嵌套对象/嵌套对象列表
问题描述
我尝试对API返回的模型进行本地缓存,模型定义如下:
data class Subject( val id: Long, val meanings: List<Meaning> // 其他无关字段已省略 ) data class Meaning( val meaning: String, val primary: Boolean, val acceptedAnswer: Boolean )
Meaning模型仅包含ObjectBox支持的类型,且每个Subject的Meaning都是唯一的,不会在多个Subject间共享。核心需求是:每次从API获取更新数据并覆盖现有Subject时,同时覆盖所有嵌套对象,将Subject及其内部所有嵌套对象视为一个整体。
尝试使用ObjectBox关联定义实体:
@Entity data class SubjectEntity( @Id var id: Long = 0, @Index @Unique(onConflict = ConflictStrategy.REPLACE) var apiId: Long = 0, ) { lateinit var meanings: ToMany<MeaningEntity> } @Entity data class MeaningEntity( @Id var id: Long = 0, val meaning: String = "", val primary: Boolean = false, val acceptedAnswer: Boolean = false )
更新时执行以下代码:
subjectEntity.meanings.apply { clear() addAll(...) } subjectBox.put(subjectEntity)
但会导致MeaningEntity盒子中保留之前的所有meanings,必须手动删除旧对象,操作繁琐。关联方式相当于额外维护一张表,不符合ObjectBox作为NoSQL数据库的使用预期,想知道有没有更好的实现方式?
解决方案
使用ObjectBox的**嵌入对象(Embedded Objects)**特性,完全符合你的需求——把嵌套对象和主实体视为一个整体,更新主实体时自动同步嵌套对象的增删改,无需手动维护关联关系。
1. 定义嵌入实体
将Meaning定义为嵌入类,用@Embed标注;在SubjectEntity中用@EmbeddedList标注嵌套列表:
@Entity data class SubjectEntity( @Id var id: Long = 0, @Index @Unique(onConflict = ConflictStrategy.REPLACE) var apiId: Long = 0, // 用EmbeddedList标注嵌套的Meaning列表 @EmbeddedList var meanings: List<MeaningEmbed> = emptyList() ) // 用@Embed标注嵌入类,无需@Entity和@Id @Embed data class MeaningEmbed( val meaning: String = "", val primary: Boolean = false, val acceptedAnswer: Boolean = false )
2. 更新操作
直接将API返回的Subject转换为SubjectEntity后调用put即可,ObjectBox会自动处理嵌套列表的覆盖:
// 假设从API获取到subject: Subject val subjectEntity = SubjectEntity( apiId = subject.id, meanings = subject.meanings.map { MeaningEmbed(it.meaning, it.primary, it.acceptedAnswer) } ) subjectBox.put(subjectEntity)
适配优势
- 嵌入对象与主实体存储在一起,不存在独立的"表",完全契合你将Subject和Meaning视为整体的需求;
- 更新主实体时,ObjectBox会自动替换整个嵌套列表,旧的嵌入对象会被直接清除,无需手动删除;
- 嵌入对象的查询与主实体绑定,不需要额外处理关联查询逻辑。
内容的提问来源于stack exchange,提问作者emi
相关产品推荐
相关产品推荐

