当前位置: 首页 > 知识库问答 >
问题:

如何在JPA条件生成器选择语句中执行子查询?

缑兴贤
2023-03-14

我试图使用CritierBuilder/CrtieriaQuery执行select语句,从表a中选择某些字段,然后如果该记录存在于另一个表中,则使用布尔标志。

基本上,我有一个“官员”列表和一个用户列表。用户是使用该系统的人,可以为官员添加书签/保存信息。当用户询问官员时,我希望能够显示他们已经为哪些官员添加了书签。

SELECT o.FIRST_NAME, o.LAST_NAME,
 (select CAST(1 AS BIT) from OFFICER_BOOKMARK b where b.OFFICER_ID=o.OFFICER_ID AND USER_ID=123456789) as BOOKMARKED 
from OFFICER o;

所以这个查询,我在我的h2数据库控制台中运行,它(相当)有效。如果官员被用户123456789标记为书签,则返回true,否则书签列为空。

但我很难将其转换为jpa标准查询。。。

public List<OfficerDTO> getOfficersDto() {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<OfficerDTO> cq = cb.createQuery(OfficerDTO.class);
    Root<OfficerEntity> root = cq.from(OfficerEntity.class);
    Root<OfficerBookmarkEntity> subRoot = cq.from(OfficerBookmarkEntity.class);

    Subquery<Boolean> subquery = cq.subquery(Boolean.class);
    subRoot.alias("bookmarked");
    subquery.select(cb.isNotNull(subRoot.get("id")));
    subquery.where(cb.equal(subRoot.get("officer").get("officerId"), root.get("officerId")));
    subquery.where(cb.equal(subRoot.get("user").get("userId"), "123456789"));

    cq.multiselect(
            cb.construct(
                OfficerDTO.class,
                root.get("firstName"),
                root.get("lastName"),
                subquery.getSelection().as(Boolean.class)
            )
    );
    TypedQuery<OfficerDTO> q = em.createQuery(cq);
    return q.getResultList();
}

我想我已经很接近了,但我不知道select语句的子查询部分,以及如何返回布尔值。

共有1个答案

方博
2023-03-14

问题是cb.isNotNull(subRoot.get("id"))仅在subquery结果存在时才有效(仅返回true)。否则您得到了null。因此您必须在更高的杠杆上检查subquery结果。

这应该行得通

  public List<OfficerDTO> getOfficersDto() {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<OfficerDTO> cq = cb.createQuery(OfficerDTO.class);
        Root<OfficerEntity> root = cq.from(OfficerEntity.class);

        Subquery<Long> subquery = cq.subquery(Long.class); // or Integer (depends on id class)
        Root<OfficerBookmarkEntity> subRoot = 
            subquery.from(OfficerBookmarkEntity.class);

        Predicate officerPredicate = cb.equal(
            subRoot.get("officer").get("officerId"), 
            root.get("officerId")
        );

        Predicate userPredicate = cb.equal(
            subRoot.get("user").get("userId"), 
            "123456789"
        );

        subquery.select(subRoot.get("id"))                 // select subRoot id
            .where(officerPredicate, userPredicate);       // if you execute `.where` twice 
                                                           // it replaces the previously added restrictions     
        cq.multiselect(
            cb.construct(
                OfficerDTO.class,
                root.get("firstName"),
                root.get("lastName"),
                subquery.getSelection().isNotNull()        // check if subquery result is present
            )
        );

        return em.createQuery(cq).getResultList();
}
 类似资料:
  • 如何在Hibernate中为下面给定的查询编写criteria builder api查询?batchId不是主键 从用户中选择批号('1','3') 我尝试过: 除了数据库中存在的数据外,我什么也得不到。

  • 我试图使用JPA标准编写以下查询,但我无法选择子查询中的多列。 我陷入了下面的实现过程中,无法找到如何在子查询中选择多个列。请看我在代码中的评论(第三行)。 请帮我解决这个问题。

  • 我正在尝试使用criteriaBuilder和谓词构建一个SQL where子句,以创建一些SQL语句,如: AND或对列表周围的括号对于将它们与不存在分开很重要。这是因为和有优先权我得到的是 我可以构建所有谓词,没有问题,但我不知道如何让它在AND或PAIRES列表中添加括号 AND或OR对的列表是这样构建成1个谓词列表的 子查询是这样添加的 还有地点 每个AND或AND对周围的括号也一样好

  • 问题内容: 这是SQL中的JOIN问题更新语句的扩展,但是我试图使用Spring Data JPQL。 我正在尝试将更新与JPQL中的JOIN一起使用,如下所示 但是,我得到如下错误 org.hibernate.hql.internal.ast.QuerySyntaxException:期望“设置”,找到“ JOIN” JPQL中无法进行UPDATE和JOIN吗?有什么选择。谢谢 问题答案: 该J

  • 这是在SQL中使用JOIN的question Update语句的扩展,但我正在尝试使用Spring Data JPQL。 我试图在JPQL中使用Update和JOIN,如下所示 在JPQL中是否不能更新和连接?另一种选择是什么。谢谢

  • 此外,您是否愿意指出任何好的教程,以编写复杂的查询在JPA。