首页 > 解决方案 > 如何获取和/或设置谓词 CriteriaQuery 的参数?

问题描述

我正在尝试重构我的 Spring 规范 (org.springframework.data.jpa.domain.Specification) 以使用 JSR 310 类。换句话说,我的规范使用 Date 而我想使用 Instant。

为了做到这一点,我想为规范创建单元测试。我的想法是获取生成的查询字符串并在重构前后进行比较。

如果重构后有相同的,那么一切都应该是好的。

但是,我的查询参数始终为空。如果我尝试设置它们,我会得到 IllegalArgumentExcpeption。

    Instant now = Instant.now();
    Specification<Sp> sp = SpSpecification.betweenDates(now, now);

    CriteriaBuilder cb = entityManagerFactory.getCriteriaBuilder();
    CriteriaQuery<Sp> q = cb.createQuery(Sp.class);
    Root<Sp> root = q.from(Sp.class);

    Predicate p = sp.toPredicate(root, q, cb);
    q.where(p);

    TypedQuery<Sp> typedQuery = entityManagerFactory.createEntityManager().createQuery(q);

    List<Sp> resultList = typedQuery.getResultList();

    // doesn't show the parameter values
    String queryString = typedQuery.unwrap(org.hibernate.Query.class).getQueryString();
    // always empty
    System.out.println(typedQuery.getParameters());
    // ok get named parameters --> [param5, param0, param3, param4, param1, param2]
    String[] namedParameters = typedQuery.unwrap(org.hibernate.Query.class).getNamedParameters();
    // try and set one of them -> IllegalArgumentException (Unable to locate parameter registered with that name)
    typedQuery.setParameter("param5", now);

标签: hibernatejpaspring-data-jpa

解决方案


可能您可以使用query.getNamedParameters() withquery.getParameterValue(namedParameter)来获取值。
由于我找不到使用 spring 数据specification进行连接查询的方法unrelated entities,这不是由一对一或一对多关系定义的,我使用以下代码来组合规范(在这种情况下扮演将表单字段转换为 where 子句的“fields where assembler”)


@Override
    public Page<TestData> find(Specification<TestData> testDataSpecification,
                               Specification patientSpecification,
                               Pageable page) {
        String basicQuerystring = " from TestData t , Patient p  ";
        StringBuffer finalQs = new StringBuffer();
        finalQs.append(basicQuerystring);
        String testDataAlias = "t";
        Query testDataQuery = toQuery(testDataSpecification, TestData.class, testDataAlias);
        String patientAlias = "p";
        Query patientQuery = toQuery(patientSpecification, Patient.class, patientAlias);

        String testDataWhere = getWhereQs(testDataQuery, testDataAlias);
        String patientWhere = getWhereQs(patientQuery, patientAlias);

        StringBuffer allWhere = new StringBuffer(" where t.patientCode=p.hospitalCode ");
        allWhere.append(testDataWhere.length() > 0 ? (" and " + testDataWhere) : "");
        allWhere.append(patientWhere.length() > 0 ? (" and " + patientWhere) : "");

        finalQs.append(allWhere);

        Map<String, Object> paramMap = new HashMap();

        // page and sort
        int pageSize = page.getPageSize();
        long offset = page.getOffset();
        String sortString = page.getSort().toString();
        String countString = "select  count(*) " + finalQs.toString();
        if (!"UNSORTED".equals(sortString)) {
            finalQs.append(" sort by " + sortString);
        }
        javax.persistence.Query finalQuery = entityManager.createQuery(finalQs.toString());
        finalQuery.setFirstResult((int) offset);
        finalQuery.setMaxResults(pageSize);

        // add params
        if (testDataQuery != null) {
            addParamValue(testDataAlias, testDataQuery, paramMap);
        }
        if (patientQuery != null) {
            addParamValue(patientAlias, patientQuery, paramMap);
        }
        addAllParamsToQuery(paramMap, finalQuery);

        List resultList = finalQuery.getResultList();
        return PageableExecutionUtils.getPage(resultList, page, new LongSupplier() {
            @Override
            public long getAsLong() {
                javax.persistence.Query countQuery = entityManager.createQuery(countString);
                addAllParamsToQuery(paramMap, countQuery);
                return (Long) countQuery.getSingleResult();
            }
        });
    }

private Query toQuery(Specification specification, Class aClass, String classAlias) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery query = cb.createQuery(aClass);
        Root<TestData> root = query.from(aClass);
        root.alias(classAlias);
        Predicate predicate = specification.toPredicate(root, query, cb);
        return predicate == null ? null : entityManager.createQuery(query.where(predicate)).unwrap(Query.class);
    }

private String getWhereQs(Query query, String entityAlias) {
        if (query == null)
            return "";
        String queryString = query.getQueryString();
        int containsWhere = queryString.indexOf("where");
        String substring = "";
        if (containsWhere != -1) {
            substring = queryString.substring(containsWhere + "where".length());
        }
        return substring.replaceAll(":param", ":" + entityAlias + "param");
    }

private void addParamValue(String testDataAlias, Query testDataQuery, Map<String, Object> paramMap) {
        for (String namedParameter : testDataQuery.getNamedParameters()) {
            paramMap.put(testDataAlias + namedParameter, testDataQuery.getParameterValue(namedParameter));
        }
    }

private void addAllParamsToQuery(Map<String, Object> paramMap, javax.persistence.Query finalQuery) {
        for (Map.Entry<String, Object> each : paramMap.entrySet()) {
            String paramName = each.getKey();
            Object paramValue = each.getValue();
            finalQuery.setParameter(paramName, paramValue);
        }
    }

推荐阅读