如何借助Hilt与ViewModel从RoomDB获取Sale及关联SaleProducts?
最优实现方案:Room关联查询+一次性监听
核心思路是利用Room的@Relation注解直接查询出包含关联SaleProducts的Sale数据,彻底避免多次查询和多观察者管理的麻烦。
1. 创建组合数据类封装关联数据
定义一个专门的组合类,用来打包Sale及其对应的所有关联产品:
data class SaleWithProducts( @Embedded val sale: Sale, @Relation( parentColumn = "sale_id", // Sale表的主键字段名 entityColumn = "sale_id" // SaleProducts表中关联Sale的外键字段名 ) val products: List<SaleProduct> )
@Embedded:将Sale实体的字段直接嵌入这个组合类中@Relation:指定一对多的关联规则,Room会自动完成关联数据的查询和匹配
2. 在Dao中添加关联查询方法
修改你的SaleDao,新增带事务的关联查询方法:
@Dao interface SaleDao { // 新增关联查询,必须加@Transaction保证原子性 @Transaction @Query("SELECT * FROM Sale") fun getSalesWithAllProducts(): LiveData<List<SaleWithProducts>> }
@Transaction是必须的,确保多表查询的原子性,避免出现Sale和Products数据不一致的情况。
3. 仓库层暴露关联数据
在仓库类中注入SaleDao,并对外提供关联数据的LiveData:
class SaleRepository @Inject constructor( private val saleDao: SaleDao ) { fun getSalesWithProducts(): LiveData<List<SaleWithProducts>> { return saleDao.getSalesWithAllProducts() } }
4. ViewModel中获取关联数据
通过Hilt注入仓库,直接拿到包含关联数据的LiveData:
@HiltViewModel class SaleViewModel @Inject constructor( private val saleRepository: SaleRepository ) : ViewModel() { val salesWithProducts: LiveData<List<SaleWithProducts>> = saleRepository.getSalesWithProducts() }
5. UI层一次性监听数据
在Activity/Fragment中只需要监听这一个LiveData,无需循环处理每个Sale的单独查询:
// Activity/Fragment中 viewModel.salesWithProducts.observe(viewLifecycleOwner) { saleWithProductsList -> saleWithProductsList.forEach { item -> val targetSale = item.sale val relatedProducts = item.products // 直接处理业务逻辑 } }
方案优势
- 性能更优:从N+1次查询(1次查所有Sale+N次查对应Products)简化为1次查询,减少数据库IO开销
- 逻辑简洁:仅需管理一个观察者,避免多LiveData监听的复杂度
- 数据一致:通过事务保证关联查询的原子性,避免数据不同步问题
内容的提问来源于stack exchange,提问作者Think_Twice
相关产品推荐
相关产品推荐

