有没有办法用计数查询包装CriteriaQuery?我的想法是创建一个从任何给定查询创建计数查询的函数。
例如在plane sql中:
SELECT
item_type,
count(*) AS lol
FROM inventory_movements
WHERE movement_date_time BETWEEN '2017-05-08 12:00:00' AND '2017-05-08 13:00:00'
GROUP BY item_type
我希望创建这样的东西(我知道在这个特定的查询中,一个不同的计数将解决问题,但我需要一个通用的解决方案,我想在非jpa托管返回类型查询中使用它进行分页): / p>
SELECT count(*)
FROM (
SELECT
item_type,
count(*) AS rand_
FROM inventory_movements
WHERE movement_date_time BETWEEN '2017-05-08 12:00:00' AND '2017-05-08 13:00:00'
GROUP BY item_type
) AS sub;
CriteriaQuery不是Expression的实例,因此无法在criteriaBuilder.count();
中使用然后我认为我可以将它转换为Subquery,因为CriteriaQuery和Subquery都实现了相同的接口,但是Subquery也实现了Expression。
但这不符合我的想法。这是我目前的非工作代码:
public <T>TypedQuery<Long> getCountQuery(CriteriaQuery<T> origQuery) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = cb.createQuery(Long.class);
Subquery<T> subQuery = (Subquery<T>) origQuery;
query.select(cb.count(subQuery));
return entityManager.createQuery(query);
}
我在运行时遇到以下异常:
java.lang.ClassCastException: org.hibernate.query.criteria.internal.CriteriaQueryImpl无法强制转换 到javax.persistence.criteria.Subquery
这在jpa / hibernate中是否可行?
答案 0 :(得分:1)
@PersistenceContext
private EntityManager em;
...
...
public Page<T1> findByParameters(P p) {
CriteriaQuery<T1> criteriaQuery = (CriteriaQuery<T1>) getEm().getCriteriaBuilder().createQuery(typeToken1.getRawType());
Root<T2> root = (Root<T2>) criteriaQuery.from(typeToken2.getRawType());
criteriaQuery = SpecificationBuilder.of().buildCriteriaQuery(p, root, criteriaQuery, criteriaBuilder);
TypedQuery<T1> query = getEm().createQuery(criteriaQuery);
query.setFirstResult(pageRequest.getPageNumber() * pageRequest.getPageSize());
query.setMaxResults(pageRequest.getPageSize());
Integer totoal = getTotal(criteriaQuery, (CriteriaQueryTypeQueryAdapter) query);
PageImpl<T1> page1 = new PageImpl<>(query.getResultList(), pageRequest, totoal);
return page1;
}
private Integer getTotal(CriteriaQuery<T1> criteriaQuery, CriteriaQueryTypeQueryAdapter query) throws NoSuchFieldException, IllegalAccessException {
String jql = getEm().createQuery(criteriaQuery.orderBy()).unwrap(Query.class).getQueryString();
Field f = CriteriaQueryTypeQueryAdapter.class.getDeclaredField("jpqlQuery");
f.setAccessible(true);
QueryImpl jpqlQuery = (QueryImpl) f.get(query);
Map<String, TypedValue> stringTypedValueMap = jpqlQuery.getQueryParameters().getNamedParameters();
String sql = getSql(jql);
sql = String.format("select count(*) from (%1$s) t", sql);
NativeQuery nativeQuery = (NativeQuery) getEm().createNativeQuery(sql);
int index = 1;
for (Iterator<Map.Entry<String, TypedValue>> iterator = stringTypedValueMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, TypedValue> next = iterator.next();
nativeQuery.setParameter(index, next.getValue().getValue());
index++;
}
return (Integer) nativeQuery.getSingleResult();
}
答案 1 :(得分:0)
default Long countByQueryEvent(QueryEvent event) {
EntityManager entityManager = event.getEntityManager();
Query query = event.getQuery();
org.hibernate.Query hqlQuery = query.unwrap(HibernateQuery.class).getHibernateQuery();
ASTQueryTranslatorFactory astQueryTranslatorFactory = new ASTQueryTranslatorFactory();
HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) entityManager.getEntityManagerFactory();
SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) hibernateEntityManagerFactory.getSessionFactory();
QueryTranslator queryTranslator = astQueryTranslatorFactory.createQueryTranslator("", hqlQuery.getQueryString(), EMPTY_MAP, sessionFactory, null);
queryTranslator.compile(EMPTY_MAP, false);
String queryString = "select count(*) from (" + queryTranslator.getSQLString() + ") t";
org.hibernate.Query countQuery = entityManager.createNativeQuery(queryString).unwrap(org.hibernate.Query.class);
ParameterTranslations parameterTranslations = queryTranslator.getParameterTranslations();
//is there any way to get all parameters with values?
// all parameters!!! not only provided by setParameter() method in Query
Map params;
try {
Field f = AbstractQueryImpl.class.getDeclaredField("namedParameters");
f.setAccessible(true);
params = (Map) f.get(hqlQuery);
} catch (NoSuchFieldException e) {
e.printStackTrace();
return null;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
for (Object param : parameterTranslations.getNamedParameterNames()) {
String paramString = (String) param;
final int[] positions =
parameterTranslations.getNamedParameterSqlLocations(paramString);
for (final int p : positions) {
countQuery.setParameter(p, ((TypedValue)params.get(paramString)).getValue(),
((TypedValue)params.get(paramString)).getType());
}
}
Object result = countQuery.uniqueResult();
if (result instanceof BigDecimal) {
return ((BigDecimal) result).longValue();
} else if (result instanceof BigInteger) {
return ((BigInteger) result).longValue();
} else {
throw new IllegalArgumentException("JDBC driver returned unsupported resultType from count.");
}
}