Olá pessoal, estou utilizando JSF + EJB3 + JPA e tenho uma dúvida a respeito do seguinte cenário:
Managed Beans JSF no escopo de “request”.
Quando preciso atualizar os dados de alguma entidade, é feito um find na entidade e enviado o objeto para a camada de visão, ao qual representa esses dados num formulário para que o usuário possa alterá-los.
A entidade possui vários atributos, sendo alguns de tipo fora do padrão do java, por exemplo Pessoa.
Existem alguns atributos que são obrigatórios para ser feita a persistência da entidade, porém não são editados/inseridos pelo usuário, quando eles retornam da camada de visão para camada de negócio, como o managed bean está no escopo request, esses campos obrigatórios (porém ocultos para o usuário) voltam nulos.
Até aí tudo bem, eu poderia criar campos ocultos no form para que essas informações não sejam perdidas, mas o problema é que não são tipos padrão do java, e sim outras entidades que compõe.
Ex.:
class Filial {
private Empresa empresa
.
.
.
}
É algo como se a empresa fosse oculta para o usuário, mas quando é feito o request para efetuar o update, esses campo volta null, como todos os outros que são ocultos para o usuário, seu estado não foi salvo, pois está no escopo request.
Existe alguma forma para tratar esse tipo de situação?
Nao sei se te entendi o direito, mas voce deve estar com problemas ao chamar o merge porque ele apaga o relacionamento com a Empresa que voce tinha antes na hora que voce edita a classe Filial.
Se é isso, a ideia é voce passar por hidden o id da empresa que estava antes associada. O JPA na hora que ve que o ID do objeto esta populado, vai deixar o relacionamento como esta e nao vai mexer na Empresa caso voce esteja dando merge so na filial (e nao tenha cascade). Entao o resto dos atributos de Empresa podem continuar null.
Existem outras tecnicas, com o hibernate da pra mudar esse comportamento, e quando estiver null vc deixa o que ja esta. Mas se voce quiser retirar o relcacionamento e realmente deixa-lo null, ai o problema fica invertido!
Editar entidades que tem relacionamentos via formulario web ainda é chatinho via JPA. Alguns frameworks ja tem solucoes prontas para esses casos.
Alias, gostaria de ler outras ideias que os usuarios aqui usam.
Isso mesmo, e também apaga os outros atributos da entidade que não são visíveis para o usuário, caso forem visíveis, bom - aí vai do jeito que foi editado.
Pois é, tinha pensado nisso (hidden), porém referenciando no JSF o atributo que é a entidade relacionada, aí caí no problema de conversão, e realmente desenvolver um conversor customizado para cada entidade que tiver relacionamento é uma péssima idéia e talvez complexa demais.
Essa técnica do hibernate realmente é muito interessante e poupa um bom trabalho. Uso uma técnica do tomahawk que é o save state, ele mantém o estado do bean gerenciando (como se o escopo fosse “quase session”), porém o estado permanece para apenas 1 request futuro, depois disso o estado é perdido, mas já ajuda bastante. Um requisito para usar o save state é que o bean gerenciado deve ser serializável.
Eu poderia usar essa técnica do save state, mas como estou usando um managed bean genérico, o buraco é mais embaixo e o save state se perde, vou estudar a respeito pra ver o motivo do problema que está ocorrendo.
[quote] Editar entidades que tem relacionamentos via formulario web ainda é chatinho via JPA. Alguns frameworks ja tem solucoes prontas para esses casos.
Alias, gostaria de ler outras ideias que os usuarios aqui usam.[/quote]
Realmente é meio chato isso, mas seria interessante saber de outras idéias e técnicas utilizadas para resolver esse tipo de problema.
Deixar o managed bean no escopo de sessão (ou saveState) pode ser sim a solução, mas tome cuidado que isso limita a escalabilidade (problema das sessões gordas).
Acho que um jeito razoável, mas bem feio se visto do lado OO purista é fazer como o paulo disse e guardar apenas os ids dos relacionamentos em campos hidden, preenchendo-os denovo no submit. Não precisa de javax.faces.converter.Converter especial, só fazer:
Parace bem interessante esse componente do tomahawk, mas ai entra outro problema: ele pode serializar relacionamentos dos relacionamentos dos relacionamentos dos … e o tamanho da arvore de componentes serializada no hidden do cliente ficara enorme! Poderia criar uma tag excludes que diz quais atributos nao precisa guardar, ou um atributo depth indicando ate que nivel (e pro hibernate/jpa basta depth=1).
Um componente desses seria muito bom para o JSF 2.
Os modelos de “conversacao” do seam, shale e parte do spring webflow tambem podem ajudar a gente nisso: nao colocamos o objeto na sessao, e sim deixamos ele vivo durante a conversacao. O que acha?
[quote=Fabio Kung]Deixar o managed bean no escopo de sessão (ou saveState) pode ser sim a solução, mas tome cuidado que isso limita a escalabilidade (problema das sessões gordas).
Acho que um jeito razoável, mas bem feio se visto do lado OO purista é fazer como o paulo disse e guardar apenas os ids dos relacionamentos em campos hidden, preenchendo-os denovo no submit. Não precisa de javax.faces.converter.Converter especial, só fazer:
sim, colocar so os ids funciona. Nao se esqueca de depois deixar o objeto relacionado construido na relacao, senao o JSF nao vai conseguir setar o ID dele, pois tera uma referencia nula.
[quote] Um componente desses seria muito bom para o JSF 2.
Os modelos de “conversacao” do seam, shale e parte do spring webflow tambem podem ajudar a gente nisso: nao colocamos o objeto na sessao, e sim deixamos ele vivo durante a conversacao. O que acha?
[/quote]
Realmente na nova versão do JSF seria interessante um componente assim.
Bem legal o esquema de conversação, vou dar uma olhada pra ver qual é.