在Spring数据计数方法中使用group by with specification

时间:2018-02-27 11:31:05

标签: group-by spring-data-jpa specifications

我想实现一个spring数据方法,用于检查以下查询的结果

select count(1) from installation_requested_t requested 
where requested.installation_id in 
      (select installation_id from installation_requested_t where request_id=?) 
group by requested.installation_id
having count(1)>1;

对于项目,必须使用带有弹簧数据jpa的规范。 所以有我的存储库方法调用:

installationRequestedRepository.count(
                               InstallationSpecs
                               .existsInstallationRequestLinkedToAnotherEPR(movingEprId)
);

和我的规范方法:

public static Specification<InstallationRequested> existsInstallationRequestLinkedToAnotherEPR(final Long EPRId) {
    return new Specification<InstallationRequested>() {

        @Override
        public Predicate toPredicate(Root<InstallationRequested> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

            Subquery<Long> InstallationIdsLinkedToEPRsubquery = query.subquery(Long.class);

            InstallationIdsLinkedToEPRsubquery.select(root.get(InstallationRequested_.id))
                    .where(cb.equal(root.get(InstallationRequested_.environmentPermitRequestId), EPRId));

            Subquery<InstallationRequested> installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR =
                    query.subquery(InstallationRequested.class);

            installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR
                    .select(installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR
                            .from(InstallationRequested.class))
                    .where(root.get(InstallationRequested_.id).in(InstallationIdsLinkedToEPRsubquery))
                    .groupBy(root.get(InstallationRequested_.id))
                    .having(cb.greaterThan(cb.count(cb.literal(1)), cb.literal(1l)));

            return cb.exists(installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR);

        }
    };

}

我的问题是一切都不能很好地执行:

org.springframework.dao.InvalidDataAccessApiUsageException: 
org.hibernate.hql.internal.ast.QuerySyntaxException: 
unexpected token: where near line 1, column 333 
[select count(generatedAlias0) from be.question.domain.model.request.installation.InstallationRequested as generatedAlias0 
where exists 
    (select generatedAlias1 from be.question.domain.model.request.installation.InstallationRequested as generatedAlias1 
    where generatedAlias0.id in 
        (select generatedAlias0.id from  where generatedAlias0.environmentPermitRequestId=1072487L) 
    group by generatedAlias0.id having count(1)>1L)
]; 

您是否有想法让我的规范工作以及另一种方式来完成被询问的任务?

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。 我修改了规范:

public static Specification<InstallationRequested> existsInstallationRequestLinkedToAnotherEPR(final Long EPRId) {
    return new Specification<InstallationRequested>() {

        @Override
        public Predicate toPredicate(Root<InstallationRequested> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

            // subquery to select installation ids
            Subquery<Long> InstallationIdsLinkedToEPRsubquery = query.subquery(Long.class);
            Root<InstallationRequested> selectIdSubQueryRoot =
                    InstallationIdsLinkedToEPRsubquery.from(InstallationRequested.class);
            InstallationIdsLinkedToEPRsubquery
                    .select(selectIdSubQueryRoot.get(InstallationRequested_.installation).get(Installation_.id))
                    .where(cb.equal(selectIdSubQueryRoot.get(InstallationRequested_.environmentPermitRequestId),
                            EPRId));

            // subquery to select count of installation request group by installation id
            Subquery<Long> installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR =
                    query.subquery(Long.class);
            Root<InstallationRequested> groupBySubQueryRoot =
                    installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR
                            .from(InstallationRequested.class);
            Path<Long> installationIdInGroupBySubQuery =
                    groupBySubQueryRoot.get(InstallationRequested_.installation).get(Installation_.id);

            installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR.select(cb.count(cb.literal(1)))
                    .where(installationIdInGroupBySubQuery.in(InstallationIdsLinkedToEPRsubquery))
                    .groupBy(installationIdInGroupBySubQuery)
                    .having(cb.greaterThan(cb.count(cb.literal(1)), cb.literal(1l)));

            // returning existing condition on result of the group by
            return cb.exists(installationRequestForTheseInstallationIdsWhoAreLinkedToAnotherEPR);

        }
    };

}

顺便说一句,如果有人作为一个更好的主意我会乐意阅读它;)