2011-12-15 9 views
11

Tengo varias entidades que se consultan a través de la consulta de criterios JPA2.Cómo recuperar todos los datos en una consulta

soy capaz de unirse a dos de estas entidades y obtener el resultado a la vez:

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

entonces trato de unirse a una tabla adicional de esa manera:

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

me sale el siguiente error :

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] 

¿Cómo puedo decirle a JPA/Hibernate, que debe seleccionar todas las entidades a la vez?

Respuesta

6

No es lo que viene a JPA, puede cadena de unirse a recuperaciones en consultas de la API Criteria (cita de especificación):

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.

Y tampoco se admite en las consultas 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 parece posible: Hibernate documentation EclipseLink no proporciona dicha extensión, por lo que la sintaxis de la siguiente consulta es aceptada por Hibernate, pero no por EclipseLink:

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

En EclipseLink, lo mismo se puede hacer a través de query hints.

11

Con JPA 'algunos dialectos de JPA' puede encadenar las incorporaciones, pero no creo que pueda/deba hacer una combinación y una búsqueda conjunta.

Por ejemplo, si tenemos una Program que tiene una relación de uno a muchos a un Reward que tiene una relación con un Duration, la siguiente JPQL obtendría una instancia específica con las recompensas y la duración pre-descabellada:

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

} 

Con el código criterios equivalentes:

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

Tenga en cuenta que las variables intermedias recompensa y la duración no son necesarios aquí, pero son adentra con fines informativos. root.fetch("rewards", JoinType.LEFT).fetch("duration", JoinType.LEFT) tendría el mismo efecto.

+0

Funciona debido a las extensiones de proveedor en algunas implementaciones (como Hibernate, por ejemplo). En JPA en general, esta consulta JPQL no funciona, porque tal encadenamiento y alias en este caso no son necesarios para ser compatibles según la especificación. –

+1

Gracias por la aclaración Mikko. Es bastante desagradable que esas extensiones se activen silenciosamente, así que las usas sin realmente darte cuenta. –

+0

Gracias hasta ahora. El uso de buscar sin usar una combinación antes resuelve el problema. Sin embargo, me gustaría poner un predicado en la tabla unida. ¿Cómo podría hacer eso? Antes estaba usando la siguiente construcción: Unir ladung = from.join ("ladung"); ladung.get ("fzadresse"). In (adressen); – Stinnux

Cuestiones relacionadas