2013-03-13 74 views
4

這是我的第一篇文章。所以,我希望這個問題很令人興奮。 我有一個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:

  1. 我不明白爲什麼在檢索實體時無法識別此更新。
  2. 如何強制JPA更新所有字段(即使不更改)?

可能的(不太好)解決方案:

就在後的那一刻這個消息,我實現了一個可能的解決方案(不太好)。在更新之前修改代碼以從數據庫中刪除實體(提交提交),然後啓動其他事務,更新對象。它是,再次移除並堅持對象。有用。

在我嘗試在相同的事務中使用remove()和merge(),但它沒有工作。

+1

您是否嘗試過不同的列定義?例如,請參閱http://stackoverflow.com/questions/3988046/jpa-configure-boolean-fields-to-persist-as-integers。 – SpaceTrucker 2013-03-13 07:49:13

+0

嗨@SpaceTrucker,我試着改變字段的數據類型,以及表中列的順序,並試圖將註釋保存爲整數。但是其中任何一個解決問題。 JPA繼續從數據庫中檢索具有未用最新值更新的字段「painel」的值。 – 2013-03-13 15:12:17

+0

另外兩種可能性: 1.配置em.find()以使用PESSIMISTIC LOCKING。 2.使用find()沒有指定鎖定後,使用em.refresh(object)。 – 2013-03-13 15:39:15

回答

2

根據具體實現情況,您的情況下使用EclipseLink,JPA 將始終插入所有映射列,並且只會更新已更改的列。如果需要其他操作,則可以使用API​​,SQL或存儲過程來自定義用於這些操作的查詢。

您可以使用Hibernate dynamicInsert和dynamicUpdate修改此行爲,但不能使用EclipseLink。這些遷移指南告訴你。

相關問題