我正在尝试使用 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();
}