2013-08-20 77 views
1

MyEntity是一個帶有生成ID的傳統JPA實體。我想自動設置一個字段(myStringField)爲基於id的值。在這個例子中,如果ID是43,我想將它設置爲「foo43」。在@PostPersist中修改的字段在DB中未更新

由於id由數據庫自動生成,所以在em.persist(myEntity)調用之前它爲null。但是在持久化之後,它有一個由Hibernate分配的ID(在DB序列上稱爲NEXTVAL)。所以,我雖然聲明@PostPersist方法,如下的:

package ...; 

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.persistence.PostPersist; 


@Entity 
public class MyEntity { 

    @Id @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 

    private String myStringField; 

    @PostPersist 
    public void postPersist(){ 
     System.out.println("The id = " + id); 
     this.myStringField = "foo" + id; 
    } 

    public String getMyStringField() { 
     return myStringField; 
    } 
    ... 
} 

下面是一些用於創建和持續存在的實體代碼:

package ...; 

import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 

import org.springframework.stereotype.Service; 
import org.springframework.transaction.annotation.Transactional; 

@Transactional 
@Service 
public class MySpringBean { 
    @PersistenceContext EntityManager em; 

    public void createMyEntity() { 
     MyEntity myEntity = new MyEntity(); 
     em.persist(myEntity); 
     System.out.println(myEntity.getMyStringField()); 
    } 
} 

它輸出以下:

The id = 47 
foo47 

這很好。但是,在數據庫中,myStringField字段爲空!有人知道爲什麼嗎?

我的確希望實體在MyEntity.postPersist()方法期間被標記爲骯髒,並且在刷新期間更新將在事務結束時發生。但實際上不是。

我使用Hibernate V4.2.4

是否有人知道爲什麼這個數據庫記錄有一個空值?

回答

0

你正在做它後堅持,所以它發生後寫入數據庫。

根據回答JPA @PostPersist usage規範狀態

These database operations may occur directly after the persist, merge, or remove operations have been invoked or they may occur directly after a flush operation has occurred

0

的@PostPersist代碼myEntity所運行後保存。因此,如果您想確保myStringField字段以更新後的值保存:「foo」+ id,那麼在@PostPersist代碼後,您需要再次保存該實體。

所以,如果你改變你的代碼:

MyEntity myEntity = new MyEntity(); 
    em.persist(myEntity); 
    em.persist(myEntity); 

這在理論上應該正確保存更新myStringField。雖然這有點尷尬。不確定你的整個用例,但是你可以考慮在數據庫本身寫一個'插入觸發器'來爲你處理這件事。

1

就是這樣!我做了額外的測試,實際上,在刷新過程中調用@PostPersist(可能是因爲SQL INSERT是在刷新期間發送的)。因此,總結一下,按照以下順序進行:1. em.persist(),1.1 NEXTVAL發送到數據庫,myEntity.id被分配,@Transactional方法的2端到達並執行刷新。 2.1 INSERT發送到數據庫。 2.2 @PostPersist調用。 2.2.1 myEntity.myStringField被分配並且實體很髒。然後不執行進一步的刷新(和髒檢查和更新)=>沒有數據庫保存。非常感謝!!!

1

使用

@PrePersist 

代替,但你的方法用磁場產生不適合我是正確的,因爲如果你的myStringField即將成爲一個業務ID,從JPA ID不同,你應該假設它是在創建bean初始化。

關於如何處理業務ID的詳細例子,我建議您看到這個主題有關的equals()/ hashCode()方法的困境,並專門這樣的響應:https://stackoverflow.com/a/5103360/2598693

0

要回答你的問題,你不應該在你的數據層做這樣的事情。該插入和更新應該由業務邏輯層處理。

但是,如果您真的需要在數據層中使用@PrePersist。