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



我正在尝试使用 CritierBuilder/CrtieriaQuery 执行一个选择语句,以从表 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,否则对于书签列为 null。

但是我无法将其转换为 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 语句的子查询部分以及如何只取回布尔值。

问题是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();
}

相关内容

  • 没有找到相关文章

最新更新