2010-12-29 5 views
6

En esta consulta:referencia a un campo de alias anteriormente en una consulta criterios

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Tuple> q = cb.createTupleQuery(); 

// FROM GamePlayedEvent gpe 
Root<GamePlayedEvent> gpe = q.from(GamePlayedEvent.class); 
// SELECT gameId, COUNT(*) AS count, AVG(duration) 
// AS avDur, AVG(rewardCurrency) AS avCur, AVG(rewardXP) avXp 
q.select(cb.tuple(
    gpe.<String>get("gameId"), 
    cb.count(gpe).alias("count"), 
    cb.avg(gpe.<Double>get("duration")).alias("avDur"), 
    cb.avg(gpe.<Integer>get("rewardCurrency")).alias("avCur"), 
    cb.avg(gpe.<Integer>get("rewardXp")).alias("avXp") 
)); 
// WHERE loginTime BETWEEN ... 
q.where(cb.between(gpe.<Date>get("time"), fromTime, toTime)); 
// GROUP BY gameId 
q.groupBy(gpe.<String>get("gameId")); 
// ORDER BY count DESC 
q.orderBy(cb.desc(???)); 

¿Cómo puedo añadir el ORDER BY count DESC, en referencia a la "cuenta" se define en la cláusula SELECT?

Respuesta

7

¿Qué pasa si acaba de capturar la expresión de conteo y la utiliza directamente?

Expression event_count = cb.count(gpe); 

q.select(cb.tuple( 
    gpe.<String>get("gameId"), 
    event_count, 
    ... 
)); 

q.orderBy(cb.desc(event_count)); 
0

¿Ha intentado configurar una proyección con un alias?

criteria.setProjection(Projections.projectionList() 
    .add(Projections.count("item.id"), "countItems")); 
criteria.addOrder(Order.desc("countItems")); 
+0

Esa es la API de criterios de Hibernate. Esta pregunta es acerca de la API de criterios de JPA 2 (y su implementación de Hibernate). De manera bastante confusa, esos no son lo mismo. –

1

A pesar de que la APP Pro 2 libro describe que el método alias puede ser utilizado para generar un alias de consulta SQL (en la página 251) que no han tenido éxito con lo que es trabajar con ninguno EclipseLink o hibernación. Por su pregunta, diría que su línea orderBy debe decir:

q.orderBy(cb.desc(cb.count(gpe)); 

si fue apoyada por los diferentes proveedores.

Por lo que respecta a mi investigación, el método de alias solo se usa para nombrar elementos en la tublea utilizada en la selección (solo para proyección).

Tengo una pregunta sin embargo. ¿Por qué querrías usar la API de criterios de JPA para esta consulta? (La consulta) parece ser de naturaleza estática, ¿por qué no usar JPQL donde puede definir sus alias de consulta directamente?

0

me encontré con el mismo problema hoy, pero ninguna de las soluciones sugeridas trabajó para mí porque tenía que volver a utilizar la expresión no sólo en la cláusula order by sino también en la cláusula group by. Una solución obvia sería crear una vista en el nivel de la base de datos, pero esto es un poco torpe, crea una subconsulta innecesaria e incluso no es posible si el usuario db no tiene suficientes privilegios. Una mejor opción, que terminé de aplicación es escribir algo como esto

q.select(cb.tuple( 
    gpe.<String>get("gameId"), 
    cb.count(gpe), 
    ... 
)).groupBy(cb.literal(2)).orderBy(cb.literal(2)); 

La primera desventaja de este enfoque es que el código es errorprone. El otro inconveniente es que la consulta SQL generada contiene notación de posición ordinal, que funciona en algunas bases de datos (como postgresql o mariadb) pero no funciona en otras (como el servidor sql). En mi caso, sin embargo, encontré que esta es la mejor opción.

Probado en jpa 2.1 con hibernación 5.2.3 como proveedor y postgresql 9.6.

Cuestiones relacionadas