diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/EmbeddableWithCollectionTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/EmbeddableWithCollectionTest.java new file mode 100644 index 0000000000..aaf3d338a7 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/EmbeddableWithCollectionTest.java @@ -0,0 +1,269 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test.integration.components; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OrderColumn; +import javax.persistence.Table; + +import org.hibernate.envers.AuditMappedBy; +import org.hibernate.envers.Audited; +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.transaction.TransactionUtil; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Chris Cranford + */ +@TestForIssue(jiraKey = "HHH-9108") +public class EmbeddableWithCollectionTest extends BaseEnversJPAFunctionalTestCase { + private Long headerId; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Header.class, Item.class }; + } + + @Test + @Priority(10) + public void initData() { + // Revision 1 + headerId = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + Header h1 = new Header( "h1" ); + h1.addItem( new Item( "h1-item0", h1 ) ); + h1.addItem( new Item( "h1-item1", h1 ) ); + entityManager.persist( h1 ); + return h1.getId(); + } ); + + // Revision 2 + TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + final Header header = entityManager.find( Header.class, headerId ); + header.addItem( new Item( "h1-item2", header ) ); + entityManager.merge( header ); + } ); + + // Revision 3 + TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + final Header header = entityManager.find( Header.class, headerId ); + header.removeItem( header.getEmbeddableWithCollection().getItems().get( 0 ) ); + entityManager.merge( header ); + } ); + + // Revision 4 + TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + final Header header = entityManager.find( Header.class, headerId ); + header.setEmbeddableWithCollection( null ); + entityManager.merge( header ); + } ); + } + + @Test + public void testRevisionCounts() { + assertEquals( Arrays.asList( 1, 2, 3, 4 ), getAuditReader().getRevisions( Header.class, headerId ) ); + } + + @Test + public void testRevisionHistory() { + final Header rev1 = getAuditReader().find( Header.class, headerId, 1 ); + assertEquals( 2, rev1.getEmbeddableWithCollection().getItems().size() ); + assertEquals( "h1-item0", rev1.getEmbeddableWithCollection().getItems().get( 0 ).getName() ); + assertEquals( "h1-item1", rev1.getEmbeddableWithCollection().getItems().get( 1 ).getName() ); + + final Header rev2 = getAuditReader().find( Header.class, headerId, 2 ); + assertEquals( 3, rev2.getEmbeddableWithCollection().getItems().size() ); + assertEquals( "h1-item0", rev2.getEmbeddableWithCollection().getItems().get( 0 ).getName() ); + assertEquals( "h1-item1", rev2.getEmbeddableWithCollection().getItems().get( 1 ).getName() ); + assertEquals( "h1-item2", rev2.getEmbeddableWithCollection().getItems().get( 2 ).getName() ); + + final Header rev3 = getAuditReader().find( Header.class, headerId, 3 ); + assertEquals( 2, rev3.getEmbeddableWithCollection().getItems().size() ); + assertEquals( "h1-item1", rev3.getEmbeddableWithCollection().getItems().get( 0 ).getName() ); + assertEquals( "h1-item2", rev3.getEmbeddableWithCollection().getItems().get( 1 ).getName() ); + + final Header rev4 = getAuditReader().find( Header.class, headerId, 4 ); + assertEquals( 0, rev4.getEmbeddableWithCollection().getItems().size() ); + } + + @Entity(name = "Header") + @Table(name = "ENVERS_HEADER") + @Audited + public static class Header { + private Long id; + private String name; + private EmbeddableWithCollection embeddableWithCollection; + + Header() { + + } + + Header(String name) { + this.name = name; + } + + Header(Long id, String name) { + this( name ); + this.id = id; + } + + @Id + @GeneratedValue + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Embedded + public EmbeddableWithCollection getEmbeddableWithCollection() { + return embeddableWithCollection; + } + + public void setEmbeddableWithCollection(EmbeddableWithCollection embeddableWithCollection) { + if ( embeddableWithCollection != null ) { + this.embeddableWithCollection = embeddableWithCollection; + } + else if ( this.embeddableWithCollection != null ) { + this.embeddableWithCollection.getItems().clear(); + } + } + + public void addItem(Item item) { + if ( this.embeddableWithCollection == null ) { + this.embeddableWithCollection = new EmbeddableWithCollection(); + } + this.embeddableWithCollection.addItem( item ); + } + + public void removeItem(Item item) { + if ( this.embeddableWithCollection != null ) { + this.embeddableWithCollection.removeItem( item ); + } + } + } + + @Entity(name = "Item") + @Table(name = "ENVERS_ITEM") + @Audited + public static class Item { + private Long id; + private String name; + private Header header; + private Integer position; + + Item() { + + } + + Item(String name, Header header) { + this.name = name; + this.header = header; + } + + Item(Long id, String name, Header header) { + this( name, header ); + this.id = id; + } + + @Id + @GeneratedValue + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @ManyToOne + @JoinColumn(name = "C_HDR", insertable = false, updatable = false, nullable = false) + public Header getHeader() { + return header; + } + + public void setHeader(Header header) { + this.header = header; + } + + @Column(name = "C_POSITION", insertable = false, updatable = false) + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + } + + @Embeddable + @Audited + public static class EmbeddableWithCollection { + private List items; + + @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval=true) + @JoinColumn(name = "C_HDR", foreignKey = @ForeignKey(name = "ENVERS_ITEM_FK_ENVERS_HEADER"), nullable = false) + @OrderColumn(name = "C_POSITION", nullable = false) + @AuditMappedBy(mappedBy = "header", positionMappedBy = "position") + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } + + public void addItem(Item item) { + if ( this.items == null ) { + this.items = new ArrayList(); + } + this.items.add( item ); + } + + public void removeItem(Item item) { + if ( this.items != null ) { + this.items.remove( item ); + } + } + } +}