我正在尝试将以下简单查询转换为JPA条件API:
SELECT ticket_action.ticket_id IS NOT NULL, ticket.id
FROM ticket
LEFT OUTER JOIN ticket_action ON ticket.id = ticket_action.ticket_id
我尝试了两种方法:
使用
criteriaBuilder.function("ISNULL", Boolean.class, ticketAction.get(TicketAction_.ticketId))
:如果像ISNULL
这样的ISNOTNULL
(对于MySQL / MariaDB数据库),问题是没有否定的使用
criteriaBuilder.isNotNull(ticketAction.get(TicketAction_.ticketId))
:但这将返回Predicate
,而select语句仅接受Expression
伸展目标:与
GROUP BY ticket.ticket_id IS NOT NULL
相同表结构要求
+-----------+---------+
| ticket |
+-----------+---------+
| name | type |
+-----------+---------+
| id | integer |
| title | varchar |
+-----------+---------+
+-----------+---------+
| ticket_action |
+-----------+---------+
| name | type |
+-----------+---------+
| id | integer |
| ticket_id | integer |
| title | varchar |
+-----------+---------+
结果:
最后,我最终使用了构造器查询,该查询接收了
id
的ticket_action
。在构造函数中,有关于状态的决定:this.hasTicketAction = ticketActionId != null;
不是很令人满意,但是可以工作。
谢谢任何人发表您的答案!
最佳答案
一种可行的方法是使用CriteriaBuilder.selectCase(..)
。
与DTO
一样(Object[]
相同,但是从一开始就是类型安全的)
@Getter
@AllArgsConstructor
public class TicketTuple {
private Boolean hasAction;
private Long ticketId;
}
结果可以通过以下查询获得
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<TicketTuple> cq = cb.createQuery(TicketTuple.class);
Root<Ticket> from = cq.from(Ticket.class);
Join<Ticket, TicketAction> join = from.join("ticketAction", JoinType.LEFT);
Expression<Boolean> caseHasAction = cb.<Boolean>selectCase()
.when(cb.isNotNull(join), true)
.otherwise(false);
cq.multiselect(
caseHasAction.as(Boolean.class)
,from.get("id")
);
关于分组,我不太了解您需要分组的内容,但是例如
cq.multiselect(
caseHasAction.as(Boolean.class)
,cb.count(from.get("id"))
).groupBy(caseHasAction.as(Boolean.class));
将返回具有和不具有
Ticket
的TicketAction
个计数。我不知道实际的原因,但是问题似乎是通过
cb.isNotNull(..)
(我的)JPA
实现要么总是获取似乎不是null
的东西,要么取决于null
的检查方式创建一些INNER JOIN
,以便将null
值从结果集中删除。(我正在使用OpenJPA)
关于java - 条件API:选择表达式IF [NOT] NULL <值>,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47830390/