Autor
Mensagem
Salve galera!
Gostaria de saber de vcs qual a melhor opção de mapeamento em JPA
Collection, List ou Set
Realizando testes com JPA+Hibernate 3.5.0 Final descobri o seguinte:
Considerando as seguintes Entitys Class:
Pessoa (Pessoa possui uma lista de Email e Endereços)
Email
Endereco
Usando Set<>
1° Se eu uso Set<> com
#Código
fetch=FetchType.EAGER
nos mapeamentos funciona! Os seja, o metodo find do EntityManager traz os Sets preenchidos!2° Se eu uso Set<> com
#Código
fetch=FetchType.LAZY
nos mapeamentos o método find do EntityManager retorna o seguinte erro: #Código
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
3. Quando utilizo Set mesmo sem fazer
#Código
fetch=FetchType.EAGER
consigo fazer o seguinte jp ql:#Código
select p from Pessoa p
join fetch p.emailSet em
join fetch p.enderecoSet en
where p.pesId = 1
join fetch p.emailSet em
join fetch p.enderecoSet en
where p.pesId = 1
4. Outro problema que encontrei utilizando Set<> é o seguinte:
Set não aceita dados duplicados na lista como por exemplo uma lista de nomes:
Paulo
Paulo
Felipe
Se adiciono estes nomes em um Set os dados duplicados serão descartados ficando assim:
Paulo
Felipe
=====================================================================================
Usando List<>
1° Se eu uso List<> com
#Código
fetch=FetchType.EAGER
nos mapeamentos o método find do EntityManager retorna o seguinte erro:#Código
org.hibernate.HibernateException: cannot simultaneously fetch multiple bags
2° Se eu uso List<> com
#Código
fetch=FetchType.LAZY
nos mapeamentos o método find do EntityManager retorna o seguinte erro: #Código
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
3. Quando utilizo List de nenhuma maneira consigo fazer o seguinte jp ql:
#Código
select p from Pessoa p
join fetch p.emailList em
join fetch p.enderecoList en
where p.pesId = 1
join fetch p.emailList em
join fetch p.enderecoList en
where p.pesId = 1
pois tenho o seguinte erro:
#Código
org.hibernate.HibernateException: cannot simultaneously fetch multiple bags
4. Utilizando List eu consigo fazer o seguinte jp ql e funciona!
#Código
select p from Pessoa p join fetch p.emailList
Só não consigo entender porque funciona com Set e não Funciona com List alguem puder me explicar? Devo utilizar Collection, List ou Set? Onde estou me perdendo?
O problema do Lazy, é arquitetural,
é muito comum acontecer, talvez vc deva usar o Spring e sua entidade não tem nenhuma sessão aberta para vc simplesmente dar um get e ele abrir uma conexão do banco para fazer essa pesquisa sobe demanda.
Para sua lista de Set se for um objeto complexo (diferente de uma lista de String), vc deve sobrescrever o equals e o hashCode para um atributo q não se repete, como de repente vc pode usar o id. O nome pode se repetir.
Para os erros do List, eu teria que estar mais contextualizado, mas posso lhe adianta se nas classes envolvidas no mapeamente tiver muitos Eager, dá esse erro que vc citou. talvez sua classe só tenha um EAGER, mas se a classe que vc chamu tiver outros EAGER e ele e os EAGERs mais outros, assim o hibernate se perde.
Geralmente o que eu faço é deixar Eager quando realmente é útil e no serviço ao invez de recuperar via objeto.getSuaDependencia() e fugir do lazyException é chamar via um serviço, por exemplo:
service.recuperaDependenciasObjeto(objeto)... e por aí vai.
Espero ter dado alguma luz
Att Davi
é muito comum acontecer, talvez vc deva usar o Spring e sua entidade não tem nenhuma sessão aberta para vc simplesmente dar um get e ele abrir uma conexão do banco para fazer essa pesquisa sobe demanda.
Para sua lista de Set se for um objeto complexo (diferente de uma lista de String), vc deve sobrescrever o equals e o hashCode para um atributo q não se repete, como de repente vc pode usar o id. O nome pode se repetir.
Para os erros do List, eu teria que estar mais contextualizado, mas posso lhe adianta se nas classes envolvidas no mapeamente tiver muitos Eager, dá esse erro que vc citou. talvez sua classe só tenha um EAGER, mas se a classe que vc chamu tiver outros EAGER e ele e os EAGERs mais outros, assim o hibernate se perde.
Geralmente o que eu faço é deixar Eager quando realmente é útil e no serviço ao invez de recuperar via objeto.getSuaDependencia() e fugir do lazyException é chamar via um serviço, por exemplo:
service.recuperaDependenciasObjeto(objeto)... e por aí vai.
Espero ter dado alguma luz
Att Davi
Olá Rogerio
concordo com a resposta do Davi está excelente.
com relação a sua ultima query postada o erro dela me parece que o seu provedor de persistencia não deixa fazer esses 2 join teste colocando virgula entre eles ou na anotação de 1 desses atributos eu colocaria fetch=FetchType.EAGER para trazer os e-mails ou endereços.
att
robson
concordo com a resposta do Davi está excelente.
com relação a sua ultima query postada o erro dela me parece que o seu provedor de persistencia não deixa fazer esses 2 join teste colocando virgula entre eles ou na anotação de 1 desses atributos eu colocaria fetch=FetchType.EAGER para trazer os e-mails ou endereços.
att
robson








