eu tenho uma classe que contém uma propriedade que é um list de enums.
public class Usuario() {
...
private List<Perfil> perfis;
...
}
Onde Perfil é um enum.
Agora para tornar a query mais performatica eu estou tentando fazer a query com um left join para que o JPA já traga os usuários já com a associação preenchida, mas não estou conseguindo.
Eu tentei dessa forma:
e também dessa:
Porém a primeira retornou usuários repetidos (se o usuário tem 2 perfis ele aparecia 2 vezes, se tem 3 aparece 3 vezes no resultado e assim por diante).
E a segunda query não retornou nenhum resultado :?
Bem, não parei para analisar a query pq iria ter que ver a estrutura das tabelas. Mas vc pode trocar de List<> para Set<> .
Ele vai eliminar os objetos repetidos.
Apenas se lembre de criar hashCode() e equals() na sua classe.
=D
B
brunoskrebs
obrigado pela resposta, porém não é a solução. o problema não está em ter perfis repetidos para um usuário e sim no fato de as duas consultas que eu apresentei não estarem retornado o esperado.
e o esperado no caso era um usuário com seus devidos perfis.
eu consigo isso com
e depois acessando os perfis através de u.getPerfis(). Porém isso resulta em mais acessos ao banco para retornar os perfis de cada usuário que eu listo, e isso no caso se torna muito oneroso.
e por fim, para analisar a query nao teria que analisar estrutura das tabelas levando em conta que eu uso jpql (sql orientado a objetos). mas de qualquer forma segue a minha classe Usuário com a sua associação com o enum Perfil:
Você pode procurar por outras alternativas como marcar relacionamentos como LAZY ou ao invés de utilizar from (onde todo o grafo do objeto é recuperado) utilizar um construtor na query (select new)…
D
derlon
brunoskrebs:
select u from Usuario u left join u.perfis perfis group by u.nome order by u.nome…
E a segunda query não retornou nenhum resultado :?
…
@brunoskrebs,
Vc não nos informou q BD vc usa. Ah, e pq q vc num coloca -> ‘showSql=true’??!
Se for Oracle, p/ex., ele exige q todos os Campos q estejam no GroupBy tem q estar no Select, tb sacou??!
B
brunoskrebs
Acredito que não seja esse o problema considerando que no JPQL “select u from Usuario u” corresponde a “select * from usuario”. Mas sim eu uso Oracle.
E sobre o ganho de performance, eu prefiro que o meu aplicativo faça apenas 1 consulta no banco de dados que retorne os usuários já com seus devidos perfis do que faça 1 + n consultas para retornar os perfis. Imaginem se eu listo seila 50 usuários, são 51 consultas contra 1 consulta possível…
Eu vou fazer mais algumas tentativas num futuro bem próximo, no momento estou fazendo um outro requisito. Mas se eu obtiver sucesso posto a forma aqui.
Valeu!
Hebert_Coelho
Vc pode tentar usar então o lazy load. Por default é false, se vc setar true, ele vai buscar todo mundo. Eu sei que tem como usar com o hibernate, não sei para JDBC ou outras camadas de acesso a banco.
O lazy load tem seu conceito de “Não carregue se não precisar”, por isso seu valor default é false. No caso, quando vc colocar true, para os perfis, ele vai carregar todo mundo.
Dá uma olhada para adaptar isso ao seu projeto. Nesse caso ele irá trazer toda sua lista de perfis quando vc buscar pelos usuários! [=
B
brunoskrebs
jakefrog, eu sei sobre o lazy loading, na verdade setar o fetch type dessa associação não irá me adiantar, pois:
1 - todas as vezes que eu carregar um usuário ele já vai carregar os perfis. e eu não quero isso, quero que a minha consulta especifica para trazer usuários com perfis faça isso, com um só select ao banco de dados.
2 - o fetchtype eager não vai fazer com que apenas um select traga os usuários com seus devidos perfis.
e sobre usar lazy load, isso não funciona assim no jdbc pois no jdbc tu faz essas associações, e cria os objetos “na mão”…
B
brunoskrebs
a propósito o lazy loading é o padrão, oq não é padrão é o eager, esse sim traz toda a coleção sempre que você trouxer um entidade…
B
breno500as
Apenas com JDBC não tem como …
Todas as vezes que você carregar um Usuario os Perfis serão carregados se o relacionamento não estiver marcado como LAZY … Você tem que entender que se você marcar Perfis como LAZY e fizer um from na tabela de Usuario, não será feito um select na tabela de Perfis.
Aí vai depender das suas regras de négocio… Independente de como estiver marcado(EAGER ou LAZY) o relacionamento, se você sempre precisar buscar um Perfil para um Usuario logicamente sempre será feito mais de um select no banco de dados… O que você pode fazer é adiar essa busca marcando o relacionamento como LAZY, e quando você achar necessário acessar os Perfis (claro que você deve acessa-los antes da sua Session ser fechada para o Hibernate através do Proxy
fazer o select de busca dos perfis).
Correto, o EAGER irá fazer um select tbm na tabela de perfis (caso você faça um from em Usuario) …
Você está errado … O padrão ou default em um relacionamento é o EAGER, para mais detalhes consulte a documentação …
Consultando a documentação. Como eu disse o default é o LAZY.
B
breno500as
Tem razão… Vi agora que você está utilizando a anotação @CollectionOfElements e que o default é realmente LAZY …
B
brunoskrebs
na verdade não só o @collectionofelements mas como o hibernate utiliza o lazy por default nas collections…
D
derlon
brunoskrebs:
…Consultando a documentação. Como eu disse o default é o LAZY.
Obs.: o tipo default de Loading vai depender do tipo de Relacionamento (cardinalidade, etc.). @brunoskrebs,
Em vez de usar JPAQL, pq q vc não usa ‘Criteria’ q, além de ser muito + fácil de usar (e + OO), ainda vc pode definir o tipo de FetchMode (Eager ou Lazy) q quiser?!! :idea: