RESOLVIDO:Passando de JDBC para Hibernate Como continuar salvando múltiplos registros no banco?

8 respostas
kdashu

[quote]Olá pessoal,

Tenho um CRUD em JDBC funcional 100% com Postgres, mas ao tentar migrá-lo para Hibernate o método salvar não está 100% como deveria. Isso acontece quando no Form se marca um JCheckBox para indicar ao programa que aquele registro será salvo com repetição, tipo por mais "Y" vezes (Exe: salva o registro1 original, com a data = 01/01/2011, e caso marcado o JCheckBox irá repetí-lo por mais 2 meses, ficando: registro2 = 01/02/2011 e registro3 = 01/03/2011 )

Abaixo o código funcional em JDBC que consegue salvar todos os registros no banco:

public void salvar() {
        try {
            Registro registro = new Registro();           
            if (RB_Despesa.isSelected()) {
                registro.setTipo("Despesa");
            } else {
                registro.setTipo("Receita");
            }
            registro.setCategoria(CB_Categoria.getSelectedItem().toString());
            registro.setValor(Float.parseFloat(TF_Valor.getText()));
            registro.setProduto(TF_Produto.getText());
            registro.setComentario(TF_Comentario.getText());
            registro.setData(TF_Data.getText().toString());

            registroDao.incluirRegistro(registro);
            //System.out.println(registro.getData());

            if (CheckBox_Repetir.isSelected()) {
                calculaRepetirPeriodo(registro);
            }
            calculaBalanco();

        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, e.getMessage());
        }
    }
public void incluirRegistro(Registro registro) {
       Connection conexao = ConexaoPostGreSQL.getConnection(); 
       try {
            String comando = "insert into " + tabela + " (valor, categoria, tipo, produto, comentario, data) values (?, ?, ?, ?, ?, ?)";
            PreparedStatement statement = conexao.prepareStatement(comando);

            statement.setDouble(1, registro.getValor());
            statement.setString(2, registro.getCategoria());
            statement.setString(3, registro.getTipo());
            statement.setString(4, registro.getProduto());
            statement.setString(5, registro.getComentario());
            statement.setString(6, registro.getData());

            statement.executeUpdate();

            JOptionPane.showMessageDialog(null, "Registro INSERIDO no banco de dados !");
           } catch (SQLException e){
               JOptionPane.showMessageDialog(null, "Use . (ponto) para inserir casas decimais");
           } finally {
                try {
                    conexao.close();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
        }

Quando tentei migrar para Hibernate, o código incluirRegistro ficou assim:

public void incluirRegistro(Registro registro) {

       EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA_UP");
       EntityManager em = emf.createEntityManager();

       try {                      
           em.getTransaction().begin();
           //em.refresh(registro);
           em.persist(registro);                      
           //em.flush();
           em.getTransaction().commit();

           JOptionPane.showMessageDialog(null, "Registro INSERIDO no banco de dados !");

           } finally {
            try {
                    
            } catch (Exception e) {
                em.getTransaction().rollback();
                e.printStackTrace();
            }
        }
   }

E aqui há o laço de repetição que chama o método incluirRegistro, caso o JCheckBox_Repetir seja marcado para repetir "Y" vezes:

public void calculaRepetirPeriodo(Registro registro) {
           for (Integer contador = 1; contador <= vezes; contador++) {
                String dataOriginal = registro.getData();
                //chamaMetodoQueCalculaNovaData
                registroDao.incluirRegistro(registro);
            }
}

O método salvar permaneceu inalterado. Só que agora ele está salvando somente o último registro no banco (no exemplo, o registro3 01/03/2011 mencionado antes).

Alguém sabe me dizer por quê? Tentei usar o flush e o refresh, conforme comentários, mas sem sucesso. :roll:

8 Respostas

romarcio

Tenta fazendo assim:

public void incluirRegistro(Registro registro) {  
  
       EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA_UP");  
       EntityManager em = emf.createEntityManager();  
  
       try {                        
			em.getTransaction().begin();  
			//em.refresh(registro);  
			em.persist(registro);                        
			//em.flush();  
			em.getTransaction().commit();  
  
			JOptionPane.showMessageDialog(null, "Registro INSERIDO no banco de dados !");
			
		} catch (Exception e) {  
            em.getTransaction().rollback();  
            e.printStackTrace();  
		} finally {  
			em.close();             
		}  
}
kdashu

Infelizmente não funcinou amigo, deu a mensagem: EntityManager is closed

felipekamakura

Tenho um palpite.

No seu código você sempre passa a mesma instância de registro para o método incluirRegistro. O problema é que quando você chama um em.persist, o JPA seta o ID na instância que você passa.

Se vc tentar chamar o persist em seguida, usando a mesma instância (que está com o ID setado), provavelmente deve estar subindo um EntityExistsException.

Veja (pode ser com debugger, print) se o registro que você está passando para o incluir registro não está com o ID setado.

Se estiver, seta o ID do registro para null antes de salvar, ou cria uma nova.

kdashu

felipekamakura:
Tenho um palpite.

No seu código você sempre passa a mesma instância de registro para o método incluirRegistro. O problema é que quando você chama um em.persist, o JPA seta o ID na instância que você passa.

Se vc tentar chamar o persist em seguida, usando a mesma instância (que está com o ID setado), provavelmente deve estar subindo um EntityExistsException.

Veja (pode ser com debugger, print) se o registro que você está passando para o incluir registro não está com o ID setado.

Se estiver, seta o ID do registro para null antes de salvar, ou cria uma nova.

Acho que entendi o que você falou colega, coloquei um print após o método incluirRegistro e setei uma data para 01/03/2011 repetir por 2 meses:
as saidas para salvar o registro foram:

01/03/2011
01/04/2011
01/05/2011, mas somente este ficou gravado no banco.

Vou tentar setar como você falou e após posto os resultados

felipekamakura

Acho que fui precipitado e nem prestei atenção no seu modelo. Sua chave primária é o que? A Data?

Se for falei besteira, pq assumi que vc estava usando um ID auto-gerado como chave primária. =)

P

Vc sabe que existem 3 estados possiveis que um objeto pode estar usando o Hibernate? O seu problema é decorrente disso, mas basicamente vc devera criar pra cada novo registro um novo objeto com a nova data, vc não pode simplesmente pegar o objeto que vc persistiu e mudar a data pois na verdade o objeto é unico e por isso que o que é gravado aparece com a ultima data.

romarcio

kdashu:

Infelizmente não funcinou amigo, deu a mensagem: EntityManager is closed

Estranho, não deveria, por que você cria um EntityManager novo a cada chamada do método do registro e depois fecha, dai cria um novo e fecha…

Uma coisa que não entendi é como você esta mudando esta data, pq no método calculaRepetirPeriodo() não não altera o objeto registro.

Mas, de qualquer modo, faz um teste, troca o em.persist(registro) por em.merge(registro)

kdashu
pbnf:
Vc sabe que existem 3 estados possiveis que um objeto pode estar usando o Hibernate? O seu problema é decorrente disso, mas basicamente vc devera criar pra cada novo registro um novo objeto com a nova data, vc não pode simplesmente pegar o objeto que vc persistiu e mudar a data pois na verdade o objeto é unico e por isso que o que é gravado aparece com a ultima data.

Salve pessoal,

Tentei fazer o que o pbnf disse e funcionou! Tive que instanciar um novo registro e setar a data modificada para que o Hibernate salvasse todos.

Deixo meu código abaixo sobre como ficou (eu sei, é um código ruim e eu deveria ter usado algo do tipo calendar para calcular melhor, mas não consegui ainda)

public void calculaRepetirPeriodo(Registro registro) {

        Integer vezes = Integer.parseInt(CB_Vezes.getSelectedItem().toString());

        if (CB_Periodo.getSelectedItem().equals(&quot;Mês&quot;)) {

            for (Integer contador = 1; contador &lt;= vezes; contador++) {
                //variavel para usar no mes com a virada de ano
                Integer x = 1;
                String dataOriginal = registro.getData();
                String mesString = dataOriginal.substring(3, 5); // = parte do MES na string
                String anoString = dataOriginal.substring(6, 10); // = parte do ANO na string
                Integer mes = Integer.parseInt(mesString);
                Integer ano = Integer.parseInt(anoString);

                mes++;
                mesString = mes.toString();
                //verifica se mes passar de dezembro, aumenta o ano e volta mes para 1
                if (mes &gt; 12) {
                    mes = x;
                    x++;
                    ano++;
                }

                anoString = ano.toString();

                if (mes &lt; 10) {
                    mesString = &quot;0&quot;.concat(mes.toString());
                }
                //aqui tive que instanciar novo registro
                registro = new Registro();

                if (RB_Despesa.isSelected()) {
                    registro.setTipo(&quot;Despesa&quot;);
                } else {
                    registro.setTipo(&quot;Receita&quot;);
                }
                registro.setCategoria(CB_Categoria.getSelectedItem().toString());
                registro.setValor(Float.parseFloat(TF_Valor.getText()));
                registro.setProduto(TF_Produto.getText());
                registro.setComentario(TF_Comentario.getText());
                //e setar a nova data
                registro.setData(dataOriginal.substring(0, 3) + mesString + &quot;/&quot; + anoString);

                registroDao.incluirRegistro(registro);
                System.out.println(registro.getData());
            }
//se for ano...

Obrigado a todos que tentaram me ajudar!

Criado 24 de fevereiro de 2011
Ultima resposta 25 de fev. de 2011
Respostas 8
Participantes 4