Ajude-me a entender onde usar um JOIN regular e onde um JOIN FETCH.
Por exemplo, se tivermos essas duas consultas
FROM Employee emp
JOIN emp.department dep
e
FROM Employee emp
JOIN FETCH emp.department dep
Existe alguma diferença entre eles? Se sim, qual usar quando?
Respostas:
Nessas duas consultas, você está usando JOIN para consultar todos os funcionários que possuem pelo menos um departamento associado.
Mas a diferença é: na primeira consulta, você está retornando apenas os funcionários do Hibernate. Na segunda consulta, você está retornando os Empregados e todos os Departamentos associados.
Portanto, se você usar a segunda consulta, não precisará fazer uma nova consulta para acessar o banco de dados novamente e ver os Departamentos de cada Funcionário.
Você pode usar a segunda consulta quando tiver certeza de que precisará do departamento de cada funcionário. Se você não precisar do departamento, use a primeira consulta.
Eu recomendo a leitura deste link se você precisar aplicar alguma condição WHERE (o que você provavelmente precisará): Como expressar corretamente o JPQL "junção de busca" com a cláusula "where" como JPA 2 CriteriaQuery?
Atualizar
Se você não usar
fetch
e os departamentos continuarem sendo devolvidos, é porque o seu mapeamento entre Funcionário e Departamento (a@OneToMany
) está definidoFetchType.EAGER
. Nesse caso, qualquerfetch
consulta HQL (com ou não)FROM Employee
trará todos os departamentos. Lembre-se de que todo o mapeamento * ToOne (@ManyToOne
e@OneToOne
) é EAGER por padrão.fonte
fetch
deve ser usado se (usando o nosso exemplo) você desejar solicitar por algum atributo do Departamento. Caso contrário, (válido pelo menos para o PG), você poderá obterERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
em este link eu mencionei antes sobre o comentário, leia esta parte:
este "JOIN FETCH" terá efeito se você tiver (fetch = FetchType.LAZY) a propriedade de uma coleção dentro da entidade (exemplo a seguir).
E é apenas o método de "quando a consulta deve acontecer". E você também deve saber isso :
quando a associação é buscada -> seu tipo "FETCH"
como é buscado -> Participar / selecionar / Subselecionar / Lote
No seu caso, o FETCH só terá efeito se você tiver um departamento como um conjunto dentro de Employee, algo parecido com isto na entidade:
quando você usa
você receberá
emp
eemp.dep
. quando você não usou a busca, ainda é possível obter,emp.dep
mas o hibernate processará outra seleção no banco de dados para obter esse conjunto de departamentos.portanto, é apenas uma questão de ajuste de desempenho: você deseja obter todos os resultados (você precisa ou não) em uma única consulta (busca ansiosa) ou deseja consultá-lo mais tarde quando precisar (busca lenta).
Use a busca ansiosa quando precisar obter pequenos dados com uma seleção (uma grande consulta). Ou use a busca lenta para consultar o que você precisa depois (muitas consultas menores).
use buscar quando:
nenhuma grande coleção / conjunto desnecessário dentro dessa entidade que você está prestes a receber
comunicação do servidor de aplicativos com o servidor de banco de dados longe demais e precisa de muito tempo
você pode precisar dessa coleção posteriormente quando não tiver acesso a ela ( fora do método / classe transacional )
fonte
List
vez de umSet
?FETCH
palavra - chave em uma instrução JPQL implica uma propriedade recuperada ansiosamente?JUNTE-SE
Ao usar
JOIN
contra associações de uma entidade, o JPA gerará uma JOIN entre as tabelas da entidade pai e da entidade filha na instrução SQL gerada.Então, tomando o seu exemplo, ao executar esta consulta JPQL:
O Hibernate irá gerar a seguinte instrução SQL:
JUNTE-SE À PESQUISA
Portanto, em comparação com
JOIN
, oJOIN FETCH
permite projetar as colunas da tabela de junção naSELECT
cláusula da instrução SQL gerada.Portanto, no seu exemplo, ao executar esta consulta JPQL:
O Hibernate irá gerar a seguinte instrução SQL:
Além disso,
JOIN FETCH
é uma ótima maneira de abordar a questãoLazyInitializationException
ao usar o Hibernate, pois você pode inicializar associações de entidades usando aFetchType.LAZY
estratégia de busca junto com a entidade principal que você está buscando.fonte
Se você tiver o
@oneToOne
mapeamento definidoFetchType.LAZY
e usar a segunda consulta (porque você precisa que os objetos do Departamento sejam carregados como parte dos objetos Employee), o que o Hibernate fará é, ele emitirá consultas para buscar objetos do Department para cada objeto Employee individual que busca no DB.Posteriormente, no código, você poderá acessar os objetos Department por meio da associação de valor único Employee to Department e o Hibernate não emitirá nenhuma consulta para buscar o objeto Department para o Employee em questão.
Lembre-se, o Hibernate ainda emite consultas iguais ao número de funcionários que buscou. O Hibernate emitirá o mesmo número de consultas nas duas perguntas acima, se você desejar acessar os objetos de departamento de todos os objetos de funcionários
fonte
Dherik: Não tenho certeza do que você diz, quando você não usa buscar, o resultado será do tipo: o
List<Object[ ]>
que significa uma lista de tabelas de objetos e não uma lista de funcionários.Quando você usa a busca, há apenas uma seleção e o resultado é a lista de Funcionários que
List<Employee>
contém a lista de departamentos. Substitui a declaração lenta da entidade.fonte
fetch
, sua consulta retornará apenas os funcionários. Se os departamentos, mesmo nesse caso, continuarem a ser devolvidos, é porque o mapeamento entre Funcionário e Departamento (um @OneToMany) está definido com FetchType.EAGER. Nesse caso, qualquerfetch
consulta HQL (com ou não)FROM Employee
trará todos os departamentos.@OneToMany(fetch = FetchType.EAGER
). Caso contrário, os departamentos não serão devolvidos.select
foi feito no HQL. TenteSELECT emp FROM Employee emp JOIN FETCH emp.department dep
. JPA / Hibernate tem esse comportamento de retornar umList
deObject[]
quando você omite aSELECT
peça.