Merge só salva alguns dados?

6 respostas
lcn.andre

Boa noite!
Estou há alguns dias com um problema no trabalho que não consigo resolver e que já rendeu boas brigas com o cliente. A questão é que temos um cadastro de clientes gigante e o que rola é que alguns dados são salvos quando se clica em “Gravar”, outros não. Ah sim, isso só acontece com alguns clientes. Vamos às informações:

  • Estamos usando Oracle XE, com TopLink e JPA.
  • Um cliente se parece com isso:
    • Cliente
      ** Pessoa
      *** Endereco
      ** AnaliseCredito
  • Estamos usando o seguinte método de gravação:
    • Criar ou carregar uma entidade Cliente
    • Na hora de gravar, seta todas as propriedades ao objeto Cliente
    • Retorna o cliente a uma outra classe que faz a persistência
    • Esse método abre uma transaction, caso já não esteja aberta, faz o merge, o flush e o commit.

O que é estranho é que isso só ocorre no cadastro de clientes, sendo que essa mesma fórmula acima é usada para vários outros cadastros do nosso sistema. Outra coisa é que isso só acontece quando o sistema está configurado para rodar pela base deles, que em tese é idêntica à nossa local que usamos para testes. Quando se cria um novo cliente, todos os dados salvam tranquilamente e é possível alterá-los depois, mas se você tentar alterar os dados já existentes, o que estiver em branco e for preenchido não é gravado.

Já passei dias tentando resolver o problema e nada. Conto com a ajuda de vocês para ver se conseguimos uma luz.
Desde já, agradeço.

6 Respostas

overkill

Amigo seria interessante colocar o codigo para analise, assim poderemos ver a lógica que vc desenvolveu para salvar os dados as vezes um clear() no entity manager resolve isso, as vezes é uma questáo de cascade nas entidades. Sem a analize e mais informações fica complicado identificar a causa.

Abraço

lcn.andre

Foi mal, é que quando postei já estava em casa e não tinha acesso ao código. As classes estão incompletas, se precisarem de mais alguma informação é só dizer.

Cliente:
@Entity
@Table(name = "CLIENTE")
@NamedQueries({})
public class Cliente extends Entidade implements Serializable {

    @Transient
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
    private static final long serialVersionUID = 1L;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // id
    //
    @Id
    @SequenceGenerator(name = "SeqClienteId", sequenceName = "SEQ_CLIENTE_ID", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SeqClienteId")
    @Column(name = "ID", nullable = false)
    private Long id;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // dataCadastro
    //
    @Column(name = "DATA_CADASTRO", nullable = false)
    @Temporal(TemporalType.DATE)
    private Date dataCadastro;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // comprador
    //
    @Column(name = "COMPRADOR")
    private String comprador;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // historicos
    //
    @Column(name = "HISTORICOS")
    private String historicos;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // compradorTel
    //
    @Column(name = "COMPRADOR_TEL")
    private String compradorTel;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // compradorCel
    //
    @Column(name = "COMPRADOR_CEL")
    private String compradorCel;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // ramalTecnico
    //
    @Column(name = "RAMAL_TECNICO")
    private String ramalTecnico;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // ramalComprador
    //
    @Column(name = "RAMAL_COMPRADOR")
    private String ramalComprador;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // historicoCotacao
    //
    @Column(name = "HISTORICOS_COTACAO")
    private String historicosCotacao;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // restricao
    //
    @Column(name = "RESTRICAO")
    private Character restricao;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // observacao
    //
    @Column(name = "OBSERVACAO")
    private String observacao;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // dataVencimentoSeguro
    //
    @Column(name = "DATA_VENCIMENTO_SEGURO")
    @Temporal(TemporalType.DATE)
    private Date dataVencimentoSeguro;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // analiseCredito
    //
    @JoinColumn(name = "ANALISE_CREDITO_ID", referencedColumnName = "ID")
    @OneToOne(cascade=CascadeType.ALL)
    private AnaliseCredito analiseCredito;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // codSeguradora
    //
    @Column(name = "COD_SEGURADORA")
    private String codSeguradora;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // suframa
    //
    @Column(name = "SUFRAMA")
    private String suframa;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // chamadas
    //
    @OneToMany(mappedBy = "cliente", cascade = {CascadeType.ALL})
    private List<Chamada> chamadas;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // evento
    //
    @JoinColumn(name = "EVENTO_ID", referencedColumnName = "ID")
    @ManyToOne
    private Evento evento;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // sujeitoAnalise
    //
    @Column(name = "SUJEITO_ANALISE")
    private Character sujeitoAnalise;
Função que persiste:
public void update(Observable o, Object m) {
        Evento evt = (Evento) m;
        if (evt == Evento.VISUALIZAR) {
            setCampos();
            desbloqueieCampos(false);
        } else if (evt == Evento.INSERIR) {
            desbloqueieCampos(true);
        } else if (evt == Evento.ALTERAR) {
            desbloqueieCampos(true);
            setCampos();
        } else if (evt == Evento.SALVAR) {
            try {
                Object entidade = getCampos();
                getDatabaseControl().getDatabase().save(entidade);
                desbloqueieCampos(false);
                setCampos();
            } catch (Exception e) {
                //             setCampos();
                e.printStackTrace();
                desbloqueieCampos(true);
                List<String> msgs = new ArrayList<String>();
                msgs.add(e.toString());

                throw new Excecao(msgs);
            }
        } else if (evt == Evento.CANCELAR) {
            desbloqueieCampos(false);
            setCampos();
        } else if (evt == Evento.FECHAR) {
            this.setVisible(false);
        } else if (evt == Evento.EXCLUIR) {
            int resultado = JOptionPane.showConfirmDialog(null, "Você têm certeza que deseja excluir este registro?", "Confirmação de exclusão", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

            if (resultado == JOptionPane.YES_OPTION) {
                try {
                    getDatabaseControl().getDatabase().remove(getCampos());
                    this.setVisible(false);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null, "Ocorreu um erro durante a exclusão do registro.\n" +
                            "Verifique se algum outro registro possui dependência com" +
                            " este registro.", "AVISO", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }
Cliente extende a classe que contém a função acima, logo, o getCampos() do cliente:
@Override
    protected Object getCampos() throws Excecao {

        // PRIMEIRA PARTE
        Pessoa pessoa = getCliente().getPessoa();
        if (campoTipoCliente.getSelectedItem().toString().equals("PF")) {
            pessoa.setTipoPessoa(Pessoa.PESSOA_FISICA);
        } else {
            pessoa.setTipoPessoa(Pessoa.PESSOA_JURIDICA);
        }
        getCliente().setTipoClienteId((TipoCliente) jComboBox1.getSelectedItem());        
        pessoa.setCnpjCpf(campoCNPJcpf.getText());
        pessoa.setIeRg(campoRg.getText());
        pessoa.setNome(campoRazaoSocial.getText());
        pessoa.setNomeFantasia(campoNomeFantasia.getText());
        pessoa.setDataCadastro(campo_dataCadastro.getDate());
        cliente.setEvento((wserp.model.entity.Evento) comboEvento.getSelectedItem());

        pessoa.setObservacao(campoObservacoes.getText());

        pessoa.setSite(campo_endSite.getText());
        pessoa.setEmail(campo_endEmail.getText());
        pessoa.setCelular(campo_contatoPrincCelular.getText());
        pessoa.setTelFax(campo_contatoPrincFax.getText());
        pessoa.setTelefone(campo_contatoPrincTelefone.getText());

        getCliente().setDataCadastro(campo_dataCadastro.getDate());
        getCliente().setSuframa(edSuframa.getText());
try {
            getCliente().getAnaliseCredito().setEmpresa5SaldoLiquidado(Double.parseDouble(edEmpresa5SaldoLiquidado.getText().replace(".", "").replace(",", ".")));
        } catch (Exception e) {}
        //----------------------------------------------------------------------

        //FINANCEIRO------------------------------------------------------------
        getCliente().setReferenciaComercial01(campo_refComerciaisEmpresa1Nome.getText());
        getCliente().setTelRefComercial01(campo_refComerciaisEmpresa1Tel.getText());
        getCliente().setReferenciaComercial02(campo_refComerciaisEmpresa2Nome.getText());
        getCliente().setTelRefComercial02(campo_refComerciaisEmpresa2Tel.getText());
        //Referencias pessoais
        getCliente().setReferenciaPessoal01(campo_refPessoaisEmpresa2Nome.getText());
        getCliente().setTelRefPessoal01(campo_refPessoaisEmpresa2Tel.getText());
        getCliente().setReferenciaPessoal02(campo_refPessoaisEmpresa2Nome.getText());
        getCliente().setTelRefPessoal02(campo_refPessoaisEmpresa2Tel.getText());

        // credito
        if (campo_limiteDeCreditoAprovadoLiberar.isSelected()) {
            getCliente().setCreditoLiberado('1');
        } else {
            getCliente().setCreditoLiberado('0');
        }
        getCliente().setLimiteCredito((Double) campo_limiteDeCreditoAprovado.getValue());
        getCliente().setLimiteCreditoVencimento(campo_limiteCreditoVencimento.getDate());
        getCliente().setDataVencimentoSeguro(campo_vencimentoSeguro.getDate());

        // saldo credito / debito
        if (campo_haSaldoCreditoOuDebito.isSelected()) {
            getCliente().setSaldo('1');
        } else {
            getCliente().setSaldo('0');
        }
        if (campo_haSaldoCreditoOuDebitoValor.getValue() != null) {
            getCliente().setSaldoCredito((Double) campo_haSaldoCreditoOuDebitoValor.getValue());
        }
getCliente().getChamadas().clear();
        getCliente().getChamadas().addAll(listaChamadas);

        return getCliente();

    }
E finalmente o método save() da classe que é extendida:
public Object save(Object object) throws Exception {
        boolean autoCommit = false;
        if (!entityManager.getTransaction().isActive()) {
            entityManager.getTransaction().begin();
            autoCommit = true;
        }
        try {

//            if (!entityManager.contains(object)) {
//                entityManager.refresh(object);
//            }

            object = entityManager.merge(object);
            
            //entityManager.persist(object);
            if ((autoCommit) && (entityManager.getTransaction().isActive())) {
                entityManager.flush();
                entityManager.getTransaction().commit();
            }
        } catch (Exception e) {
            //... (isto estava comentado... está em teste)
            if ((autoCommit) && (entityManager.getTransaction().isActive())) {
                entityManager.getTransaction().rollback();
            }
            //...
            throw e;
        }
        return object;
    }
lcn.andre

Fazendo um debug, encontrei o problema, mas não consegui resolver. No form, defini valor 1 para Suframa e mandei gravar. A função foi chamada e o objeto cliente ficou com valor 1 para o atributo em questão. Isso, até chegar na função merge. Assim que o objeto passa pelo merge, o atributo suframa fica null.
Alguém sabe o que pode estar acontecendo? :roll:

lcn.andre

Acabei de descobrir que no nosso banco também acontece o mesmo problema com alguns clientes. :evil:

lcn.andre

Poxa, ninguem? :frowning:

Eis o esquema:
ENDERECO->PESSOA<-CLIENTE->ANALISE_CREDITO

O que acontece é o seguinte: alguns clientes ele está salvando perfeitamente, já outros, ele só salva os dados nas tabelas ENDERECO, PESSOA e ANALISE_CREDITO, mas nada do que foi alterado é guardado na própria tabela CLIENTE.

Já quebrei muito a cabeça com isso, mas não consigo pensar numa explicação lógica para o que está acontecendo. Ainda mais que só acontece com alguns clientes.

EDIT: -----------------------------
Não acredito nisso! O erro estava logo no construtor da minha tela. :evil:

//cliente = (Cliente) transaction.getDatabase().findById(Cliente.class, id); cliente = (Cliente) entityManager.find(Cliente.class, id);

hvivox

Fala parceiro,
Acredito q só vc pode resolver essa questão! dei uma pesquisada no merge()! Vc sabia que ele pode ALTERAR E INSERIR dados dependendo da situação! Isso pode ser perigoso.

Talvez isso esclareça algo: assim merge() é utilizado quando vc tenta alterar dados desligados! caso ele não encontre dados no banco igual as que vc tenta alterar ele acaba inserindo dos dados. Isso é muito perigoso. “Vc mencionou SUFRAMA”?

Da uma olhada no livro hibernete persistence com JPA capitulo 9.2 e 9.3, tenho certeza que vai esclarecer

Criado 22 de janeiro de 2010
Ultima resposta 26 de jan. de 2010
Respostas 6
Participantes 3