You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Room如何查询含嵌入式实体与非实体POJO的多对多关联数据

问题根因

Room 的 @Relation 注解要求关联的目标类型必须是被 @Entity 或 @DatabaseView 修饰的类,你直接将非实体的展示类 CardView 作为 @Relation 的关联目标,因此触发了编译错误。

前置修正:现有代码笔误

先修正几个实体类的笔误,避免后续运行出错:

  1. Chapter 类构造函数名错误,应该和类名保持一致:
// 原错误写法:public CardListChapter(long listId, String chapterTitle)
public Chapter(long listId, String chapterTitle){
    this.listId = listId;
    this.chapterTitle = chapterTitle;
}
  1. 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
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:15:07