【问题标题】:JPA Criteria Builder OneToMany RestrictionsJPA Criteria Builder OneToMany 限制
【发布时间】:2015-03-19 13:30:33
【问题描述】:

我有一个父级,它与一个子表具有 OneToMany 关联。

我正在尝试使用 CriteriaBuilder 编写查询以限制从 Child 表返回的结果。

我正在添加一个谓词,类似于

cb.equal(parent.get("children").get("sex"), "MALE")

如果 Parent 有一个儿子或 SON 和 Daughter,它会返回该父母,但也会返回他们拥有的所有孩子。

Hibernate 使用我的谓词触发第一个查询,但获取子项的第二个查询仅在它不包含的 where 子句中使用 JoinColumn

cb.equal(parent.get("children").get("sex"), "MALE").

想法?

我正在使用 SetJoin

children = parent.joinSet("children", JoinType.LEFT)

澄清:

public static Specification<Parent> findPlanBenefits(Integer parentId) {
    return (parent, query, cb) -> {
        Predicate predicates = cb.conjunction();
        List<Expression<Boolean>> expressions = predicates.getExpressions();

        //Parent Criteria
        expressions.add(cb.equal(parent.get("parentId"), parentId));

        //Children Criteria
        SetJoin<Parent, Children> children = parent.joinSet("children", JoinType.LEFT);

        Predicate sex = cb.equal(children.get("sex"), "MALE");
        children.on(sex);

        return predicates;
    };
}

【问题讨论】:

  • 请修正代码格式,删除&lt;code&gt;标签和箭头。在代码前留一个空行,并使用缩进使其格式正确。

标签: java jpa one-to-many


【解决方案1】:

恐怕JOIN ON 无法按照您在回答中的预期工作。 JOIN ON 只告诉如何加入,而不是如何加载关系。

因此,为了解决您的问题,您必须在加载孩子后对其进行过滤,或者使用单独的查询手动获取所有男性孩子。

为了检查JOIN ON 的工作原理,您还可以尝试相应的 JPQL 查询。


更新

OP 告诉 JPQL 查询select p from parent p join fetch children c where p.parentId = :parentId and c.sex = "MALE" 有效。

相应的 CriteriaQuery 如下所示:

CriteriaQuery<Parent> criteria = cb.createQuery((Class<Parent>) Parent.class);
Root<Parent> parent = criteria.from(Parent.class);

criteria.select((Selection<T>) parent);
SetJoin<Parent, Children> children = parent.joinSet("children", JoinType.LEFT);

Predicate sexPredicate = cb.equal(children.get("sex"), "MALE");
parent.fetch(children);
//parent.fetch("children");//try also this

criteria.where(sexPredicate);

【讨论】:

  • select p from parent p join fetch children c where p.parentId = :parentId and c.sex = "MALE" 有效,如何通过 Specification/CriteriaQuery 进行等效操作?
  • 我刚刚更改了示例代码,因为缺少获取部分。
  • 但恐怕这也行不通。您是否希望父级仅加载其男性子级?
  • 是的,JPQL 就是这样做的。
  • 关系急,我试了fetch还是不行。
【解决方案2】:

当你创建JOIN时(尤其是当属性是集合类型,而不是SingularAttribute时,你必须使用它来构建条件,所以使用

cb.equal(children.get("sex"), "MALE").

而不是

cb.equal(parent.get("children").get("sex"), "MALE").

【讨论】:

  • 其实我就是这样做的: SetJoin children = parent.joinSet("children", JoinType.LEFT); cb.equal(children.get("sex", "MALE") 但它仍然只将该谓词放在第一个查询上以返回父对象。
  • 我只是不明白你的问题,出现问题的带有注释的代码比描述要好得多。
【解决方案3】:

为了将来的参考,这是另一个帖子,它帮助了我(link): 代替 parent.joinSet 使用 fetch 然后将其强制加入:

Join<Parent, Children> join = (Join<Parent, Children>)parent.fetch(Parent_.children);

正如上面链接的帖子中提到的,这不是完美的解决方案,但它为我省去了很多麻烦。

【讨论】:

    猜你喜欢
    • 2017-07-20
    • 2017-09-26
    • 2015-01-14
    • 2017-05-13
    • 1970-01-01
    • 2015-05-11
    • 2013-08-25
    • 1970-01-01
    相关资源
    最近更新 更多