2011-12-15 16 views
11

Ho più entità che vengono interrogate tramite la query criteri JPA2.Come recuperare tutti i dati in una query

sono in grado di unire due di queste entità e ottenere il risultato in una sola volta:

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); 
CriteriaQuery<LadungRgvorschlag> criteriaQuery = criteriaBuilder.createQuery(LadungRgvorschlag.class); 
Root<LadungRgvorschlag> from = criteriaQuery.from(LadungRgvorschlag.class); 
Join<Object, Object> ladung = from.join("ladung"); 

from.fetch("ladung", JoinType.INNER); 

poi cerco di aderire a una tabella aggiuntiva del genere:

ladung.join("ladBerechnet"); 
ladung.fetch("ladBerechnet", JoinType.LEFT); 

ottengo il seguente errore :

org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias3,role=null,tableName=ladberechnet,tableAlias=ladberechn3_,origin=ladungen ladung1_,columns={ladung1_.id ,className=de.schuechen.beans.tms.master.LadBerechnet}}] [select generatedAlias0 from de.schuechen.beans.tms.master.LadungRgvorschlag as generatedAlias0 inner join generatedAlias0.ladung as generatedAlias1 inner join generatedAlias1.ladBerechnet as generatedAlias2 left join fetch generatedAlias1.ladBerechnet as generatedAlias3 inner join fetch generatedAlias0.ladung as generatedAlias4 where (generatedAlias0.erledigt is null) and (generatedAlias0.belegart in (:param0, :param1)) and (generatedAlias1.fzadresse in (:param2, :param3)) and (generatedAlias1.zudatum<=:param4) and (1=1) order by generatedAlias0.belegart asc, generatedAlias1.fzadresse asc, generatedAlias1.zudatum asc, generatedAlias1.zulkw asc] 

come posso dire JPA/Hibernate, che dovrebbe selezionare tutte le entità in una volta?

risposta

6

Non quello che si tratta di APP, è possibile catena di aderire recupera nelle query Criteri API (citazione da specifica):

An association or attribute referenced by the fetch method must be referenced from an entity or embeddable that is returned as the result of the query. A fetch join has the same join semantics as the corresponding inner or outer join, except that the related objects are not top-level objects in the query result and cannot be referenced elsewhere by the query.

E non è anche supportato nelle query JPQL:

The association referenced by the right side of the FETCH JOIN clause must be an association or element collection that is referenced from an entity or embeddable that is returned as a result of the query.

It is not permitted to specify an identification variable for the objects referenced by the right side of the FETCH JOIN clause, and hence references to the implicitly fetched entities or elements cannot appear elsewhere in the query.

Con HQL sembra possibile: Hibernate documentation EclipseLink non fornisce tale estensione, quindi la sintassi della seguente query è accettata da Hibernate, ma non da EclipseLink:

SELECT a FROM A a LEFT JOIN FETCH a.bb b LEFT JOIN FETCH b.cc 

In EclipseLink lo stesso può essere fatto tramite query hints.

11

Con JPA 'alcuni dialetti di JPA' è possibile concatenare i recuperi a catena, ma non penso che si possa/dovrebbe fare sia un join che un join fetch.

Per esempio, se abbiamo un Program che ha una relazione uno-a-molti per un Reward che ha una relazione con un Duration, il seguente JPQL otterrebbe una specifica istanza con le ricompense e la durata pre-inverosimile:

SELECT DISTINCT 
    program 
FROM 
    Program _program 
     LEFT JOIN FETCH 
    _program.rewards _reward 
     LEFT JOIN FETCH 
    _reward.duration _duration 
WHERE 
    _program.id = :programId 

} 

Con il codice criteri equivalenti:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Program> criteriaQuery = criteriaBuilder.createQuery(Program.class); 
Root<Program> root = criteriaQuery.from(Program.class); 

Fetch<Program, Reward> reward = root.fetch("rewards", JoinType.LEFT); 
Fetch<Reward, Duration> duration = reward.fetch("duration", JoinType.LEFT); 

criteriaQuery.where(criteriaBuilder.equal(root.get("id"), programId)); 

TypedQuery<program> query = entityManager.createQuery(criteriaQuery); 

return query.getSingleResult(); 

si noti che le variabili ricompensa e durata intermedia non sono necessari qui, ma sono sporge a scopo informativo. root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT) avrebbe lo stesso effetto.

+0

Funziona a causa di estensioni del fornitore in alcune implementazioni (come ad esempio Hibernate). In JPA, in generale, questa query JPQL non funziona, poiché non è necessario che tale catena e alias in questo caso siano supportati secondo le specifiche. –

+1

Grazie per il chiarimento Mikko. È piuttosto brutto che tali estensioni vengano attivate silenziosamente, quindi le usi senza rendertene conto. –

+0

Grazie finora. Utilizzare il recupero senza utilizzare un join prima di risolvere il problema. Tuttavia, vorrei mettere un predicato sulla tabella unita. come potrei farlo? Prima di utilizzare il seguente costrutto: Unire ladung = from.join ("ladung"); ladung.get ("fzadresse"). In (indirizzo); – Stinnux

Problemi correlati