2015-12-15 21 views
13

Ho una persistenza eredità classica con gli enti controllanti e Bambino, dove Bambino estende Parent. Classe Parent è astratto, mentre Child non lo è.Hibernate Envers: @Audited su una sottoclasse

Voglio verificare Bambino. Questa entità è sotto il mio controllo, mentre Parent non lo è. Inoltre, ha molte altre sottoclassi che non devono essere controllate. La strategia di ereditarietà dell'intera gerarchia è JOINED.

così ho annotato Bambino con @Audited e inoltre con @AuditOverride (forClass = Parent.class).

quello che ottengo è questo errore:

"org.hibernate.MappingException: Entity 'Child' is audited, but its superclass: 'Parent' is not."

A proposito, sto usando la versione envers 4.0.1.Final.

Qualcuno sa come posso ottenere questo? Ho provato a rimuovere @Audited in Bambino classe, eliminando @AuditOverride, utilizzando deprecato auditParents in @Audited annotazione, ma nulla sembra funzionare.

questo sia il soggetto capogruppo:

@Entity 
@Table(name = "parent") 
@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn(name = "type") 
public class Parent { 
    public Parent() { 
     super(); 
    } 

    @Id 
    @GeneratedValue(strategy = IDENTITY) 
    @Column(name = "base_id", unique = true, nullable = false) 
    private Integer baseId; 

    @Column(name = "base_field") 
    private String baseField; 

    @Column(name = "type") 
    private String type; 

    // getters and setters 
} 

E questa è la mia entità del bambino:

@Entity 
@Table(name = "child") 
@DiscriminatorValue("CHILD") 
@Audited 
@AuditOverride(forClass = Parent.class) 
public class Child extends Parent { 
    public Child() { 
     super(); 
    } 

    @Column(name = "child_field") 
    private String childField; 

    // getters and setters 
} 

Questo sono le entità:

CREATE TABLE `REVINFO` (
    `REV` BIGINT NOT NULL AUTO_INCREMENT, 
    `REVTSTMP` BIGINT NULL , 
    PRIMARY KEY (`REV`) 
); 

CREATE TABLE `parent` (
    `base_id` int(11) NOT NULL AUTO_INCREMENT, 
    `base_field` varchar(45) DEFAULT NULL, 
    `type` varchar(45) NOT NULL, 
    PRIMARY KEY (`base_id`) 
); 

CREATE TABLE `child` (
    `base_id` int(11) NOT NULL AUTO_INCREMENT, 
    `child_field` varchar(45) DEFAULT NULL, 
    PRIMARY KEY (`base_id`) 
); 

CREATE TABLE `child_AUD` (
    `base_id` int(11) NOT NULL, 
    `REV` BIGINT NOT NULL, 
    `REVTYPE` tinyint(2) DEFAULT NULL, 
    `child_field` varchar(45) DEFAULT NULL, 
    PRIMARY KEY (`base_id`,`REV`) 
); 

ecco un banco di prova:

public class EnversInheritanceTest extends AbstractJUnit4SpringContextTests { 

    @Inject 
    private EntityManagerFactory entityManagerFactory; 

    private EntityManager entityManager; 

    @Test 
    public void inheritanceTest() { 

     this.entityManager = this.entityManagerFactory.createEntityManager(); 

     Child child = this.createChild(); 
     this.saveChild(child); 

     this.modifyChild(child); 
     this.saveChild(child); 

     Assert.assertNotNull(child.getBaseId()); 
     Assert.assertNotNull(this.getOriginalRevision(child.getBaseId())); 

     Child original = this.getOriginalChild(child.getBaseId()); 

     Assert.assertNotNull(original); 
     Assert.assertEquals("child", original.getChildField()); 

    } 

    private Child createChild() { 
     Child child = new Child(); 
     child.setBaseField("base"); 
     child.setChildField("child"); 
     child.setType("CHILD"); 
     return child; 
    } 

    private void saveChild(Child child) { 
     this.entityManager.getTransaction().begin(); 
     this.entityManager.persist(child); 
     // We need to commit in order to trigger Envers magic 
     this.entityManager.getTransaction().commit(); 
    } 

    private void modifyChild(Child child) { 
     child.setBaseField("foo"); 
     child.setChildField("bar"); 
    } 

    public Child getOriginalChild(Serializable id) { 
     Object queryResult = this.getAuditReader().createQuery() 
       .forEntitiesAtRevision(Child.class, this.getOriginalRevision(id)) 
       .add(AuditEntity.id().eq(id)) 
       .getSingleResult(); 
     return (Child) queryResult; 
    } 

    private Number getOriginalRevision(Serializable id) { 
     AuditProjection minRevNumberAuditProjection = AuditEntity.revisionNumber().min(); 
     Number revision = (Number) this.getAuditReader().createQuery() 
       .forRevisionsOfEntity(Child.class, false, false) 
       .add(AuditEntity.id().eq(id)) 
       .addProjection(minRevNumberAuditProjection) 
       .getSingleResult(); 

     return revision; 
    } 

    private AuditReader getAuditReader() { 
     return AuditReaderFactory.get(this.entityManager); 
    } 

} 

E infine ecco una patata:

Potato image

Grazie in anticipo!

+0

Molto probabilmente si tratta di un bug in 'hibernate-envers'. Vedi: https://forum.hibernate.org/viewtopic.php?p=2489543 – Andremoniy

+0

Tale mappatura funziona bene in ibernazione 5. Una soluzione potrebbe essere quella di aggiornare lo stato di ibernazione. –

risposta

2

Ottima domanda. Ci era same discussion sul forum degli sviluppatori jboss nell'anno 2013. E la risposta è stata da the founder and project lead of Hibernate Enver:

You would have to get the superclass audited somehow. Currently there's no other way to specify such metadata except for annotations.

Nella stessa struttura di discussione in base al fatto che la classe padre dovrebbe essere lì annotato anche stato suggerito loro annotate in fase di esecuzione. Ma questa decisione sembra brutta e non è adatta al tuo caso: puoi annotare manualmente la classe genitore.

Come soluzione alternativa, se non si vuole classe genitore sottoposto a controllo, si può provare a creare base astratta MappedSuperClass che essenzialmente sarà stesso Parent, mentre Parent sarà solo il suo discendente, e quindi provare @AuditOverride nuovo per Child di classe. È possibile che esegua il controllo "salta" per la classe Parent e lo faccia per Child.