Merge só salva alguns dados?

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.

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

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:

[code]@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 chamadas;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// evento
//
@JoinColumn(name = “EVENTO_ID”, referencedColumnName = “ID”)
@ManyToOne
private Evento evento;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// sujeitoAnalise
//
@Column(name = “SUJEITO_ANALISE”)
private Character sujeitoAnalise;[/code]

Função que persiste:

[code]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 msgs = new ArrayList();
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);
            }
        }
    }
}[/code]

Cliente extende a classe que contém a função acima, logo, o getCampos() do cliente:

[code]@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();

}[/code]

E finalmente o método save() da classe que é extendida:

[code]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;
}[/code]

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:

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

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);

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