2016-06-29 41 views
9

Ho una classe , che contiene uno List<Hearing>, ognuno con un attributo Date.SELECT DISTINCT + ORDER BY in API JPA 2 Criteria

ho bisogno di selezionare tutte le Lawsuit s ordinata secondo la data della loro Hearing s

Ho un CriteriaQuery come

CriteriaBuilder   cb = em.getCriteriaBuilder(); 
CriteriaQuery<Lawsuit> cq = cb.createQuery(Lawsuit.class); 
Root<Lawsuit>   root = cq.from(Lawsuit.class); 

Io uso distinta per appiattire i risultati:

cq.select(root).distinct(true); 

I then joinLawsuit con Hearing

Join<Lawsuit, Hearing> hearing = root.join("hearings", JoinType.INNER); 

per creare Predicate s

predicateList.add(cb.isNotNull(hearing.<Date>get("date"))); 

e Order s:

orderList.add(cb.asc(hearing.<Date>get("date"))); 

Tutto funziona bene se evito distinct, ma se lo uso, si lamenta di non essere in grado di ordinare in base a campi che non si trovano in SELECT:

Caused by: org.postgresql.util.PSQLException: ERROR: for SELECT DISTINCT , ORDER BY expressions must appear in select list

Il List<Hearing> è già accessibile attraverso i Lawsuit classi restituito, così mi sono confuso: come dovrei aggiungerli alla lista di selezione?

+0

Beh, avete bisogno di una sub-select per l'elenco e allora forse si può mettere l'ordine nella sotto-selezione? Non ho tempo per guardarlo adesso. –

+0

Grazie @Nicholas; come faresti la query interiore con criteri API? –

+0

[Questa risposta] (http://stackoverflow.com/a/35915532/4754790) potrebbe essere utile. –

risposta

5

Ho scoperto la fonte del problema da qualche altra parte e risolverlo non ha reso necessario fare quanto richiesto nella domanda; come descritto in altre risposte, non dovrebbe essere necessario eseguire lo distinct qui.

Le righe duplicate originate da erronee left join s eseguite su collezioni (attributi dell'oggetto radice) anche se non sono stati stati utilizzati i predicati:

Join<Lawsuit, Witness> witnesses = root.join("witnesses", JoinType.LEFT); 
if (witnessToFilterWith!=null) { 
    predicateList.add(cb.equal(witnesses.<Long>get("id"),witnessToFilterWith.getId())); 
} 

Il join dovrebbe ovviamente essere eseguite come inner e solo se necessario:

if (witnessToFilterWith!=null) { 
    Join<Lawsuit, Witness> witnesses = root.join("witnesses", JoinType.INNER); 
    predicateList.add(cb.equal(witnesses.<Long>get("id"),witnessToFilterWith.getId())); 
} 

Quindi, se siete qui perché si sta ricevendo lo stesso problema, cerca il problema nei join.

0

È inoltre possibile de-duplicare tramite GROUP BY sulla base di primaria colonna chiave della tabella di root:

cq.groupBy(root.get("id")); // Assuming that Lawsuite.id is primary key column