這是我的第一篇文章。所以,我希望這個問題很令人興奮。 我有一個Java程序,它使用Swing + JPA與 PostgreSQL數據庫一起使用。我使用EclipseLink JPA 2.0作爲我的 持久性提供程序。我的實體類自動是 通過Netbeans的產生7.2.1JPA merge()只更新一些字段。其他變化不承認
我面臨的問題是:一個更新期間,更改)使用find(檢索對象的4個 字段,然後我使用 合併()來更新對象在數據庫中。 三個變化在表中被識別和更新, 但其中一個未更新。
我嘗試了幾件事情來解決這個問題:我試圖改變與持久單元的同步策略相關的選項,更改代碼中的行位置(當其他字段被更新時),我也嘗試過前綴實體類字段與註釋@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**
展望的代碼,我放了,如果之前更改值,看是否由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。 THen:
- 我不明白爲什麼在檢索實體時無法識別此更新。
- 如何強制JPA更新所有字段(即使不更改)?
可能的(不太好)解決方案:
就在後的那一刻這個消息,我實現了一個可能的解決方案(不太好)。在更新之前修改代碼以從數據庫中刪除實體(提交提交),然後啓動其他事務,更新對象。它是,再次移除並堅持對象。有用。
在我嘗試在相同的事務中使用remove()和merge(),但它沒有工作。
您是否嘗試過不同的列定義?例如,請參閱http://stackoverflow.com/questions/3988046/jpa-configure-boolean-fields-to-persist-as-integers。 – SpaceTrucker 2013-03-13 07:49:13
嗨@SpaceTrucker,我試着改變字段的數據類型,以及表中列的順序,並試圖將註釋保存爲整數。但是其中任何一個解決問題。 JPA繼續從數據庫中檢索具有未用最新值更新的字段「painel」的值。 – 2013-03-13 15:12:17
另外兩種可能性: 1.配置em.find()以使用PESSIMISTIC LOCKING。 2.使用find()沒有指定鎖定後,使用em.refresh(object)。 – 2013-03-13 15:39:15