QueryDSL 和多对多关系

Posted

技术标签:

【中文标题】QueryDSL 和多对多关系【英文标题】:QueryDSL and ManyToMany relationships 【发布时间】:2021-10-18 08:57:27 【问题描述】:

在一个项目中,我有以下实体:具有与关键字连接的模板部分的模板。这两个关系都是@ManyToMany。一些代码:

@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "TEMPLATE")
public class TemplateEntity extends SystemFlagEntity 

    ...

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "TEMPLATEPART_CATALOGUE",
            joinColumns = @JoinColumn(name = "C_FK_TEMPLATE", referencedColumnName = "C_I_IDF"),
            inverseJoinColumns = @JoinColumn(name = "C_FK_TEMPLATEPART", referencedColumnName = "C_I_IDF"))
    Set<TemplatePartEntity> templatePartsCatalogue = new HashSet<>();



@ToString
@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "TEMPLATEPART")
public class TemplatePartEntity extends SystemFlagEntity 

    ...

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "TEMPLATEPART_KEYWORD",
            joinColumns = @JoinColumn(name = "C_FK_TEMPLATEPART"),
            inverseJoinColumns = @JoinColumn(name = "C_FK_KEYWORD"))
    Set<KeywordEntity> keywords = new HashSet<>();



@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "KEYWORD")
public class KeywordEntity extends LabeledEntity 

    ...


然后我尝试查找与具有给定 ID 的某个模板相关的关键字。我使用此谓词对QueryDSL 执行此操作:

public Iterable<KeywordEntity> findCatalogueKeywordsForTemplate(Long id) 
    return findAll(
        QKeywordEntity.keywordEntity.in(QTemplateEntity.templateEntity.templatePartsCatalogue.any().keywords)
            .and(QTemplateEntity.templateEntity.id.eq(id))
    );

由于某种原因,谓词根本不能很好地处理。尝试调用该方法时出现此错误:

org.hibernate.hql.internal.ast.QuerySyntaxException: templateEntity.templatePartsCatalogue 未映射 [选择 关键字实体\n来自 mypackage.core.domain.model.KeywordEntity keywordEntity\n存在的地方(选择 1\nfrom templateEntity.templatePartsCatalogue 为 templateEntity_templatePartsCatalogue_0\n其中的关键字实体成员 templateEntity_templatePartsCatalogue_0.keywords)和 模板实体.id = ?1];嵌套异常是 java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: templateEntity.templatePartsCatalogue 未映射 [选择 关键字实体\n来自 mypackage.core.domain.model.KeywordEntity keywordEntity\n存在的地方(选择 1\nfrom templateEntity.templatePartsCatalogue 为 templateEntity_templatePartsCatalogue_0\n其中的关键字实体成员 templateEntity_templatePartsCatalogue_0.keywords)和 模板实体.id = ?1]

看起来它不能很好地处理@ManyToMany 关联。关于如何解决这个问题的任何想法?我知道我可以明确地使用JPAQuery,但我想改用Predicate

【问题讨论】:

【参考方案1】:

在看到QueryDSL's creator 的这个答案后,我发现我误解了谓词的工作方式。 此查询无需显式定义多对多关联表即可工作:

public Iterable<KeywordEntity> findCatalogueKeywordsForTemplate(Long id) 
    return new JPAQuery<>(entityManager)
            .select(QKeywordEntity.keywordEntity)
            .from(QTemplateEntity.templateEntity)
            .innerJoin(QTemplateEntity.templateEntity.templatePartsCatalogue, QTemplatePartEntity.templatePartEntity)
            .innerJoin(QTemplatePartEntity.templatePartEntity.keywords, QKeywordEntity.keywordEntity)
            .where(interceptPredicate(QTemplateEntity.templateEntity.id.eq(id)))
            .distinct()
            .fetch();

【讨论】:

以上是关于QueryDSL 和多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

如何判断一对一对多和多对多的关系

具有一对多和多对多关系的 JOOQ pojos

Symfony 固定装置和多对多关系(学说)

多表关系一对多和多对多

Typegoose 模型和多对多关系

HasManyThrough 具有多态和多对多关系