Por favor, ayúdame a entender dónde usar un JOIN regular y dónde un JOIN FETCH.
Por ejemplo, si tenemos estas dos consultas
FROM Employee emp
JOIN emp.department dep
y
FROM Employee emp
JOIN FETCH emp.department dep
¿Hay alguna diferencia entre ellos? En caso afirmativo, ¿cuál usar cuando?
Respuestas:
En estas dos consultas, está utilizando JOIN para consultar a todos los empleados que tienen al menos un departamento asociado.
Pero, la diferencia es: en la primera consulta, solo está devolviendo los Empleados para Hibernate. En la segunda consulta, está devolviendo los Empleados y todos los Departamentos asociados.
Por lo tanto, si usa la segunda consulta, no necesitará hacer una nueva consulta para volver a acceder a la base de datos para ver los departamentos de cada empleado.
Puede usar la segunda consulta cuando esté seguro de que necesitará el Departamento de cada Empleado. Si no necesita el Departamento, use la primera consulta.
Recomiendo leer este enlace si necesita aplicar alguna condición WHERE (lo que probablemente necesitará): ¿Cómo expresar adecuadamente JPQL "join fetch" con la cláusula "where" como JPA 2 CriteriaQuery?
Actualizar
Si no usa
fetch
y los departamentos continúan devolviéndose, es porque su asignación entre Empleado y Departamento (a@OneToMany
) está configurada conFetchType.EAGER
. En este caso, cualquier consulta HQL (confetch
o no) conFROM Employee
traerá todos los departamentos. Recuerde que todas las asignaciones * ToOne (@ManyToOne
y@OneToOne
) son EAGER por defecto.fuente
fetch
debe usarse si (usando nuestro ejemplo) desea ordenar por algún atributo de Departamento. De lo contrario, (válido al menos para PG) que podría obtenerERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
en este enlace que mencioné antes en el comentario, lea esta parte:
este "JOIN FETCH" tendrá efecto si tiene la propiedad (fetch = FetchType.LAZY) para una colección dentro de la entidad (ejemplo a continuación).
Y solo tiene efecto el método de "cuándo debe ocurrir la consulta". Y también debes saber esto :
cuándo se obtiene la asociación -> su tipo "FETCH"
cómo se obtiene -> Unir / seleccionar / Subseleccionar / Lote
En su caso, FETCH solo tendrá efecto si tiene un departamento como conjunto dentro de Employee, algo así en la entidad:
cuando usas
obtendrás
emp
yemp.dep
. cuando no usó fetch todavía puede obtener,emp.dep
pero hibernate procesará otra selección en la base de datos para obtener ese conjunto de departamentos.así que es solo una cuestión de ajuste de rendimiento, acerca de si desea obtener todos los resultados (lo necesita o no) en una sola consulta (búsqueda ansiosa), o desea consultarlo más tarde cuando lo necesite (recuperación perezosa).
Use la búsqueda entusiasta cuando necesite obtener datos pequeños con una selección (una consulta grande). O use la recuperación lenta para consultar lo que necesita más tarde (muchas consultas más pequeñas).
use fetch cuando:
no hay una gran colección / conjunto innecesario dentro de esa entidad que está a punto de obtener
comunicación del servidor de aplicaciones al servidor de la base de datos demasiado lejos y necesita mucho tiempo
es posible que necesite esa colección más tarde cuando no tiene acceso a ella ( fuera del método / clase transaccional )
fuente
List
lugar de unSet
?FETCH
palabra clave en una declaración JPQL implica una propiedad recuperada con entusiasmo?UNIRSE
Cuando se utiliza
JOIN
contra las asociaciones de una entidad, JPA generará una UNIÓN entre la entidad principal y las tablas de la entidad secundaria en la instrucción SQL generada.Entonces, tomando su ejemplo, al ejecutar esta consulta JPQL:
Hibernate va a generar la siguiente instrucción SQL:
ÚNETE A FETCH
Entonces, en comparación con
JOIN
, leJOIN FETCH
permite proyectar las columnas de la tabla de unión en laSELECT
cláusula de la instrucción SQL generada.Entonces, en su ejemplo, al ejecutar esta consulta JPQL:
Hibernate va a generar la siguiente instrucción SQL:
Además,
JOIN FETCH
es una excelente manera de abordar el problemaLazyInitializationException
al utilizar Hibernate, ya que puede inicializar asociaciones de entidades utilizando laFetchType.LAZY
estrategia de recuperación junto con la entidad principal que está recuperando.fuente
Si tiene
@oneToOne
configurado el mapeoFetchType.LAZY
y usa una segunda consulta (porque necesita que los objetos de Departamento se carguen como parte de los objetos de Empleado), lo que Hibernate hará es emitir consultas para recuperar objetos de Departamento para cada objeto de Empleado individual que recupere de DB.Más tarde, en el código, puede acceder a los objetos del Departamento a través de la asociación de un solo valor Empleado a Departamento e Hibernate no emitirá ninguna consulta para obtener el objeto Departamento para el Empleado dado.
Recuerde, Hibernate sigue emitiendo consultas iguales al número de empleados que ha obtenido. Hibernate emitirá el mismo número de consultas en las dos consultas anteriores, si desea acceder a los objetos del Departamento de todos los objetos de Empleado
fuente
Dherik: No estoy seguro de lo que dices, cuando no uses fetch, el resultado será de tipo: lo
List<Object[ ]>
que significa una lista de tablas de Objetos y no una lista de Empleados.Cuando usa fetch, solo hay una selección y el resultado es la lista de Empleados que
List<Employee>
contiene la lista de departamentos. Anula la declaración perezosa de la entidad.fuente
fetch
, su consulta devolverá solo los empleados. Si los departamentos, incluso en este caso, continúan siendo devueltos, es porque su asignación entre Empleado y Departamento (un @OneToMany) está configurada con FetchType.EAGER. En este caso, cualquier consulta HQL (confetch
o no) conFROM Employee
traerá todos los departamentos.@OneToMany(fetch = FetchType.EAGER
). Si no es el caso, los departamentos no serán devueltos.select
se hizo en HQL. TratarSELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate tiene este comportamiento de retorno de unaList
deObject[]
cuando ommit laSELECT
parte.