Dúvida Collections para Mapeamento em JPA
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 nos mapeamentos funciona! Os seja, o metodo find do EntityManager traz os Sets preenchidos!
2° Se eu uso Set<> com nos mapeamentos o método find do EntityManager retorna o seguinte erro:
3. Quando utilizo Set mesmo sem fazer consigo fazer o seguinte jp ql:
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 nos mapeamentos o método find do EntityManager retorna o seguinte erro:
2° Se eu uso List<> com nos mapeamentos o método find do EntityManager retorna o seguinte erro:
3. Quando utilizo List de nenhuma maneira consigo fazer o seguinte jp ql:
pois tenho o seguinte erro:
4. Utilizando List eu consigo fazer o seguinte jp ql e funciona!
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?
Considerando as seguintes Entitys Class:
Pessoa (Pessoa possui uma lista de Email e Endereços)
Endereco
Usando Set<> 1° Se eu uso Set<> com
fetch=FetchType.EAGER
2° Se eu uso Set<> com
fetch=FetchType.LAZY
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
3. Quando utilizo Set mesmo sem fazer
fetch=FetchType.EAGER
select p from Pessoa p 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
fetch=FetchType.EAGER
org.hibernate.HibernateException: cannot simultaneously fetch multiple bags
2° Se eu uso List<> com
fetch=FetchType.LAZY
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
3. Quando utilizo List de nenhuma maneira consigo fazer o seguinte jp ql:
select p from Pessoa p join fetch p.emailList em join fetch p.enderecoList en where p.pesId = 1
pois tenho o seguinte erro:
org.hibernate.HibernateException: cannot simultaneously fetch multiple bags
4. Utilizando List eu consigo fazer o seguinte jp ql e funciona!
select p from Pessoa p join fetch p.emailList
Rogério Martins
Curtidas 0
Respostas
Davi Costa
08/02/2011
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
GOSTEI 0
Dyego Carmo
08/02/2011
Sugiro sempre List,
Lembrando que o Hibernate tem uma serie de "dores de barriga" com coleções complexas...
Principalmente aquelas do tipo LAZY dentro de updates (em.merge())...
Problemas arquiteturais e que a super "JBoss" se recusa a aceitar como BUG.
Mas a resposta do davi esta bem consistente.
Lembrando que o Hibernate tem uma serie de "dores de barriga" com coleções complexas...
Principalmente aquelas do tipo LAZY dentro de updates (em.merge())...
Problemas arquiteturais e que a super "JBoss" se recusa a aceitar como BUG.
Mas a resposta do davi esta bem consistente.
GOSTEI 0
Rogério Martins
08/02/2011
Tudo bem, qual seria a solução para o jp ql abaixo:
select p from Pessoa p join fetch p.emailList em join fetch p.enderecoList en where p.pesId = 1
GOSTEI 0
Robson Teixeira
08/02/2011
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
GOSTEI 0