Room如何查询含嵌入式实体与非实体POJO的多对多关联数据
问题根因
Room 的 @Relation 注解要求关联的目标类型必须是被 @Entity 或 @DatabaseView 修饰的类,你直接将非实体的展示类 CardView 作为 @Relation 的关联目标,因此触发了编译错误。
前置修正:现有代码笔误
先修正几个实体类的笔误,避免后续运行出错:
Chapter类构造函数名错误,应该和类名保持一致:
// 原错误写法:public CardListChapter(long listId, String chapterTitle) public Chapter(long listId, String chapterTitle){ this.listId = listId; this.chapterTitle = chapterTitle; }
ChapterCardMap类构造函数存在变量名错误:
// 原错误写法:public CardListChapterMap(long chapterId, long cardId){ this.cardListId = cardListId; } public ChapterCardMap(long chapterId, long cardId){ this.chapterId = chapterId; this.cardId = cardId; } // 可以删除无用的cardListId相关getter、setter
CardView类构造函数名错误,应该和类名保持一致:
// 原错误写法:public FlashcardView(Long cardId, String typeName, String text, boolean bookmarked) public CardView(Long cardId, String typeName, String text, boolean bookmarked){ this.cardId = cardId; this.typeName = typeName; this.text = text; this.bookmarked = bookmarked; }
可行实现方案
该方案兼容性强,不需要修改你现有 CardView 的查询逻辑,也不需要把 CardView 改为实体或视图:
步骤1:修改 ChapterWithCards 定义
去掉 @Relation 注解,改为普通组合POJO:
public class ChapterWithCards { @Embedded private Chapter chapter; private List<CardView> cardViews; // 原有getter、setter保持不变 public Chapter getChapter() { return chapter; } public void setChapter(Chapter chapter) { this.chapter = chapter; } public List<CardView> getCardViews() { return cardViews; } public void setCardViews(List<CardView> cardViews) { this.cardViews = cardViews; } }
步骤2:DAO层新增查询接口
复用你原有 CardView 的多表JOIN逻辑,新增两个基础查询,再加一个事务型组合方法:
// 查询指定listId下的所有章节 @Query("SELECT * FROM Chapter WHERE listId = :targetListId") abstract public Flow<List<Chapter>> getChaptersByListId(long targetListId); // 查询指定章节关联的所有CardView,复用你原有多表JOIN逻辑,仅修改WHERE条件 @Query("SELECT cardId, typeName, text, bookmarked FROM <你原有多表JOIN语句> WHERE cardId IN (SELECT cardId FROM ChapterCardMap WHERE chapterId = :chapterId)") abstract public Flow<List<CardView>> getCardViewsByChapterId(long chapterId); // 事务注解保证两次查询的数据一致性,组合返回嵌套结构 @Transaction public Flow<List<ChapterWithCards>> getChapterWithCards(long targetListId) { return getChaptersByListId(targetListId) .flatMapConcat(chapters -> { List<Flow<ChapterWithCards>> itemFlows = new ArrayList<>(); for (Chapter chapter : chapters) { Flow<ChapterWithCards> itemFlow = getCardViewsByChapterId(chapter.getChapterId()) .map(cardViews -> { ChapterWithCards result = new ChapterWithCards(); result.setChapter(chapter); result.setCardViews(cardViews); return result; }); itemFlows.add(itemFlow); } return Flow.combine(itemFlows, objects -> { List<ChapterWithCards> resultList = new ArrayList<>(); for (Object obj : objects) { resultList.add((ChapterWithCards) obj); } return resultList; }); }); }
如果你的项目有明确的分层要求,也可以把上面的Flow组合逻辑移到Repository层实现,DAO层只需要暴露两个基础查询接口即可。
内容的提问来源于stack exchange,提问作者Nejesis
相关产品推荐
相关产品推荐

