From 1e860c419542d860d00c63d183ee0a3a3cf79feb Mon Sep 17 00:00:00 2001 From: Chris Cranford Date: Wed, 15 Jun 2016 11:12:55 -0500 Subject: [PATCH] HHH-8305 - Fix ToOne join tables with optional=true and OneToOne inverse mappings. (cherry picked from commit 86fad51) --- .../metadata/AuditMetadataGenerator.java | 10 +++ .../bidirectional/BiRefedOptionalEntity.java | 64 ++++++++++++++ .../bidirectional/BiRefingOptionalEntity.java | 64 ++++++++++++++ .../BidirectionalManyToOneOptionalTest.java | 87 +++++++++++++++++++ .../bidirectional/BiRefedOptionalEntity.java | 61 +++++++++++++ .../bidirectional/BiRefingOptionalEntity.java | 64 ++++++++++++++ .../BidirectionalOneToOneOptionalTest.java | 87 +++++++++++++++++++ 7 files changed, 437 insertions(+) create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefedOptionalEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefingOptionalEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BidirectionalManyToOneOptionalTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefedOptionalEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefingOptionalEntity.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BidirectionalOneToOneOptionalTest.java diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AuditMetadataGenerator.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AuditMetadataGenerator.java index a6955d5ea9..4c2a14b934 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AuditMetadataGenerator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/metadata/AuditMetadataGenerator.java @@ -456,6 +456,16 @@ public final class AuditMetadataGenerator { final Element joinElement = MetadataTools.createJoin( parent, auditTableName, schema, catalog ); joinElements.put( join, joinElement ); + // HHH-8305 - Fix case when join is considered optional. + if ( join.isOptional() ) { + joinElement.addAttribute( "optional", "true" ); + } + + // HHH-8305 - Fix case when join is the inverse side of a mapping. + if ( join.isInverse() ) { + joinElement.addAttribute( "inverse", "true" ); + } + final Element joinKey = joinElement.addElement( "key" ); MetadataTools.addColumns( joinKey, join.getKey().getColumnIterator() ); MetadataTools.addColumn( joinKey, verEntCfg.getRevisionFieldName(), null, null, null, null, null, null ); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefedOptionalEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefedOptionalEntity.java new file mode 100644 index 0000000000..50bf2b2def --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefedOptionalEntity.java @@ -0,0 +1,64 @@ +/* + * 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.manytoone.bidirectional; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +import org.hibernate.envers.Audited; + +/** + * @author Chris Cranford + */ +@Entity +@Audited +public class BiRefedOptionalEntity { + @Id + @GeneratedValue + private Integer id; + + @OneToMany(mappedBy = "reference") + private List references = new ArrayList<>(); + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getReferences() { + return references; + } + + public void setReferences(List references) { + this.references = references; + } + + @Override + public int hashCode() { + return ( id != null ? id.hashCode() : 0 ); + } + + @Override + public boolean equals(Object object) { + if ( object == this ) { + return true; + } + if ( !( object instanceof BiRefedOptionalEntity ) ) { + return false; + } + BiRefedOptionalEntity that = (BiRefedOptionalEntity) object; + return !( id != null ? !id.equals( that.id ) : that.id != null ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefingOptionalEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefingOptionalEntity.java new file mode 100644 index 0000000000..d45c64f256 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BiRefingOptionalEntity.java @@ -0,0 +1,64 @@ +/* + * 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.manytoone.bidirectional; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; + +import org.hibernate.envers.Audited; + +/** + * @author Chris Cranford + */ +@Entity +@Audited +public class BiRefingOptionalEntity { + @Id + @GeneratedValue + private Integer id; + + @ManyToOne(optional = true) + @JoinTable(name = "A_B", joinColumns = @JoinColumn(name = "a_id", unique = true), inverseJoinColumns = @JoinColumn(name = "b_id") ) + private BiRefedOptionalEntity reference; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public BiRefedOptionalEntity getReference() { + return reference; + } + + public void setReference(BiRefedOptionalEntity reference) { + this.reference = reference; + } + + @Override + public int hashCode() { + return ( id != null ? id.hashCode() : 0 ); + } + + @Override + public boolean equals(Object object) { + if ( object == this ) { + return true; + } + if ( !( object instanceof BiRefingOptionalEntity ) ) { + return false; + } + BiRefingOptionalEntity that = (BiRefingOptionalEntity) object; + return !( id != null ? !id.equals( that.id ) : that.id != null ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BidirectionalManyToOneOptionalTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BidirectionalManyToOneOptionalTest.java new file mode 100644 index 0000000000..17e6586ec4 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytoone/bidirectional/BidirectionalManyToOneOptionalTest.java @@ -0,0 +1,87 @@ +/* + * 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.manytoone.bidirectional; + +import javax.persistence.EntityManager; + +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +/** + * @author Chris Cranford + */ +@TestForIssue(jiraKey = "HHH-8305") +public class BidirectionalManyToOneOptionalTest extends BaseEnversJPAFunctionalTestCase { + private Integer refingWithNoRefedId; + private Integer refingId; + private Integer refedId; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + BiRefingOptionalEntity.class, + BiRefedOptionalEntity.class + }; + } + + @Test + @Priority(10) + public void initData() { + EntityManager entityManager = getEntityManager(); + try { + // Revision 1 + entityManager.getTransaction().begin(); + + // store refing with null refed entity + BiRefingOptionalEntity refingWithNoRefed = new BiRefingOptionalEntity(); + refingWithNoRefed.setReference( null ); + entityManager.persist( refingWithNoRefed ); + + // store refing with non-null refed entity + BiRefingOptionalEntity refing = new BiRefingOptionalEntity(); + BiRefedOptionalEntity refed = new BiRefedOptionalEntity(); + refed.getReferences().add( refing ); + refing.setReference( refed ); + entityManager.persist( refing ); + entityManager.persist( refed ); + + entityManager.getTransaction().commit(); + + this.refingId = refing.getId(); + this.refedId = refed.getId(); + this.refingWithNoRefedId = refingWithNoRefed.getId(); + } + finally { + entityManager.close(); + } + } + + @Test + public void testRevisionCounts() { + assertEquals( 1, getAuditReader().getRevisions( BiRefingOptionalEntity.class, refingId ).size() ); + assertEquals( 1, getAuditReader().getRevisions( BiRefingOptionalEntity.class, refingWithNoRefedId ).size() ); + assertEquals( 1, getAuditReader().getRevisions( BiRefedOptionalEntity.class, refedId ).size() ); + } + + @Test + public void testRevisionHistoryNullReference() { + BiRefingOptionalEntity rev1 = getAuditReader().find( BiRefingOptionalEntity.class, refingWithNoRefedId, 1 ); + assertNull( rev1.getReference() ); + } + + @Test + public void testRevisionHistoryWithNonNullReference() { + assertNotNull( getAuditReader().find( BiRefingOptionalEntity.class, refingId, 1).getReference() ); + assertEquals( 1, getAuditReader().find( BiRefedOptionalEntity.class, refedId, 1 ).getReferences().size() ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefedOptionalEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefedOptionalEntity.java new file mode 100644 index 0000000000..138aa5b663 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefedOptionalEntity.java @@ -0,0 +1,61 @@ +/* + * 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.onetoone.bidirectional; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToOne; + +import org.hibernate.envers.Audited; + +/** + * @author Chris Cranford + */ +@Entity +@Audited +public class BiRefedOptionalEntity { + @Id + @GeneratedValue + private Integer id; + + @OneToOne(mappedBy = "reference", optional = true) + private BiRefingOptionalEntity referencing; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public BiRefingOptionalEntity getReferencing() { + return referencing; + } + + public void setReferencing(BiRefingOptionalEntity referencing) { + this.referencing = referencing; + } + + @Override + public int hashCode() { + return ( id != null ? id.hashCode() : 0 ); + } + + @Override + public boolean equals(Object object) { + if ( object == this ) { + return true; + } + if ( !( object instanceof BiRefedOptionalEntity ) ) { + return false; + } + BiRefedOptionalEntity that = (BiRefedOptionalEntity) object; + return !( id != null ? !id.equals( that.id ) : that.id != null ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefingOptionalEntity.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefingOptionalEntity.java new file mode 100644 index 0000000000..268e3b7aa6 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BiRefingOptionalEntity.java @@ -0,0 +1,64 @@ +/* + * 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.onetoone.bidirectional; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.OneToOne; + +import org.hibernate.envers.Audited; + +/** + * @author Chris Cranford + */ +@Entity +@Audited +public class BiRefingOptionalEntity { + @Id + @GeneratedValue + private Integer id; + + @OneToOne(optional = true) + @JoinTable(name = "A_B", joinColumns = @JoinColumn(name = "a_id", unique = true), inverseJoinColumns = @JoinColumn(name = "b_id") ) + private BiRefedOptionalEntity reference; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public BiRefedOptionalEntity getReference() { + return reference; + } + + public void setReference(BiRefedOptionalEntity reference) { + this.reference = reference; + } + + @Override + public int hashCode() { + return ( id != null ? id.hashCode() : 0 ); + } + + @Override + public boolean equals(Object object) { + if ( object == this ) { + return true; + } + if ( !( object instanceof BiRefingOptionalEntity ) ) { + return false; + } + BiRefingOptionalEntity that = (BiRefingOptionalEntity) object; + return !( id != null ? !id.equals( that.id ) : that.id != null ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BidirectionalOneToOneOptionalTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BidirectionalOneToOneOptionalTest.java new file mode 100644 index 0000000000..906dbba0df --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetoone/bidirectional/BidirectionalOneToOneOptionalTest.java @@ -0,0 +1,87 @@ +/* + * 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.onetoone.bidirectional; + +import javax.persistence.EntityManager; + +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +/** + * @author Chris Cranford + */ +@TestForIssue(jiraKey = "HHH-8305") +public class BidirectionalOneToOneOptionalTest extends BaseEnversJPAFunctionalTestCase { + private Integer refingWithNoRefedId; + private Integer refingId; + private Integer refedId; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + BiRefingOptionalEntity.class, + BiRefedOptionalEntity.class + }; + } + + @Test + @Priority(10) + public void initData() { + EntityManager entityManager = getEntityManager(); + try { + // Revision 1 + entityManager.getTransaction().begin(); + + // store refing with null refed entity + BiRefingOptionalEntity refingWithNoRefed = new BiRefingOptionalEntity(); + refingWithNoRefed.setReference( null ); + entityManager.persist( refingWithNoRefed ); + + // store refing with non-null refed entity + BiRefingOptionalEntity refing = new BiRefingOptionalEntity(); + BiRefedOptionalEntity refed = new BiRefedOptionalEntity(); + refed.setReferencing( refing ); + refing.setReference( refed ); + entityManager.persist( refing ); + entityManager.persist( refed ); + + entityManager.getTransaction().commit(); + + this.refingId = refing.getId(); + this.refedId = refed.getId(); + this.refingWithNoRefedId = refingWithNoRefed.getId(); + } + finally { + entityManager.close(); + } + } + + @Test + public void testRevisionCounts() { + assertEquals( 1, getAuditReader().getRevisions( BiRefingOptionalEntity.class, refingId ).size() ); + assertEquals( 1, getAuditReader().getRevisions( BiRefingOptionalEntity.class, refingWithNoRefedId ).size() ); + assertEquals( 1, getAuditReader().getRevisions( BiRefedOptionalEntity.class, refedId ).size() ); + } + + @Test + public void testRevisionHistoryNullReference() { + BiRefingOptionalEntity rev1 = getAuditReader().find( BiRefingOptionalEntity.class, refingWithNoRefedId, 1 ); + assertNull( rev1.getReference() ); + } + + @Test + public void testRevisionHistoryWithNonNullReference() { + assertNotNull( getAuditReader().find( BiRefingOptionalEntity.class, refingId, 1).getReference() ); + assertNotNull( getAuditReader().find( BiRefedOptionalEntity.class, refedId, 1 ).getReferencing() ); + } +}