我有一个父子与OneToMany关联与子表。
我正在尝试使用CriteriaBuilder编写查询来限制从Child表返回的结果。
我正在添加谓词,类似于
cb.equal(parent.get("children").get("sex"), "MALE")
如果父母有一个儿子或者SON和女儿它正在返回那个父母,但也返回他们拥有的所有孩子。
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;
};
}
我担心,JOIN ON
不能像你期望的那样在你的答案中工作。 JOIN ON
只告诉如何加入,而不是如何加载关系。
因此,为了解决您的问题,您必须在加载后过滤子项,或者使用单独的查询手动获取所有男性子项。
为了检查JOIN ON
的工作原理,您还可以尝试相应的JPQL查询。
UPDATE
OP告诉JPQL queryselect 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);
当你创建一个JOIN
时(特别是当属性是集合类型,而不是SingularAttribute
时,你必须用它来构建标准,所以使用
cb.equal(children.get("sex"), "MALE").
代替
cb.equal(parent.get("children").get("sex"), "MALE").
为了将来的参考,这是来自另一个帖子,帮助我(link):而不是parent.joinSet使用fetch然后将其转换为join:
Join<Parent, Children> join = (Join<Parent, Children>)parent.fetch(Parent_.children);
正如上面链接的帖子中提到的那样,它并不是完美的解决方案,但它让我很烦恼。