diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/ManyToManyCompositeKey.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/ManyToManyCompositeKey.java new file mode 100644 index 0000000000..937391a65f --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/ManyToManyCompositeKey.java @@ -0,0 +1,141 @@ +/* + * 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.onetomany.idclass; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.ManyToOne; + +import org.hibernate.envers.Audited; +import org.hibernate.envers.RelationTargetAuditMode; + +/** + * @author Chris Cranford + */ +@Audited +@Entity +@IdClass(ManyToManyCompositeKey.ManyToManyId.class) +public class ManyToManyCompositeKey { + @Id + @ManyToOne(fetch = FetchType.EAGER) + private OneToManyOwned oneToMany; + + @Id + @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) + @ManyToOne(fetch = FetchType.EAGER) + private ManyToOneOwned manyToOne; + + public ManyToManyCompositeKey() { + + } + + public ManyToManyCompositeKey(OneToManyOwned oneToMany, ManyToOneOwned manyToOne) { + this.oneToMany = oneToMany; + this.manyToOne = manyToOne; + } + + public OneToManyOwned getOneToMany() { + return this.oneToMany; + } + + public ManyToOneOwned getManyToOne() { + return this.manyToOne; + } + + public ManyToManyId getId() { + return new ManyToManyId( oneToMany, manyToOne ); + } + + @Override + public int hashCode() { + int result = 0; + result = 31 * result + ( oneToMany != null ? oneToMany.hashCode() : 0 ); + result = 31 * result + ( manyToOne != null ? manyToOne.hashCode() : 0 ); + return result; + } + + @Override + public boolean equals(Object obj) { + if( this == obj ) { + return true; + } + if( !( obj instanceof ManyToManyCompositeKey ) ) { + return false; + } + + ManyToManyCompositeKey m = (ManyToManyCompositeKey) obj; + if ( oneToMany != null ? !oneToMany.equals( m.oneToMany ) : m.oneToMany != null ) { + return false; + } + if ( manyToOne != null ? !manyToOne.equals( m.manyToOne ) : m.manyToOne != null ) { + return false; + } + return true; + } + + @Override + public String toString() { + return "ManyToManyCompositeKey(oneToMany = " + + oneToMany.toString() + + ", manyToOne = " + + manyToOne.toString() + + ")"; + } + + public static class ManyToManyId implements Serializable { + private OneToManyOwned oneToMany; + + private ManyToOneOwned manyToOne; + + ManyToManyId() { + } + + ManyToManyId(OneToManyOwned oneToMany, ManyToOneOwned manyToOne) { + this.oneToMany = oneToMany; + this.manyToOne = manyToOne; + } + + public OneToManyOwned getOneToMany() { + return this.oneToMany; + } + + public ManyToOneOwned getManyToOne() { + return this.manyToOne; + } + + @Override + public int hashCode() { + int result = 3; + result = 17 * result + ( oneToMany != null ? oneToMany.hashCode() : 0 ); + result = 17 * result + ( manyToOne != null ? manyToOne.hashCode() : 0 ); + return result; + } + + @Override + public boolean equals(Object obj) { + if( this == obj ) { + return true; + } + if( !( obj instanceof ManyToManyId ) ) { + return false; + } + + ManyToManyId m = (ManyToManyId) obj; + if ( oneToMany != null ? !oneToMany.equals( m.oneToMany ) : m.oneToMany != null ) { + return false; + } + if ( manyToOne != null ? !manyToOne.equals( m.manyToOne ) : m.manyToOne != null ) { + return false; + } + return true; + } + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/ManyToOneOwned.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/ManyToOneOwned.java new file mode 100644 index 0000000000..98913e3f58 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/ManyToOneOwned.java @@ -0,0 +1,75 @@ +/* + * 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.onetomany.idclass; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.hibernate.envers.Audited; + +/** + * @author Chris Cranford + */ +@Entity +@Audited +public class ManyToOneOwned { + @Id + @GeneratedValue + private Long id; + + private String data; + + public ManyToOneOwned() { + + } + + public ManyToOneOwned(String data) { + this.data = data; + } + + public ManyToOneOwned(Long id, String data) { + this.id = id; + this.data = data; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( !( o instanceof ManyToOneOwned ) ) { + return false; + } + + ManyToOneOwned that = (ManyToOneOwned) o; + if ( data != null ? !data.equals( that.data ) : that.data != null ) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int result = 3; + result = 11 * result + ( data != null ? data.hashCode() : 0 ); + return result; + } + + @Override + public String toString() { + return "ManyToOneOwned(id = " + id + ", data = " + data + ")"; + } + + public Long getId() { + return id; + } + + public String getData() { + return data; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/OneToManyCompositeKeyTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/OneToManyCompositeKeyTest.java new file mode 100644 index 0000000000..9b4bdcb1a8 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/OneToManyCompositeKeyTest.java @@ -0,0 +1,152 @@ +/* + * 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.onetomany.idclass; + +import java.util.Arrays; + +import org.hibernate.envers.query.AuditEntity; +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; +import static org.junit.Assert.assertNull; + +/** + * @author Chris Cranford + */ +@TestForIssue(jiraKey = "HHH-7625") +public class OneToManyCompositeKeyTest extends BaseEnversJPAFunctionalTestCase { + private ManyToManyCompositeKey.ManyToManyId owning1Id = null; + private ManyToManyCompositeKey.ManyToManyId owning2Id = null; + private Long oneToManyId; + private Long manyToOne1Id; + private Long manyToOne2Id; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { OneToManyOwned.class, ManyToManyCompositeKey.class, ManyToOneOwned.class }; + } + + @Test + @Priority(10) + public void initData() { + // Revision 1 + TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + OneToManyOwned oneToManyOwned = new OneToManyOwned( "data", null ); + ManyToOneOwned manyToOneOwned1 = new ManyToOneOwned( "data1" ); + ManyToOneOwned manyToOneOwned2 = new ManyToOneOwned( "data2" ); + ManyToManyCompositeKey owning1 = new ManyToManyCompositeKey( oneToManyOwned, manyToOneOwned1 ); + ManyToManyCompositeKey owning2 = new ManyToManyCompositeKey( oneToManyOwned, manyToOneOwned2 ); + + entityManager.persist(oneToManyOwned); + entityManager.persist(manyToOneOwned1); + entityManager.persist(manyToOneOwned2); + entityManager.persist( owning1 ); + entityManager.persist( owning2 ); + + owning1Id = owning1.getId(); + owning2Id = owning2.getId(); + + oneToManyId = oneToManyOwned.getId(); + manyToOne1Id = manyToOneOwned1.getId(); + manyToOne2Id = manyToOneOwned2.getId(); + } ); + + // Revision 2 + TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + ManyToManyCompositeKey owning1 = entityManager.find( ManyToManyCompositeKey.class, owning1Id ); + entityManager.remove( owning1 ); + } ); + + // Revision 3 + TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + ManyToManyCompositeKey owning2 = entityManager.find( ManyToManyCompositeKey.class, owning2Id ); + entityManager.remove( owning2 ); + } ); + } + + @Test + public void testRevisionsCounts() { + assertEquals( Arrays.asList( 1, 2 ), getAuditReader().getRevisions( ManyToManyCompositeKey.class, owning1Id ) ); + assertEquals( Arrays.asList( 1, 3 ), getAuditReader().getRevisions( ManyToManyCompositeKey.class, owning2Id ) ); + assertEquals( Arrays.asList( 1 ), getAuditReader().getRevisions( OneToManyOwned.class, oneToManyId ) ); + assertEquals( Arrays.asList( 1 ), getAuditReader().getRevisions( ManyToOneOwned.class, manyToOne1Id ) ); + assertEquals( Arrays.asList( 1 ), getAuditReader().getRevisions( ManyToOneOwned.class, manyToOne2Id ) ); + } + + @Test + public void testOneToManyHistory() { + final OneToManyOwned rev1 = getAuditReader().find( OneToManyOwned.class, oneToManyId, 1 ); + assertEquals( "data", rev1.getData() ); + assertEquals( 2, rev1.getManyToManyCompositeKeys().size() ); + } + + @Test + public void testManyToOne1History() { + final ManyToOneOwned rev1 = getAuditReader().find( ManyToOneOwned.class, manyToOne1Id, 1 ); + assertEquals( "data1", rev1.getData() ); + } + + @Test + public void testManyToOne2History() { + final ManyToOneOwned rev1 = getAuditReader().find( ManyToOneOwned.class, manyToOne2Id, 1 ); + assertEquals( "data2", rev1.getData() ); + } + + @Test + public void testOwning1History() { + // objects + final OneToManyOwned oneToMany = new OneToManyOwned( 1L, "data", null ); + final ManyToOneOwned manyToOne = new ManyToOneOwned( 2L, "data1" ); + + // insert revision + final ManyToManyCompositeKey rev1 = getAuditReader().find( ManyToManyCompositeKey.class, owning1Id, 1 ); + assertEquals( rev1.getOneToMany(), oneToMany ); + assertEquals( rev1.getManyToOne(), manyToOne ); + + // removal revision - find returns null for deleted + assertNull( getAuditReader().find( ManyToManyCompositeKey.class, owning1Id, 2 ) ); + + // fetch revision 2 using 'select deletions' api and verify. + final ManyToManyCompositeKey rev2 = (ManyToManyCompositeKey) getAuditReader() + .createQuery() + .forRevisionsOfEntity( ManyToManyCompositeKey.class, true, true ) + .add( AuditEntity.id().eq( owning1Id ) ) + .add( AuditEntity.revisionNumber().eq( 2 ) ) + .getSingleResult(); + assertEquals( rev2.getOneToMany(), oneToMany ); + assertEquals( rev2.getManyToOne(), manyToOne ); + } + + @Test + public void testOwning2History() { + // objects + final OneToManyOwned oneToMany = new OneToManyOwned( 1L, "data", null ); + final ManyToOneOwned manyToOne = new ManyToOneOwned( 3L, "data2" ); + + // insert revision + final ManyToManyCompositeKey rev1 = getAuditReader().find( ManyToManyCompositeKey.class, owning2Id, 1 ); + assertEquals( rev1.getOneToMany(), oneToMany ); + assertEquals( rev1.getManyToOne(), manyToOne ); + + // removal revision - find returns null for deleted + assertNull( getAuditReader().find( ManyToManyCompositeKey.class, owning2Id, 3 ) ); + + // fetch revision 3 using 'select deletions' api and verify. + final ManyToManyCompositeKey rev2 = (ManyToManyCompositeKey) getAuditReader() + .createQuery() + .forRevisionsOfEntity( ManyToManyCompositeKey.class, true, true ) + .add( AuditEntity.id().eq( owning2Id ) ) + .add( AuditEntity.revisionNumber().eq( 3 ) ) + .getSingleResult(); + assertEquals( rev2.getOneToMany(), oneToMany ); + assertEquals( rev2.getManyToOne(), manyToOne ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/OneToManyOwned.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/OneToManyOwned.java new file mode 100644 index 0000000000..030ddea0ef --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/idclass/OneToManyOwned.java @@ -0,0 +1,88 @@ +/* + * 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.onetomany.idclass; + +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +import org.hibernate.envers.Audited; + +/** + * @author Chris Cranford + */ +@Entity +@Audited +public class OneToManyOwned { + @Id + @GeneratedValue + private Long id; + + private String data; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "oneToMany") + private List manyToManyCompositeKeys; + + public OneToManyOwned() { + + } + + public OneToManyOwned(String data, List manyToManyCompositeKeys) { + this.data = data; + this.manyToManyCompositeKeys = manyToManyCompositeKeys; + } + + public OneToManyOwned(Long id, String data, List manyToManyCompositeKeys) { + this.id = id; + this.data = data; + this.manyToManyCompositeKeys = manyToManyCompositeKeys; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( !( o instanceof OneToManyOwned ) ) { + return false; + } + + OneToManyOwned that = (OneToManyOwned) o; + if ( data != null ? !data.equals( that.data ) : that.data != null ) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int result = 3; + result = 7 * result + ( data != null ? data.hashCode() : 0 ); + return result; + } + + @Override + public String toString() { + return "OneToManyOwned(id = " + id + ", data = " + data + ")"; + } + + public Long getId() { + return id; + } + + public String getData() { + return data; + } + + public List getManyToManyCompositeKeys() { + return manyToManyCompositeKeys; + } +}