spring-data规范和连接子查询

时间:2014-04-06 09:21:22

标签: jpa-2.0 spring-data-jpa criteria-api named-query

我的spring-data存储库中有以下命名查询:

@Query("FROM Pedido p JOIN FETCH p.status ps WHERE ps.status IN (?1) AND ps.id IN (SELECT MAX(ps2.id) FROM PedidoStatus ps2 GROUP BY ps2.pedido)")

我正在尝试使用Criteria API和spring-data规范获得相同的结果,这是我到目前为止所做的:

public static Specification<Pedido> byUltimoStatus(final List<PedidoStatus.StatusPedido> ultimoStatus) {
return new Specification<Pedido>() {
    public Predicate toPredicate(Root<Pedido> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

        Expression<PedidoStatus.StatusPedido> status = root.join("status").get("status");
        Predicate predicateByStatus = status.in(ultimoStatus);

        final Subquery<Long> subQuery = query.subquery(Long.class);
        final Root<PedidoStatus> ps = subQuery.from(PedidoStatus.class);

        Expression<Long> psId= ps.get("id");
        Expression<Long> maxId = builder.max(psId);

        subQuery.select(maxId);
        subQuery.groupBy(ps.get("pedido").get("id"));

        Predicate predicateByUltimoStatus = builder.in(root.join("status").get("id")).value(subQuery);

        return builder.and(predicateByStatus, predicateByUltimoStatus);             
    }
};}

它仍然不起作用,看起来有一个额外的 INNERJOIN PedidoStatus 在结果查询中。

这是@Query的结果:

select ... from Pedido pedido0_ inner join PedidoStatus status1_ on pedido0_.id=status1_.pedido where (status1_.status in (? , ?)) and (status1_.id in (select max(pedidostat2_.id) from PedidoStatus pedidostat2_ group by pedidostat2_.pedido))  

这是Criteria API的结果:

select ... from Pedido pedido0_ inner join PedidoStatus status1_ on pedido0_.id=status1_.pedido inner join PedidoStatus status2_ on pedido0_.id=status2_.pedido where (pedido0_.id is not null) and status1_.status IN (?, ?) and (status2_.id in (select max(pedidostat3_.id) from PedidoStatus pedidostat3_ group by pedidostat3_.pedido)) 

1 个答案:

答案 0 :(得分:0)

知道这是一个非常古老的问题,我认为在CriteriaQuery生成的查询中重复INNERJOIN的原因是构建查询的代码确实实际调用了root.join("status")两次。第一次调用的结果应保存到局部变量中,因此您可以重复使用它,而不是连接两次。

首先你做:

  

Expression<PedidoStatus.StatusPedido> status = root.join("status").get("status");

以后你会这样做:

  

Predicate predicateByUltimoStatus = builder.in(root.join("status").get("id")).value(subQuery);