Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
15
respostas

JPA atualizar entidade automaticamente

Boa noite, estou com a seguinte dúvida, percebi que ao utilizar a JPA (Hibernate) + Spring em uma aplicação JSF (PrimeFaces) minhas entidades não são atualizadas de imediato ao realizar um cadastro, por exemplo, possuo uma tela de cadastro de Usuários onde ao realizar o mesmo tudo ocorre normalmente, as informações são persistidas no banco de dados, mas ao tentar utilizar por exemplo um componente auto-complete em outra página o registro da entidade recém adicionada não aparece, a menos que eu reinicie o servidor, após a reinicialização tudo funciona normalmente.

Criei o tópico na sessão de JPA pois pesquisando pela internet, creio que seja algo relacionado a configuração de Cache do hibernate porém ainda não consegui encontrar a solução, caso alguém ja tenha passo por isso ou tenha alguma luz sobre o assunto me avise por favor.

Obrigado, até mais

15 respostas

Oi Bruno

Qual é o escopo do bean que você está utilizando para fazer o auto complete? Você poderia postar o código da classe?

Oi Victor,

o bean do autocomplete estou utilizando @ViewScoped, segue abaixo

@Named
@ViewScoped
public class MatriculaBean {

    private List<Modalidade> modalidadesDisponiveis;
    private List<Modalidade> modalidadesSelecionadas = new ArrayList<Modalidade>();
    private OpcaoMatricula opcaoEscolhida;
    private Modalidade modalidadeEscolhida;

    private List<Perfil> alunosDisponiveis;
    private List<Perfil> alunosSelecionados = new ArrayList<Perfil>();

    @Autowired
    private ServicoModalidade servicoModalidade;

    @Autowired
    private ServicoPerfil servicoPerfil;

    @PostConstruct
    private void init(){
        modalidadesDisponiveis = servicoModalidade.listarEager();
        alunosDisponiveis = servicoPerfil.listar();
    }



    public List<Modalidade> completeModalidade(String busca) {
        List<Modalidade> filtrados = new ArrayList<Modalidade>();
        if(modalidadesSelecionadas == null){modalidadesSelecionadas = new ArrayList<Modalidade>();}
        for (Modalidade mod : modalidadesDisponiveis) {
            if (mod.getNome().contains(busca) && !modalidadesSelecionadas.contains(mod)) {
                filtrados.add(mod);
                }
            }
        return filtrados;
    }

Lembrando que utilizei o autocomplete como exemplo apenas para retratar meu problema, o mesmo acontece em toda aplicação, por exemplo, tenho um dataTable que lista todos os usuários cadastrados, porém ao cadastrar um novo usuário e ir a página que contem essa tabela o mesmo não é listado, mas após reiniciar o servidor (Tomcat 7) a tabela é atualizada na view.

O problema é que não está sendo feita uma nova busca no banco de dados e sim numa lista já carregada em memória.

A alteração seria mais ou menos a seguinte:

    public List<Modalidade> completeModalidade(String busca) {

        return servicoModalidade.findByModalidade(busca);
    }

Olá Mauricio, não consegui entender

Veja, ao acessar a tela em que está o auto-complete MatriculaBean é executado

    @PostConstruct
    private void init(){
        modalidadesDisponiveis = servicoModalidade.listarEager();
    }

certo? me corrijam se estiver errado

Ou seja, de acordo com essa lógica, ao acessar a página uma nova consulta é feita ao banco de dados populando a lista de modalidades disponíveis, porém a modalidade recém adicionada ao banco não esta lá.

Oi Bruno

O seu problema é que a classe está como @ViewScoped, então enquanto você não fizer uma navegação (ou de alguma forma limpar a sessão do servidor) o estado do seu bean será mantido durante diversas requests.

Então, se você acessar o auto complete em um navegador e ver a lista com os elementos A, B, C e depois fizer um cadastro de um elemento D em outro navegador, como o managed bean associado com o primeiro navegador ainda está com os elementos A, B, C você não verá o item recém cadastrado. Para resolver o problema, você pode utilizar a solução dada pelo Mauricio ou mudar o escopo do seu bean para @RequestScoped

Opa Victor valeu pela resposta, mas o problema continua mesmo alterando o escopo para @RequestScoped, muito estranho...

Obs: já tive o mesmo problema anteriormente, na ocasião acabei resolvendo utilizando a configuração none no meu arquivo persistence.xml... Não sei se foi a melhor solução mas na epoca resolveu. Acontece que agora estou utilizando Spring nessa aplicação e não disponho do arquivo persistence.xml.

Qualquer ajuda é bem vinda!

Bruno você contém uma tag

Bruno você contém uma tag

Bruno você contém uma tag script na sua tela chamando o método init ? se não tem coloque e sempre que acessar a tela esse método será chamado. OBS: procure sempre deixa essa tag antes do body para evitar que seja chamado caso atualize algum campo da página

Hmm não léo... o método init é chamado quando o bean é criado... isso já está acontecendo, o método é chamado e por sua vez realiza a chamada ao banco de dados e popula a lista através do `modalidadesDisponiveis = servicoModalidade.listarEager();

acontece que por algum motivo a lista não vem com os dados recém persistidos, já verifiquei o escopo do bean, tentei utilizar um .flush() após o .saveOrUpdate do meu método adicionar no meu DAO, mas o problema continua

Se você fez isso tudo e continua sem funcionar. Pode ser que o problema esteja na hora em que você cria o novo registro. Verifique se a transação esta sendo commitada.

Ou se puder, poste o código do seu DAO.

solução!

Oi Bruno

Como você está utilizando o spring para fazer a DI no seu projeto, os escopos precisam ser controlados com as anotações do spring e não com as do JSF/CDI. Então ao invés de anotar a classe com o @RequestScoped, você precisa utilizar o @Scope do Spring:

@Named
@Scope("request")
public class MatriculaBean {
   // implementação
}

A anotação javax.faces.bean.RequestScoped só funciona em classes que são gerenciadas pelo JSF (anotadas com o javax.faces.bean.ManagedBean) e o javax.enterprise.context.RequestScoped só funciona em classes que são gerenciadas pelo CDI. Como o spring não entende as anotações de escopo do JSF e do CDI, ele utiliza o escopo padrão que é o singleton.

Victor!!! Matou a charada! Valeu pelas respostas pessoal!

O problema agora é a limitação do @Scope não possuir a opção de view mas isso é outro problema auhahauhuh