vRaptor - falhar ao recuperar objeto do banco [RESOLVIDO]

Olá amigos,

estou com o problema de que quando minha aplicação executa o método abaixo para recuperar uma cidade pelo id:

CidadeDao.java... public Cidade consultar(Long id){ Cidade cidade = (Cidade) this.session.load(Cidade.class, id); return cidade; } ...
ao debugar cidade vejo que o conteúdo retornado é este:

(objeto expandido) cidade = Cidade_$$_javassist_5 (id=141) estado = null (objeto a expandir) handler = JavassistLazyInitializer (id=148) id = null nome = null
(Obs.: estava funcionando e de repente parou, mas recuperando outros tipos de objetos funciona normalmente)

No console do Eclipse não mostra o sql da consulta!

Alguém sabe porque a cidade não está sendo recuperada?

apenas para complementar…

o método consultarPorNome funciona, mas o consultar (por id) não funciona…

... public Cidade consultarPorNome(String nome){ return (Cidade) this.session.createCriteria(Cidade.class).add(Restrictions.ilike("nome", nome, MatchMode.ANYWHERE)).uniqueResult(); } ...

na consulta por id eu tentei dos dois jeitos:

e

e destes dois jeitos tem aquele mesmo retorno estranho postado acima…

testei também chamando o consultarPorNome que retornou os dados corretos, e na linha seguinte chamando o consultar (por id)…
e para minha surpresa após executar o consultarPorNome o consultar (por id) funcionou… mas se eu chamar somente o consultar (por id) não funciona…

alguém tem alguma idéia do que pode estar acontecendo?

Esse comportamento do Hibernate é super normal.
O que acontece é o seguinte:
Ele não carrega todos os dados quando você faz o load, ele só vai carregar quando você executar algum getter da sua classe.
Ou seja, enquanto você não precisa dos dados, o Hibernate não executa o select. Somente quando você usar algum deles, o hibernate irá trazê-los do banco.
Esse comportamento é chamado de Lazy Initialization (como você pode ver no objeto handler: JavassistLazyInitializer).

Se parou de funcionar, é porque a session foi fechada antes de você usar esse objeto. Então, das duas, uma:

  1. Ou você, assim que executar o load, usa o Hibernate.initialize(objeto);
  2. Ou você deixa a session aberta até ele usar e depois fecha.

eai Rafael,

vou explicar o fluxo da minha lógica:

  • na tela de cadastro de pessoa é carregada uma lista de cidade via REST e cada option do select é nesse padrão:
  • para eu pegar o id da option selecionada fiz assim:
  • ao submeter o form para o controller o objeto cidade dentro de pessoa já vem com o id preenchido;

eu estava tentando recuperar todos os dados daquela cidade selecionada pelo id para persistir no cadastro do objeto pessoa,
mas acho que me equivoquei neste ponto, pois se a cidade já existe no banco eu não preciso persistí-la e logo não preciso recuperá-la…
apenas setando o id da cidade pessoa.cidade.id já é o suficiente para fazer referência a ela, não é mesmo?

Tente com get ao invés de load.

Teoricamente, sim. Não deve ter problema.

eai ErickRAR!!

cara, com get ao invés de load consegui recuperar a cidade por id!!

obrigado pela ajuda…

soh estou com uma dúvida agora:

A cidade já existe no banco.
Ela foi apenas apresentada em uma lista na tela.
A cidade foi selecionada.
O form de cadastro de pessoa foi submetido.
No método incluirPessoa de PessoaController o objeto pessoa.cidade.id veio com o valor do id da cidade selecionada.
Eu preciso recuperar todos os dados do objeto cidade e setar em pessoa se a cidade não vai ser persistida?

Acredito que sim. Eu já fiz isso uma vez para pesquisar e deu certo, então, teoricamente, deve dar certo para inserir.

É que eu não vejo lógica em recuperar todos os dados da cidade se ela já existe no banco…
O certo seria apenas fazer referencia com o valor do id da cidade no campo da chave estrangeira na tabela pessoa, não?
Se sim, então não precisa recuperar todos os dados da cidade pra fazer a referência…

Que eu me lembre, não precisa carregar tudo… Só o ID já basta para o hibernate fazer o relacionamento (desde que não tenha o cascade update, se não, ele vai apagar os outros dados daquele registro).

O get é o load com o Hibernate.initialize no fim…

Testei aqui e dá certo sim, só vale ficar atento no que o Rafael postou.

E se você já pegou todas as cidades do banco, basta pegar a cidade dessa lista.

é não tem cascade update…
a única configuração entre pessoa e cidade é a anotação @ManyToOne

Pessoa.java

... @ManyToOne @NotNull(message="A cidade deve ser informada!") private Cidade cidade; ...
tem ainda os get e set que não coloquei aí…

[quote=Rafael Guerreiro]Se parou de funcionar, é porque a session foi fechada antes de você usar esse objeto. Então, das duas, uma:

  1. Ou você, assim que executar o load, usa o Hibernate.initialize(objeto);
  2. Ou você deixa a session aberta até ele usar e depois fecha.[/quote]

RESOLVIDO