2015-03-03 168 views
1

我需要實現歷史化,因爲我們必須爲任何更新的記錄創建新記錄。所有記錄都有一個刪除並插入的日期。因此,我們所做的是在更新時將已刪除的日期設置爲NOW,並插入插入日期爲NOW並刪除日期爲NULL的新記錄。使用JPA進行歷史記錄

我使用JPA和eclipseLink作爲持久提供者。我的問題是,當JPA認爲需要更新時,我需要執行「額外」插入操作。到目前爲止,我已經在非元數據字段的實體上設置了updatable = false。我更新了插入日期和刪除日期以及用戶名。哪一個按預期工作。我現在需要做的就是製作額外的插頁。

我想解決這個問題,使用entityListener,其中我實現@postUpdate和@preUpdate。如果我嘗試提交我在@postUpdate上執行的新事務,那麼我無法使其工作,因爲我最終陷入僵局。如果我沒有創建一個新的EntityManager和一個事務,而僅僅是在現有的EntityManager上持續存在調用,出於某種原因,「新」實體不會發生任何事情。下面

代碼:

import java.util.Calendar; 

import javax.persistence.EntityManager; 
import javax.persistence.EntityManagerFactory; 
import javax.persistence.Persistence; 
import javax.persistence.PostPersist; 
import javax.persistence.PostUpdate; 
import javax.persistence.PreUpdate; 

public class ColorEntityListener { 

    public ColorEntityListener() 
    {  
    } 

    @PreUpdate 
    void onPreUpdate(ColorEntity c) 
    { 
     System.out.println("onPreUpdate"); 
     c.setDeletionDate(Calendar.getInstance());  
    } 

    @PostUpdate 
    void onPostUpdate(ColorEntity c) 
    { 
     System.out.println("onPostUpdate"); 
     createNewRecord(c); 
    } 

    @PostPersist 
    void onPostPersist(ColorEntity c) 
    { 
     System.out.println("onPostPersist"); 
    } 

    private void createNewRecord(ColorEntity c) { 
     EntityManagerFactory factory = Persistence.createEntityManagerFactory("v2_tl"); 
     EntityManager em = factory.createEntityManager(); 

     em.getTransaction().begin(); 

     ColorEntity cNew = new ColorEntity(); 
     cNew.setPrNumber(c.getPrNumber()); 
     cNew.setHs(c.getHs()); 
     cNew.setCountryCode(c.getCountryCode()); 
     cNew.setValidFrom(c.getValidFrom()); 
     cNew.setValidUntil(c.getValidUntil()); 
     cNew.setColorCode(c.getColorCode()); 

     //cNew.setId(0); 
     cNew.setInsertDate(Calendar.getInstance()); 
     cNew.setDeletionDate(null); 

     em.persist(cNew); 

     System.out.println("Before commit of new record"); 
     em.getTransaction().commit(); 
     System.out.println("After commit of new record"); 
    } 
} 
+0

插入和刪除日期是多餘的,如果由於某種原因刪除日期與下一個插入日期之間存在間隙,可能會導致您遇到麻煩。特別是如果你在你的例子中設置日期,因爲不同的方法可能會在'Calendar.getInstance()'返回一個接一個的值時執行。 – SpaceTrucker 2015-03-03 08:18:16

+0

相關:http://stackoverflow.com/questions/9542366/how-to-implement-a-temporal-table-using-jpa – SpaceTrucker 2015-03-03 08:22:39

+0

顯然,在完成的例子中,我將日曆設置爲本地對象,並將其用於兩者聲明。我很好奇,但是如何指示刪除的行沒有刪除日期? – Michael 2015-03-03 12:59:26

回答

2

的EclipseLink已經內置支持歷史通過添加@Customizer。 請參閱此鏈接瞭解如何使用它的一個例子:

http://wiki.eclipse.org/EclipseLink/Examples/JPA/History

+0

據我所知,如果你想將數據存儲在一個單獨的歷史表中,它只能解決這個問題。我們想要的是將數據存儲在實體所屬的同一個表中。 – Michael 2015-03-03 12:00:51

1

請看看hibernate envers project。其解決方案可以扭轉任務 - 持有有關變更審計的信息。但它存儲的信息適合您的任務格式。