Utilizzando l’API dei criteri JPA, è ansible eseguire un join di recupero che risulta in un solo join?

Utilizzo di JPA 2.0. Sembra che per impostazione predefinita (nessun recupero esplicito), i @OneToOne(fetch = FetchType.EAGER) vengano recuperati nelle query 1 + N, dove N è il numero di risultati che contiene un’entity framework che definisce la relazione con un’ quadro correlata distinta. Utilizzando l’API Criteria, potrei provare ad evitarlo come segue:

 CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(MyEntity.class); Root root = query.from(MyEntity.class); Join join = root.join("relatedEntity"); root.fetch("relatedEntity"); query.select(root).where(builder.equals(join.get("id"), 3)); 

Quanto sopra dovrebbe essere idealmente equivalente al seguente:

 SELECT m FROM MyEntity m JOIN FETCH myEntity.relatedEntity r WHERE r.id = 3 

Tuttavia, l’interrogazione dei criteri determina il fatto che la tabella radice viene aggiunta in modo inutile alla tabella delle quadro correlate due volte; una volta per il recupero, e una volta per il predicato di dove. L’SQL risultante assomiglia a qualcosa del genere:

 SELECT myentity.id, myentity.attribute, relatedentity2.id, relatedentity2.attribute FROM my_entity myentity INNER JOIN related_entity relatedentity1 ON myentity.related_id = relatedentity1.id INNER JOIN related_entity relatedentity2 ON myentity.related_id = relatedentity2.id WHERE relatedentity1.id = 3 

Ahimè, se faccio solo il recupero, quindi non ho un’espressione da usare nella clausola where.

Mi manca qualcosa o si tratta di una limitazione dell’API dei criteri? Se è il secondo, viene risolto questo problema in JPA 2.1 o esistono miglioramenti specifici del fornitore?

Altrimenti, sembra preferibile rinunciare al controllo del tipo in fase di compilazione (mi rendo conto che il mio esempio non usa il metamodello) e usare la dynamic di JPQL TypedQueries.

Invece di root.join(...) puoi usare root.fetch(...) che restituisce Fetch<> object.

Fetch<> è discendente di Join<> ma può essere usato in modo simile.

Devi solo lanciare Fetch<> to Join<> dovrebbe funzionare per EclipseLink e Hibernate

 ... Join join = (Join)root.fetch("relatedEntity"); ... 

A partire da JPA 2.1 è ansible utilizzare grafici di quadro dinamiche per questo. Rimuovi il tuo recupero e specifica un grafico di quadro come segue:

 CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(MyEntity.class); Root root = query.from(MyEntity.class); Join join = root.join("relatedEntity"); query.select(root).where(builder.equals(join.get("id"), 3)); EntityGraph fetchGraph = entityManager.createEntityGraph(MyEntity.class); fetchGraph.addSubgraph("relatedEntity"); entityManager.createQuery(query).setHint("javax.persistence.loadgraph", fetchGraph); 

L’utilizzo di root.fetch() su EclipseLink creerà un SQL con INNER JOIN perché ha 3 tipi e il valore predefinito è INNER.

 INNER, LEFT, RIGHT; 

Il suggerimento è usare CreateQuery.

 TypedQuery typedQuery = entityManager.createQuery(query); 

MODIFICA: puoi trasmettere la radice a Da in questo modo:

 From join = (From) root.fetch("relatedEntity");