Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Spring + JSF Atualizando todos os campos da entidade mesmo que não existam no formulário

Tenho uma aplicação com JSF + Spring + Hibernate e percebi o seguinte comportamento: ao editar uma entidade e salva-la a aplicação tá tratando os campos que eu nao mexi como vazios. Por exemplo, num formulário da entidade Usuario eu não tenho o campo de senha (que já está salva no banco)... Aí ao atualizar qualquer informação da minha entidade ele considera que a senha é "vazia" e altera as informações no BD. Como proceder?

8 respostas

Fala aí, Ygor, tudo certo? =)

O que você pode fazer é enviar todos os dados para o seu formulário. Dessa forma, mesmo que você não mexa neles, eles continuarão sendo enviados para o update na base de dados e permanecerão intactos... =)

Espero ter ajudado!

Abraço e bons estudos,

Fábio

Fábio, mas não é ruim eu passar todos os dados pro formulário? Teria que ter vários campos hidden? Acho ruim passar por exemplo a senha dos usuários como input hidden. E além disso eu gostaria de continuar usando a anotação @DynamicUpdate do hibernate pra justamente dar update apenas no que for alterado em minhas entidades.

Ygor,

Ahh, desculpe. Não me atentei ao fato de que a senha está envolvida... =|

Nesse caso, realmente, não é uma boa passar tudo, mesmo que em inputs hidden.

Você poderia colocar parte da sua classe de modelo e do formulário aqui, para darmos uma olhada? =)

Fábio

Oi Ygor,

eu acho que isso é mais um problema do uso do JPA/Hibernate. O JPA/Hibernate sempre atualiza a entidade inteira. Ou seja, se vc nao preencheu o usuário com login e senha, o JPA vai sobre escrever esses campos com nulo no banco.

Nesse caso seria melhor se vc carregasse primeiro a entidade usuário do banco (com os dados antigos mas todos os atributos preenchidos, incluindo login e senha). Depois vc joga os valores do "usuário que vem do formulário" para esse "usuário do banco". Então vc não vai gravar o "usuario do form", apenas atualiza o "usuario do banco", ok?

Realmente não sei se a minha explicação ficou clara .... \o/

abs

Consegui compreender a explicação sim! hahaha Então pessoal, eu creio que já estou fazendo isso, olhe meu método que carrega o usuário para preencher os campos do formulário:

    public void carregaUsuario() {
        usuario = usuarioDAO.buscaPorId(usuario.getId());
        if (usuario == null) {
            usuario = new Usuario();
        }
    }

Ou seja, eu levo todas as informações da entidade carregadas. Método para salvar / atualizar:

    @Transactional
    public void salvarUsuario() {
        this.usuario.setCategoria(categoriaDAO.buscaPorId(this.usuario.getCategoria().getId()));
        if (usuario.getId() == null) {
            usuarioDAO.adiciona(usuario);
        } else {
            System.out.println(context);
            usuarioDAO.atualiza(usuario);
            Usuario uLogado = UsuarioLogado.buscaUsuarioLogado(context);
            // Se o usuário estiver alterando o usuário da sessão, este será atualizado
            if (uLogado.getId() == usuario.getId()) {
                context.getExternalContext().getSessionMap().put("usuarioLogado", usuarioDAO.buscaPorId(usuario.getId()));
            }
        }

        usuario = new Usuario();
        usuarios = usuarioDAO.listaTodos();
    }

Eu comecei a achar esquisito porque fui tentar atualizar um usuário agorinha e vi que ele criou outro, tive que colocar um input hidden pro Id do mesmo, ai fui investigar e vi que ele "perdia" todas as informações do usuário, so fica o que existe no formulário mesmo. E isso começou a acontecer agora, que eu comecei a tentar usar o escopo de requisição do Spring kkkkk

Eu tô pra desistir de utilizar o Spring e passar a usar somente o CDI pra injetar as dependências :/

solução!

Oi Ygor,

Me parece que vc esteja carregando e atualizando o usuário em requisições diferente e por isso a entidade perde os valores pois e recriado em cada requisisao.

Tente carregar o usuario dentro do seu método salvarUsuario (depois do else).

Segue um esboço do código para ilustrar a ideia:

@Transactional
    public void salvarUsuario() {
        this.usuario.setCategoria(categoriaDAO.buscaPorId(this.usuario.getCategoria().getId()));
        if (usuario.getId() == null) {
            usuarioDAO.adiciona(usuario);
        } else {
            //novo, carregando o usuario do banco
            Usuario ususarioBanco = usuarioDao. buscaPorId(usuario.getId());

            //agora copiando valores que vc gostaria de atualizar
            usuarioBanco.setXXX(usuario.getXXX());

            //na verdade nao é preciso chamar atualiza pois a usuarioBanco já é managed, por isso comentei a linha
            //usuarioDAO.atualiza(usuarioBanco);

            Usuario uLogado = UsuarioLogado.buscaUsuarioLogado(context);
            // Se o usuário estiver alterando o usuário da sessão, este será atualizado
            if (uLogado.getId() == usuario.getId()) {
                context.getExternalContext().getSessionMap().put("usuarioLogado", usuarioDAO.buscaPorId(usuario.getId()));
            }
        }

        usuario = new Usuario();
        usuarios = usuarioDAO.listaTodos();
    }

Ah, e não desiste do Spring :)

Valeu Nico! Tinha pensado nessa possibilidade mesmo, mas achei meio chato ter que dar set em todos os campos do formulário, tem muita coisa nessa página kkkkkk

Olha só, como eu havia colocado o escopo como request realmente tava perdendo os dados nesse meio tempo, entre carregar a entidade e salvar o que modifiquei. Fui pesquisar sobre algo como o ViewScope pra Spring e vi que não existe nativamente, mas encontrei um link no site do primefaces que ensina a implementar esse escopo customizado. Segue o link: https://www.primefaces.org/port-jsf-2-0s-viewscope-to-spring-3-0/

Utilizei aqui e deu tudo certo, não preciso mais de nenhum input hidden nem carregar a entidade antes de atualizar!

Perfeito!

Realmente nao tem o ViewScope nativamente com Spring e faz falta, mas que bom que conseguiu resolver.

abs