2010-12-29 4 views
6

In questa query:Facendo riferimento a un campo alias in precedenza in una query criteri

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(???)); 

Come posso aggiungere il ORDER BY count DESC, riferendosi al "conteggio" definito nella clausola SELECT?

risposta

7

Che cosa succede se appena catturata l'espressione conteggio, e lo ha utilizzato direttamente?

Expression event_count = cb.count(gpe); 

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

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

Hai provato la creazione di una proiezione con un alias?

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

Questo è il Hibernate Criteria API. Questa domanda riguarda l'API dei criteri JPA 2 (ed è l'implementazione di Hibernate). Abbastanza confusamente, quelli non sono la stessa cosa. –

1

Anche se il libro Pro APP 2 descrive che il metodo alias può essere utilizzato per generare un alias query SQL (a pagina 251) non ho avuto successo con fare funzionare né con EclipseLink o Hibernate. Per la tua domanda, ti dirò che il tuo ordine deve essere letto:

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

se supportato dai diversi fornitori.

quanto riguarda la mia ricerca va cuciture che il metodo alias viene utilizzato solo per elementi del tuble utilizzato nel selezionare denominazione (in modo che solo per la proiezione).

Ho una domanda però. Perché dovresti voler utilizzare l'API dei criteri JPA per questa query. Le giunzioni (la query) sono di natura statica, quindi perché non utilizzare JPQL in cui è possibile definire direttamente gli alias della query.

0

mi sono imbattuto lo stesso problema di oggi, ma nessuna delle soluzioni proposte ha lavorato per me perché avevo bisogno di riutilizzare l'espressione non solo nella clausola order by ma anche nella clausola group by. Una soluzione ovvia sarebbe quella di creare una vista a livello di database, ma questo è un po 'maldestro, crea una subquery non necessaria e nemmeno impossibile se l'utente db non ha privilegi sufficienti. Una soluzione migliore che ho finito per attuare è quello di scrivere qualcosa di simile

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

Il primo aspetto negativo di questo approccio è che il codice è errorprone. L'altro svantaggio è che la query sql generata contiene la notazione di posizione ordinale, che funziona su alcuni database (come postgresql o mariadb) ma non funziona su altri (come il server sql). Nel mio caso, tuttavia, ho trovato che questa fosse l'opzione migliore.

provata su JPA 2.1 con Hibernate 5.2.3 come fornitore e PostgreSQL 9.6.

Problemi correlati