Jak dynamicznie ustawić parametry pozycyjne / nazwane na kwerendę kryteriów JPA?
Dostawca Hibernate nie generuje przygotowanej instrukcji dlanon-string wpisz parametry, chyba że są ustawioneentityManager.createQuery(criteriaQuery).setParameter(Parameter p, T t);
domyślnie wykonane przez EclipseLink.
W jaki sposób ustawić takie parametry, jeśli są dostarczane dynamicznie w czasie wykonywania. Na przykład,
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();
W tym przypadku parametr toprodName
jest parametrem typu String. Dlatego jest on automatycznie powiązany z parametrem pozycyjnym?
. Reszta (typ bez ciągów) nie są. Wszystkie są po prostu zastępowane przez ich wartości.
Muszą być ustawione nacreateQuery()
za pomocą, na przykład,
ParameterExpression<BigDecimal> exp=criteriaBuilder.parameter(BigDecimal.class);
entityManager.createQuery(criteriaQuery).setParameter(exp, new BigDecimal(1000));
Jak ustawić takie dynamiczne parametry, aby można było wygenerować przygotowane zapytanie?
Nie jest to wymagane w EclipseLink, gdzie są one automatycznie mapowane na parametry pozycyjne.
Czy można to zrobić z dostawcą Hibernate?
Używam JPA 2.0 dostarczonego przez Hibernate 4.2.7 final.
Jeśli wszystkie parametry zostaną ustawione, instrukcja wygenerowana przez zapytanie o powyższe kryteria będzie wyglądać tak, jak pokazano poniżej.
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
Właśnie uruchomiłem powyższą kwerendę kryteriów w EclipseLink (2.3.2), w wyniku której powstała następująca instrukcja SQL.
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]
tj. sparametryzowane zapytanie.
Takie postępowanie nie jest możliwe.
//...
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();
Spowodowałoby tojava.lang.IllegalArgumentException: Name of parameter to locate cannot be null
wyjątek do rzucenia.