Problema na atualização de tabela [Resolvido!]

Pessoal, estou com o seguinte problema: meu sistema possui uma tela de cadastro, onde o usuário pode cadastrar, remover e atualizar especialidades médicas. Cada especialidade possui um código e um nome. Não se pode cadastrar uma especialidade com o nome de uma especialidade já cadastrada, nem com um código já cadastrado.
O problema é que quando vou atualizar uma especialidade, se mudo o nome ou o código para um valor já cadastrado, essa atualização não é realizada, ou seja, não é salvo no banco de dados, mas atualiza o valor que aparece na tabela da página, só voltando a apresentar o valor armazenar no banco de dados depois que dou refresh na página.
Alguém tem idéia como posso resolver isso?

O código da minha tela é:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui"> 

<h:head></h:head> 
<body>
<ui:composition template="_template.xhtml">
<ui:define name="corpo">
<br></br>
<br></br>
<h:form id="formularioCadastro">
	<p:growl></p:growl>
	<div align="center" >
	<h:panelGrid columns="2" cellpadding="2"  cellspacing = "10" width="360">
		<h:outputText value="Especialidade:"  />
		<p:inputText value="#{especialidadeBean.especialidade.nome}"></p:inputText>
		<h:outputText value="Código:" />
		<p:inputText value="#{especialidadeBean.especialidade.numero}"></p:inputText>
		<p:commandButton value="Salvar" action="#{especialidadeBean.salvar}" update="@form :formularioTabela"></p:commandButton>
	</h:panelGrid>
	<br></br>
	<br></br>
	</div> 
</h:form>

<h:form id="formularioTabela">
	<div align="center" >
	<p:dataTable value="#{especialidadeBean.lista}" var = "especialidade"
		style="width:500px;"
		paginator="true" rows="10" 
		paginatorTemplate="{CurrentPageReport}  {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"                 
		rowsPerPageTemplate="5,10,15">
		
		  
		<f:facet name="header">
			Especialidades
		</f:facet>
		
		<p:column id="numero" sortBy="#{especialidade.numero}">
			<f:facet name="header">
				<h:outputText value="Código " />
			</f:facet>
			<h:outputText value="#{especialidade.numero}" />
		</p:column>
		
		<p:column id="nome" sortBy="#{especialidade.nome}">
			<f:facet name="header">
				<h:outputText value="Nome" />
			</f:facet>
			<h:outputText value="#{especialidade.nome}" />
		</p:column>
		
		<p:column>
			<p:commandButton value="Remover" action="#{especialidadeBean.remover}" update="@form :formularioTabela">
				<f:setPropertyActionListener target="#{especialidadeBean.especialidade}" value="#{especialidade}"></f:setPropertyActionListener>
			</p:commandButton>
		</p:column>
		
		<p:column>
			<p:commandButton value="Alterar" update="@form :formularioCadastro">
				<f:setPropertyActionListener target="#{especialidadeBean.especialidade}" value="#{especialidade}"></f:setPropertyActionListener>
			</p:commandButton>
		</p:column>
		
	</p:dataTable>
	</div>
</h:form>
</ui:define>		
</ui:composition>
</body> 
</html>

Minha classe Bean:

package br.pe.gov.ses.pme.mb;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;

import br.pe.gov.ses.pme.dao.DAO;
import br.pe.gov.ses.pme.dao.EspecialidadeDAO;
import br.pe.gov.ses.pme.modelo.Especialidade;

@ManagedBean
@ViewScoped
public class EspecialidadeBean {
	
	private Especialidade especialidade = new Especialidade();
	
	private DAO<Especialidade> dao = new DAO<Especialidade>(Especialidade.class);
	
	private List<Especialidade> lista;
	
	@Inject
	private EspecialidadeDAO especialidadeDAO;
	
	public EspecialidadeBean(){
		
	}
	
	public EspecialidadeBean(EspecialidadeDAO especialidadeDAO){
		this.especialidadeDAO = especialidadeDAO;
	}
	
	@PostConstruct
	public void init() { 
		setLista(dao.listarTodos());
	}
	
	public void salvar(){
		boolean salvar = this.especialidadeDAO.permitidoSalvar(especialidade);
		if(salvar){
			if(this.especialidade.getId() == null){
				dao.adiciona(especialidade);
			}else{
				dao.atualiza(especialidade);
			}
			
			this.especialidade = new Especialidade();
			lista = dao.listarTodos();
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Especialidade Cadastrada!", ""));
		}else{
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Especialidade já cadastrada!", ""));
		}
		
	}
	
	public void remover(){
		if(this.especialidade.getId() != null){
			
			dao.remove(especialidade);
			 especialidade = new Especialidade();
			 lista = dao.listarTodos();
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Operação realizada com sucesso!", ""));
		}
	}
	
	

	public List<Especialidade> getLista() {
		return lista;
	}

	public void setLista(List<Especialidade> lista) {
		this.lista = lista;
	}

	public Especialidade getEspecialidade() {
		return especialidade;
	}

	public void setEspecialidade(Especialidade especialidade) {
		this.especialidade = especialidade;
	}
	
	public String cancelar() {
		
		especialidade = new Especialidade();
		
		return "Especialidade.jsf?faces-redirect=true";
		
	}

}

Lembrando que o problema está na atualização da página, a especialidade não é salva no banco de dados, mas é atualizada na tabela. É preciso dar um refresh na página para que a tabela volte a mostrar o que está armazenado no banco de dados.

Precisamos ver esta classe

private EspecialidadeDAO especialidadeDAO;

É essa aqui:

package br.pe.gov.ses.pme.dao;

import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;

import br.pe.gov.ses.pme.modelo.Especialidade;

public class EspecialidadeDAO {

	private EntityManager em;
	
	@Inject
	public EspecialidadeDAO(EntityManager em) {
		this.em = em;
	}
	
	//TO DO: não deixar cadastrar um número já cadastrado
	public boolean permitidoSalvar (Especialidade especialidade){
		boolean salvar = false;
		Query query = em
				.createQuery("select e From Especialidade e where lower(e.nome) like :nomeEspecialidade", Especialidade.class);
		query.setParameter("nomeEspecialidade", especialidade.getNome().toLowerCase());
		List<Especialidade> lista = query.getResultList();
		
		Query queryCodigo = em.createQuery("select e from Especialidade e where e.numero = :numeroEspecialidade", Especialidade.class);
		queryCodigo.setParameter("numeroEspecialidade", especialidade.getNumero());
		List<Especialidade> listaCodigo = queryCodigo.getResultList(); 
		
		if(lista.isEmpty() && listaCodigo.isEmpty()){
			return true;
		}
		
		for(int i = 0; i < lista.size(); i++){
			if(lista.get(i).getId().equals(especialidade.getId())){
				salvar = true; 
			}
		}
		
		for(int j = 0; j < listaCodigo.size(); j++){
			if(listaCodigo.get(j).getId().equals(especialidade.getId())){
				if(!listaCodigo.isEmpty() && listaCodigo.get(j).getNome().equalsIgnoreCase(especialidade.getNome()))
					salvar = true;
			}else{
				salvar = false;
			}
		}
		
	
		return salvar;
	}
	
}

Mas a especialidade não é salva no banco de dados, apenas o valor apresentado na tela é modificado, dando a impressão que a especialidade foi salva. Quando dou um refresh na página, esta volta a apresentar corretamente os dados armazenados no banco de dados.

já imprimiu a lista apos a atualização para verificar se ela está sendo modificada ??

Você esta enviando o commit no fim da transação ?

/*
Se os dois selects não tiverem nenhum resultado, pode inserir
é uma nova especialidade.
*/
if(lista.isEmpty() && listaCodigo.isEmpty()){  
            return true;  
        }  
/*
Caso haja algum nome repetido, verifica se o código é o mesmo e salva?
*/          
        for(int i = 0; i < lista.size(); i++){  
            if(lista.get(i).getId().equals(especialidade.getId())){  
                salvar = true;   
            }  
        }  
/*
Caso haja algum código repetido, verifica se o código é o mesmo da especialidade informada,
verifica se a lisa de código NÃO está vazia e verifica se o nome é igual?
Se não for, retorna falso?
*/          
        for(int j = 0; j < listaCodigo.size(); j++){  
            if(listaCodigo.get(j).getId().equals(especialidade.getId())){  
                if(!listaCodigo.isEmpty() && listaCodigo.get(j).getNome().equalsIgnoreCase(especialidade.getNome()))  
                    salvar = true;  
            }else{  
                salvar = false;  
            }  
        }  
          
      
        return salvar;  

Vamos lá.
No meu entender, você deveria validar se a lista de nomes possui algum valor de código repetido, se existir, significa que está alterando aquele elemento.

No banco de dados está ok, eu não salvo uma especialidade com um código ou um nome cadastrado. O problema está na visualização da tela.
A tela mostra como se a especialidade estivesse sido salva, quando dou um refresh na página, são mostrados os valores corretamente. E esse problema só ocorre quando vou atualizar uma especialidade.

[quote=danipatricia]No banco de dados está ok, eu não salvo uma especialidade com um código ou um nome cadastrado. O problema está na visualização da tela.
A tela mostra como se a especialidade estivesse sido salva, quando dou um refresh na página, são mostrados os valores corretamente. E esse problema só ocorre quando vou atualizar uma especialidade.[/quote]
Isso está confuso.
Atualizar = modificar algum atributo e salvar essa modificação no banco de dados, certo?
Se o código é a PK, ele, obviamente não pode ser alterado. Já o nome, qual a restrição?

A informação persiste na tela por que você mantém o mesmo objeto. Preciso entender que regra de negócios é esta que não permite alterar um nome, para depois poder tentar auxiliar nesse detalhe da tela.

Atualizar = modificar algum atributo e salvar essa modificação no banco de dados, certo? Certo.

Não estou usando esse código como PK, esse código é atribuído pelo usuário a uma especialidade.
O cenário é esse:

  1. O usuário clica o botão atualizar.
  2. Os dados da especialidade selecionada aparecem no formulário.
  3. O usuário modifica o valor do campo código para um valor já existente.
  4. O usuário clica no botão salvar.
  5. O sistema apresenta uma mensagem indicando que essa especialidade já se encontra cadastrada.
  6. A tabela que apresenta todos as especialidades cadastradas mostra como se os dados da especialidade selecionada tivessem sido alterados. (No banco de dados nada mudou)
  7. Se o usuário dê um refresh na página, a tabela volta a mostrar os valores corretos da especialidade selecionada, ou seja, os valores contidos no banco de dados.

Entendi.

public void salvar(){  
/*
Você pode alterar aqui para algo como
*/
        Especialidade testeEspecialidade = this.especialidadeDAO.permitidoSalvar(especialidade)
        if(testeEspecialidade == null){
            if(this.especialidade.getId() == null){  
                dao.adiciona(especialidade);  
            }else{  
                dao.atualiza(especialidade);  
            }  
              
            this.especialidade = new Especialidade();  
            lista = dao.listarTodos();  
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Especialidade Cadastrada!", ""));  
        }else{  
                 especialidade = testeEspecialidade;//aqui você resolve o problema.
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Especialidade já cadastrada!", ""));  
        }  
          
    }  

E aqui

//TO DO: não deixar cadastrar um número já cadastrado  
    public Especialidade permitidoSalvar (Especialidade especialidade){  
        Especialidae salvar = null;  
        Query query = em  
                .createQuery("select e From Especialidade e where lower(e.nome) like :nomeEspecialidade", Especialidade.class);  
        query.setParameter("nomeEspecialidade", especialidade.getNome().toLowerCase());  
        List<Especialidade> lista = query.getResultList();  
          
        Query queryCodigo = em.createQuery("select e from Especialidade e where e.numero = :numeroEspecialidade", Especialidade.class);  
        queryCodigo.setParameter("numeroEspecialidade", especialidade.getNumero());  
        List<Especialidade> listaCodigo = queryCodigo.getResultList();   
          
        if(lista.isEmpty() && listaCodigo.isEmpty()){  
            return null;//se for null, procede com a ação salvar/atualizar  
        }  
          
        for(int i = 0; i < lista.size(); i++){  
            if(lista.get(i).getId().equals(especialidade.getId())){  
                salvar = lista.get(i);//se tiver mesmo código, atribuir e salvar   
            }  
        }  
          
        for(int j = 0; j < listaCodigo.size(); j++){  
            if(listaCodigo.get(j).getId().equals(especialidade.getId())){  
                if(!listaCodigo.isEmpty() && listaCodigo.get(j).getNome().equalsIgnoreCase(especialidade.getNome()))  
                    salvar = listaCodigo.get(i);//se tiver o mesmo nome, atribuir e salvar  
            }else{  
                salvar = null;//se null, permite ação  
            }  
        }  
          
      
        return salvar;  //retorna null ou a especialidade que está no banco
    }  

Infelizmente não deu certo.
A especialidade atualizada é apresentada na tela com os valores nulos, mas não com os valores que estão no banco de dados.

[quote=danipatricia]Infelizmente não deu certo.
A especialidade atualizada é apresentada na tela com os valores nulos, mas não com os valores que estão no banco de dados.[/quote]
Sim!
Ela será apresentada com o valor que você definir.
Para tanto, teu método de verificação não pode retornar um boolean, pois você precisa da especialidade que está no banco, certo?
Creio que alterando o método para retornar a especialidade que está no banco resolva. Se não houver nenhuma, retorna null, sendo null, você pode salvar, entende?

Outra opção, usando lógica lusitana, é fazer toda verificação e, após isto, uma nova consulta ao banco para obter a especialidade que se busca… Mas, como disse, lógica lusitana…

Você tem razão em relação a retorna um objeto ao invés de um boolean no método de verificação!
Um colega de trabalho deu a idéia de atualizar a lista depois que não conseguir salvar o objeto, deu certo!!!
O código ficou assim:

	public void salvar(){
		boolean salvar = this.especialidadeDAO.permitidoSalvar(especialidade);
		if(salvar){
			if(this.especialidade.getId() == null){
				dao.adiciona(especialidade);
			}else{
				dao.atualiza(especialidade);
			}
			
			this.especialidade = new Especialidade();
			lista = dao.listarTodos();
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Especialidade Cadastrada!", ""));
		}else{
			
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Especialidade já cadastrada!", ""));
			lista = dao.listarTodos();
		}
		
	}

Muito obrigada por toda ajuda!

[quote=danipatricia]Você tem razão em relação a retorna um objeto ao invés de um boolean no método de verificação!
Um colega de trabalho deu a idéia de atualizar a lista depois que não conseguir salvar o objeto, deu certo!!!
O código ficou assim:

	public void salvar(){
		boolean salvar = this.especialidadeDAO.permitidoSalvar(especialidade);
		if(salvar){
			if(this.especialidade.getId() == null){
				dao.adiciona(especialidade);
			}else{
				dao.atualiza(especialidade);
			}
			
			this.especialidade = new Especialidade();
			lista = dao.listarTodos();
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Especialidade Cadastrada!", ""));
		}else{
			
			FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN, "Especialidade já cadastrada!", ""));
			lista = dao.listarTodos();
		}
		
	}

Muito obrigada por toda ajuda![/quote]
Ainda é trabalho dobrado, visto que você está indo duas vezes ao banco de dados…
Mas, se resolve, tá resolvido, não é?