JPA merge() aktualisiert nur einige Felder. Andere Änderungen werden nicht erkanntJava

Java-Forum
Anonymous
 JPA merge() aktualisiert nur einige Felder. Andere Änderungen werden nicht erkannt

Post by Anonymous »

Dies ist mein erster Beitrag. Ich hoffe also, dass die Frage spannend ist.
Ich habe ein Java-Programm, das Swing+JPA verwendet, um mit einer
PostgreSQL-Datenbank zu arbeiten. Ich verwende EclipseLink JPA 2.0 als meinen
Persistenzanbieter. Meine Entitätsklasse wurde automatisch
von Netbeans 7.2.1 generiert

Das Problem, mit dem ich konfrontiert bin, ist: Während einer Aktualisierung ändere ich vier
Felder eines Objekts, das mit find() abgerufen wurde, und verwende dann
merge(), um das Objekt in der Datenbank zu aktualisieren. Drei von
vier Änderungen werden in der Tabelle erkannt und aktualisiert,
eine davon wird jedoch nicht aktualisiert.

Ich habe mehrere Dinge versucht, um dieses Problem zu umgehen: Ich habe versucht, die Optionen im Zusammenhang mit der Synchronisierungsstrategie meiner persistenten Einheit zu ändern, die Zeilenposition im Code zu ändern (da andere Felder aktualisiert werden), ich habe auch versucht, dem Entity Class-Feld die Annotation @Basic (optional = false) voranzustellen. Jeder meiner Versuche hat funktioniert.

Hier ist der Code meiner Entity Class (Senha.java):

Code: Select all

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;

/**
*
* @author Diego Dias
*/
@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 = :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) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Senha)) {
return false;
}
Senha other = (Senha) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}

@Override
public String toString() {
return "model.Senha[ id=" + id + " ]";
}

}
Hier ist der relevante Code der Methode, die mein Objekt aktualisiert. Der darin enthaltene Code hat keine Auswirkungen auf das Objekt.

Code: Select all

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();
Wenn ich in der Datenbank nachschaue, werden die Felder Status Hchamada und Nchamadas aktualisiert, aber das Feld Painel (vom Typ Boolean) wird nicht aktualisiert. Nachfolgend präsentiere ich einen Auszug der Protokollierung von JPA/EclipseLink:

Code: Select all

**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**
Wenn ich mir den Code ansehe, füge ich ein „If“ ein, bevor ich den Wert ändere, um zu sehen, ob die von JPA verwaltete Entität bereits den Wert hat, den ich festlegen möchte. Hier ist der geänderte Code:

Code: Select all

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();
Wenn ich den Code ausführe, erhalte ich die Meldung, dass meine Entität bereits mit dem Wert festgelegt ist, den ich in die Datenbank schreiben möchte. Ich denke also, dass JPA/EclipseLink den Wert nicht aktualisiert, wenn er sich in Bezug auf die von ihm verwaltete Entitätsklasse nicht ändert. Bevor ich den Code ausführe, habe ich jedoch das Datenbankfeld „painel“ manuell auf „false“ aktualisiert. Dann:
  • Ich habe nicht verstanden, warum dieses Update beim Abrufen der Entität nicht erkannt wird.
  • Wie kann ich JPA zwingen, alle Felder zu aktualisieren (auch die, die sich nicht ändern)?
MÖGLICHE (NICHT GUTE) LÖSUNG:

Gerade als ich diese Nachricht gepostet habe, wurde mir klar eine mögliche Lösung (nicht so gut). Ändern Sie den Code vor der Aktualisierung, um die Entität aus der Datenbank zu entfernen (durch einen Commit), und starten Sie dann eine andere Transaktion, um das Objekt zu aktualisieren. Es geht darum, das Objekt zu entfernen und erneut beizubehalten. Es funktioniert.

Vorher habe ich versucht, „remove()“ und „merge()“ innerhalb derselben Transaktion zu verwenden, aber es hat nicht funktioniert.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post