这是我的第一篇文章。所以,我希望这个问题令人兴奋。 我有一个使用Swing + JPA来处理的java程序 PostgreSQL数据库。我使用EclipseLink JPA 2.0作为我的 持久性提供者。我的实体类是自动的 由Netbeans 7.2.1生成
我面临的问题是:在更新过程中,我改变了四个 使用find()检索对象的字段,然后我使用 merge()更新数据库中的对象。三个 表中识别并更新了四个更改, 但其中一个没有更新。
我尝试了几个方法来解决这个问题:我尝试更改与持久性单元的同步策略相关的选项,更改代码中的行位置(因为其他字段已更新),我也尝试使用前缀注释为@Basic的实体类字段(可选= false)。我的任何一个尝试都有效。
以下是我的实体类(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;
/**
*
* @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 <= :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) {
// 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 + " ]";
}
}
以下是更新我的对象的方法的相关代码。里面的代码......不会影响对象。
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();
当我查看数据库时,状态Hchamada,Nchamadas字段已更新,但字段Painel(类型为boolean)未更新。接下来我将介绍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**
查看代码,我在更改值之前添加了一个if,以查看JPA管理的实体是否已经设置了我想要设置的值。这是修改后的代码:
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();
当我运行代码时,我收到的消息表明我的实体已经设置了我想在数据库中写入的值。所以,我认为如果JPA / EclipseLink相对于它管理的实体类没有改变,它就不会更新该值。但是,在运行代码之前,我手动将数据库字段painel更新为false。然后:
可能(不是那么好)解决方案:
就在发布此消息的那一刻,我意识到了一种可能的解决方案(不太好)。在更新之前修改代码以从数据库中删除实体(给出提交),然后启动其他事务,更新对象。它是,再次删除和持久化对象。有用。
在我尝试在同一个事务中使用remove()和merge()之前,它没有用。
答案 0 :(得分:2)
根据实现情况,在您的情况下,JPA 将始终插入所有已映射的列,并且仅更新已更改的列。如果需要备用操作,则可以使用API,SQL或存储过程自定义用于这些操作的查询。
您可以使用Hibernate dynamicInsert和dynamicUpdate修改此行为,但不能使用EclipseLink。这些迁移指南告诉您。