Wie werden Positionsparameter / benannte Parameter dynamisch für die JPA-Kriterienabfrage festgelegt?

Der Ruhezustand-Anbieter generiert keine vorbereitete Anweisung fürNicht-String Geben Sie Parameter ein, es sei denn, sie sind auf festgelegtentityManager.createQuery(criteriaQuery).setParameter(Parameter p, T t); wie von EclipseLink gemacht, standardmäßig.

Wie können solche Parameter eingestellt werden, wenn sie zur Laufzeit dynamisch bereitgestellt werden? Zum Beispiel,

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Long>criteriaQuery=criteriaBuilder.createQuery(Long.class);
Metamodel metamodel=entityManager.getMetamodel();
EntityType<Product> entityType = metamodel.entity(Product.class);
Root<Product> root = criteriaQuery.from(entityType);
criteriaQuery.select(criteriaBuilder.count(root));

List<Predicate>predicates=new ArrayList<Predicate>();

for (Map.Entry<String, String> entry : filters.entrySet()) {
    if (entry.getKey().equalsIgnoreCase("prodId")) {
        predicates.add(criteriaBuilder.equal(root.get(Product_.prodId), Long.parseLong(entry.getValue().trim())));
    } else if (entry.getKey().equalsIgnoreCase("prodName")) {
        predicates.add(criteriaBuilder.like(root.get(Product_.prodName), "%" + entry.getValue().trim() + "%"));
    } else if (entry.getKey().equalsIgnoreCase("marketPrice")) {
        predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(Product_.marketPrice), new BigDecimal(entry.getValue().trim())));
    } else if (entry.getKey().equalsIgnoreCase("salePrice")) {
        predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(Product_.salePrice), new BigDecimal(entry.getValue().trim())));
    } else if (entry.getKey().equalsIgnoreCase("quantity")) {
        predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(Product_.quantity), Integer.valueOf(entry.getValue().trim())));
    }
}

if (!predicates.isEmpty()) {
    criteriaQuery.where(predicates.toArray(new Predicate[0]));
}

Long count = entityManager.createQuery(criteriaQuery).getSingleResult();

In diesem Fall muss der Parameter aufprodName ist ein Parameter vom Typ String. Daher ist es automatisch an einen Positionsparameter gebunden?. Der Rest (Nicht-String-Typ) sind jedoch nicht. Sie alle werden nur durch ihre Werte ersetzt.

Sie müssen auf eingestellt seincreateQuery() indem man zum Beispiel

ParameterExpression<BigDecimal> exp=criteriaBuilder.parameter(BigDecimal.class);
entityManager.createQuery(criteriaQuery).setParameter(exp, new BigDecimal(1000));

Wie werden solche dynamischen Parameter so eingestellt, dass eine vorbereitete Abfrage generiert werden kann?

Dies ist in EclipseLink in der Tat nicht erforderlich, da sie automatisch Positionsparametern zugeordnet werden.

Kann dies mit dem Ruhezustand-Anbieter durchgeführt werden?

Ich verwende JPA 2.0 von Hibernate 4.2.7 final.

Wenn alle Parameter festgelegt sind, sieht die von der obigen Kriterienabfrage generierte Anweisung wie folgt aus.

SELECT count(product0_.prod_id) AS col_0_0_ 
FROM   projectdb.product product0_ 
WHERE  product0_.market_price >= 1000 
       AND ( product0_.prod_name LIKE ? ) 
       AND product0_.prod_id = 1 
       AND product0_.quantity >= 1 
       AND product0_.sale_price >= 1000 

Ich habe gerade die oben genannte Kriterienabfrage unter EclipseLink (2.3.2) ausgeführt, die zur Erstellung der folgenden SQL-Anweisung geführt hat.

SELECT count(prod_id) 
FROM   projectdb.product 
WHERE  ( ( ( ( ( market_price >= ? ) 
           AND prod_name LIKE ? ) 
         AND ( prod_id = ? ) ) 
       AND ( quantity >= ? ) ) 
     AND ( sale_price >= ? ) ) 

bind => [1000, %product1%, 1, 1, 1000]

eine parametrisierte Abfrage.

Das Folgende ist nicht möglich.

//...

TypedQuery<Long> typedQuery = entityManager.createQuery(criteriaQuery);

for (Map.Entry<String, String> entry : filters.entrySet()) {
    if (entry.getKey().equalsIgnoreCase("discountId")) {
        ParameterExpression<Long> parameterExpression = criteriaBuilder.parameter(Long.class);
        predicates.add(criteriaBuilder.equal(root.get(Discount_.discountId), parameterExpression));
        typedQuery.setParameter(parameterExpression, Long.parseLong(entry.getValue().trim()));
    }

    //...The rest of the if-else-if ladder.
}

//...
//...
//...
Long count = typedQuery.setFirstResult(first).setMaxResults(pageSize).getSingleResult();

Dies würde dazu führen, dassjava.lang.IllegalArgumentException: Name of parameter to locate cannot be null Ausnahme geworfen werden.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage