Solucionado (ver solução)
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