This is my first post. Therefore, I hope this question is fascinating. I have a Java program that uses Swing + JPA to work with a PostgreSQL database. I use EclipseLink JPA 2.0 as my Sustainability Provider. My Entity class was automatically created by Netbeans 7.2.1
The problem I am facing: during the update, I change the four fields of the object obtained with find (), then I use merge () to update the object in the database. Three four changes are recognized and updated in the table, but one of them is not updated.
I tried several things to get around this problem: I tried changing the parameters associated with the synchronization strategy of my permanent device, changing the position of the line in the code (as other fields were updated), I also tried to prefix the Entity class field with the @Basic annotation (optional = false). Any of my attemps worked.
Here is the code for my entity class (Senha.java):
package model; import java.io.Serializable; import java.util.Date; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.xml.bind.annotation.XmlRootElement; @Entity @Table(name = "senha") @XmlRootElement @NamedQueries({ @NamedQuery(name = "Senha.findAll", query = "SELECT s FROM Senha s"), @NamedQuery(name = "Senha.findById", query = "SELECT s FROM Senha s WHERE s.id = :id"), @NamedQuery(name = "Senha.findByGuiche", query = "SELECT s FROM Senha s WHERE s.guiche = :guiche"), @NamedQuery(name = "Senha.findByStatus", query = "SELECT s FROM Senha s WHERE s.status = :status"), @NamedQuery(name = "Senha.findByHchamada", query = "SELECT s FROM Senha s WHERE s.hchamada = :hchamada"), @NamedQuery(name = "Senha.findByAtendente", query = "SELECT s FROM Senha s WHERE s.atendente = :atendente"), @NamedQuery(name = "Senha.findByHcriacao", query = "SELECT s FROM Senha s WHERE s.hcriacao = :hcriacao"), @NamedQuery(name = "Senha.findByDtcriacao", query = "SELECT s FROM Senha s WHERE s.dtcriacao = :dtcriacao"), @NamedQuery(name = "Senha.findByNumeracao", query = "SELECT s FROM Senha s WHERE s.numeracao = :numeracao"), @NamedQuery(name = "Senha.findByNchamadas", query = "SELECT s FROM Senha s WHERE s.nchamadas = :nchamadas"), @NamedQuery(name = "Senha.findByPainel", query = "SELECT s FROM Senha s WHERE s.painel = :painel"), @NamedQuery(name = "Senha.findMaxNumeracaoByDtcriacao", query = "SELECT MAX(s.numeracao) FROM Senha s WHERE s.dtcriacao = :dtcriacao"), @NamedQuery(name = "Senha.findByStatusAndHchamadaAndHcriacao", query = "SELECT s FROM Senha s WHERE s.status = :status AND s.hchamada <= :hchamada AND s.hcriacao >= :hcriacao")}) public class Senha implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") private Integer id; @Column(name = "guiche") private String guiche; @Column(name = "status") private Character status; @Column(name = "hchamada") @Temporal(TemporalType.TIME) private Date hchamada; @Column(name = "atendente") private Integer atendente; @Column(name = "hcriacao") @Temporal(TemporalType.TIME) private Date hcriacao; @Column(name = "dtcriacao") @Temporal(TemporalType.DATE) private Date dtcriacao; @Column(name = "numeracao") private Integer numeracao; @Column(name = "nchamadas") private Integer nchamadas; @Column(name = "painel") private Boolean painel; public Senha() { } public Senha(Integer id) { this.id = id; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getGuiche() { return guiche; } public void setGuiche(String guiche) { this.guiche = guiche; } public Character getStatus() { return status; } public void setStatus(Character status) { this.status = status; } public Date getHchamada() { return hchamada; } public void setHchamada(Date hchamada) { this.hchamada = hchamada; } public Integer getAtendente() { return atendente; } public void setAtendente(Integer atendente) { this.atendente = atendente; } public Date getHcriacao() { return hcriacao; } public void setHcriacao(Date hcriacao) { this.hcriacao = hcriacao; } public Date getDtcriacao() { return dtcriacao; } public void setDtcriacao(Date dtcriacao) { this.dtcriacao = dtcriacao; } public Integer getNumeracao() { return numeracao; } public void setNumeracao(Integer numeracao) { this.numeracao = numeracao; } public Integer getNchamadas() { return nchamadas; } public void setNchamadas(Integer nchamadas) { this.nchamadas = nchamadas; } public Boolean getPainel() { return painel; } public void setPainel(Boolean painel) { this.painel = painel; } @Override public int hashCode() { int hash = 0; hash += (id != null ? id.hashCode() : 0); return hash; } @Override public boolean equals(Object object) {
Here is the corresponding method code that updates my object . The code inside ... does not affect the object.
EntityManagerFactory emf = ctrlCreateEntityManager(); EntityManager em = emf.createEntityManager(); ... current = em.find(Senha.class, getCurrentId()); if (current.getStatus().equals('W')) { em.getTransaction().begin(); current.setStatus(current.getNchamadas() >= 2 ? 'L' : current.getStatus()); current.setHchamada(Calendar.getInstance().getTime()); current.setNchamadas(current.getNchamadas() + 1); current.setPainel(true); em.merge(current); em.getTransaction().commit(); frame.getLbNumeroSenha().setText(formatSenha(current.getNumeracao())); } ... em.close(); emf.close();
When I look in the database, the Status Hchamada, Nchamadas fields are updated, but the Painel field (like boolean) is not updated. Follow the publication of excerpts from JPA / EclipseLink:
**begin transaction** **[EL Fine]**: Thread(Thread[AWT-EventQueue-1,4,file:...-threadGroup])--UPDATE senha SET hchamada = ?, nchamadas = ? WHERE (id = ?) bind => [02:15:49, 2, 4] **[EL Finer]**: Thread(Thread[AWT-EventQueue-1,4,file:...-threadGroup]) **commit transaction**
Having looked at the code, I put an if before changing the value to see if the object controlled by the JPA already has the value I want to set. Here is the code that has been modified:
EntityManagerFactory emf = ctrlCreateEntityManager(); EntityManager em = emf.createEntityManager(); ... current = em.find(Senha.class, getCurrentId()); if (current.getStatus().equals('W')) { em.getTransaction().begin(); current.setStatus(current.getNchamadas() >= 2 ? 'L' : current.getStatus()); current.setHchamada(Calendar.getInstance().getTime()); current.setNchamadas(current.getNchamadas() + 1); if (current.getPainel()) { System.out.println("Painel is already true"); } current.setPainel(true); em.merge(current); em.getTransaction().commit(); frame.getLbNumeroSenha().setText(formatSenha(current.getNumeracao())); } ... em.close(); emf.close();
When I run the code, I received a message that indicates that my object is already set with the value that I want to write to the database. So, I think JPA / EclipseLink does not update the value if it does not change with respect to the entity class managed by it. However, before I run the code, I manually update the database painel file to false. THEN:
- I did not understand why this update is not recognized when retrieving the object.
- How to force JPA to update all fields (even if they do not change)?
POSSIBLE (NOT MUST) DECISION:
Just at the time of publication of this message, I realized a possible solution (not very good). Modify the code before updating to remove the object from the database (giving a commit), and then start another transaction by updating the object. This, deleting and saving the object again. It is working.
Before I tried to use remove () and merge () inside the same transaction, but that didn't work.