【问题标题】:JPA Criteria API - query code works when executed separately but not when used as a subqueryJPA Criteria API - 查询代码在单独执行时有效,但在用作子查询时无效
【发布时间】:2020-07-04 10:11:53
【问题描述】:

我有名为Issue 的实体和名为UserIssue 的实体。 UserIssue 扩展 Issue

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Where(clause = "DELETED_AT IS NULL")
@Entity(name = "ISSUE")
public class Issue extends VersionedSequenceIdEntity {
... all fields
}

@Where(clause = "DELETED_AT IS NULL")
@Entity(name = "USER_ISSUE")
public class UserIssue extends Issue {

    ...

    @Column(name = "IS_PRIVATE", nullable = false)
    private Boolean isPrivate;

    ...
}

我正在做一个子查询like in this post 以通过 sublcas 属性进行一些过滤。我的确切测试用例是我创建了三个 UserIssues。其中两个具有 false 的“isPrivate”属性。第三个将 isPrivate 设置为 true。

当我执行这个实际上只是子查询的代码时,结果包含两个基于条件的“问题”并且它是正确的

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<UserIssue> issueQuerySimple = cb.createQuery(UserIssue.class);
Root<UserIssue> issueRootSimple = issueQuerySimple.from(UserIssue.class);

issueQuerySimple.select(issueRootSimple).where(cb.isFalse(issueRootSimple.get("isPrivate")));
List<UserIssue> resultListSimple = entityManager.createQuery(issueQuerySimple).getResultList();

但是,当我构建将上面的代码用作子查询的整个查询时,会返回所有三个“问题”并且出现问题。我希望代码只返回两个“isPrivate”属性设置为false的“问题”

CriteriaQuery<Issue> issueQuery = cb.createQuery(Issue.class);
Root<Issue> issueRoot = issueQuery.from(Issue.class);

Subquery<UserIssue> subQuery = issueQuery.subquery(UserIssue.class);
Root<UserIssue> userIssueRoot = subQuery.from(UserIssue.class);

subQuery.select(userIssueRoot).where(cb.isFalse(userIssueRoot.get("isPrivate")));

issueQuery.select(issueRoot).where(cb.exists(subQuery));
List<Issue> resultList = entityManager.createQuery(issueQuery).getResultList();

在这里,您还可以看到来自 hibernate 创建的日志的查询。对我来说似乎是正确的

select
        issue0_.id as id2_2_,
        issue0_.deleted_at as deleted_3_2_,
        issue0_.created_when as created_4_2_,
        issue0_.created_by as created_5_2_,
        issue0_.updated_when as updated_6_2_,
        issue0_.version as version7_2_,
        issue0_.application_id as applicat8_2_,
        issue0_.version_id as version_9_2_,
        issue0_.organization_id as organiz10_2_,
        issue0_.severity as severit11_2_,
        issue0_.state as state12_2_,
        issue0_.title as title13_2_,
        issue0_.type_id as type_id18_2_,
        issue0_.updated_by_customer_at as updated14_2_,
        issue0_.assigned_to as assigne15_2_,
        issue0_.description as descrip16_2_,
        issue0_.is_private as is_priv17_2_,
        issue0_.dtype as dtype1_2_ 
    from
        issue issue0_ 
    where
        (
            issue0_.DELETED_AT IS NULL
        ) 
        and (
            exists (
                select
                    userissue1_.id 
                from
                    issue userissue1_ 
                where
                    userissue1_.dtype='UserIssue' 
                    and (
                        userissue1_.DELETED_AT IS NULL
                    ) 
                    and userissue1_.is_private=0
            )
        )

那么为什么基于子类字段的过滤不起作用并且它返回所有三个实例而不是两个?有什么问题或我看不到什么?

非常感谢

【问题讨论】:

  • 您可以将issue 表中的数据添加到问题中吗?

标签: java hibernate jpa criteria-api


【解决方案1】:

替换

issueQuery.select(issueRoot).where(cb.exists(subQuery));

issueQuery.select(issueRoot).where(issueRoot.get("id").in(subQuery));

说明

  • 从sql查询我们可以看出,只要一个userissueis_private=0存在,就会选中所有issues
  • 这不是您想要的行为。您仍然必须使用子查询,但想用 issue0_.id in 替换 exists,这段代码 sn-p 可以做到这一点

【讨论】:

    猜你喜欢
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多