2015-03-03 167 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。其解决方案可以扭转任务 - 持有有关变更审计的信息。但它存储的信息适合您的任务格式。