diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/AbstractIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/AbstractIdMapper.java index 17a8b73d4d..07ede371fb 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/AbstractIdMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/AbstractIdMapper.java @@ -67,7 +67,7 @@ public abstract class AbstractIdMapper implements IdMapper { final QueryParameterData paramData1 = paramDataIter1.next(); final QueryParameterData paramData2 = paramDataIter2.next(); - parametersToUse.addWhere( + parametersToUse.addWhereOrNullRestriction( paramData1.getProperty( prefix1 ), false, "=", diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/component/MiddleEmbeddableComponentMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/component/MiddleEmbeddableComponentMapper.java index cd1702b5b7..83ede336c5 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/component/MiddleEmbeddableComponentMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/component/MiddleEmbeddableComponentMapper.java @@ -105,12 +105,7 @@ public class MiddleEmbeddableComponentMapper implements MiddleComponentMapper, C ); } else { - // (p1.prop = p2.prop or (p1.prop is null and p2.prop is null)) - Parameters sub1 = parameters.addSubParameters( "or" ); - sub1.addWhere( prefix1 + '.' + propertyName, false, "=", prefix2 + '.' + propertyName, false ); - Parameters sub2 = sub1.addSubParameters( "and" ); - sub2.addNullRestriction( prefix1 + '.' + propertyName, false ); - sub2.addNullRestriction( prefix2 + '.' + propertyName, false ); + parameters.addWhereOrNullRestriction(prefix1 + '.' + propertyName, false, "=", prefix2 + '.' + propertyName, false); } } } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/query/Parameters.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/query/Parameters.java index 2fc9a03cc5..da444fec80 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/query/Parameters.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/query/Parameters.java @@ -286,6 +286,25 @@ public class Parameters { expressions.add( expression.toString() ); } + /** + * Add where clause with a null restriction: (left = right or (left is null and right is null)) + * @param left Left property name. + * @param addAliasLeft Whether to add the alias to the left property. + * @param op The operator. + * @param right Right property name. + * @param addAliasRight Whether to add the alias to the right property. + */ + public void addWhereOrNullRestriction(String left, boolean addAliasLeft, String op, String right, boolean addAliasRight) { + // apply the normal addWhere predicate + final Parameters sub1 = addSubParameters( "or" ); + sub1.addWhere( left, addAliasLeft, op, right, addAliasRight ); + + // apply the is null predicate for both join properties + final Parameters sub2 = sub1.addSubParameters( "and" ); + sub2.addNullRestriction( left, false ); + sub2.addNullRestriction( right, false ); + } + private void append(StringBuilder sb, String toAppend, MutableBoolean isFirst) { if ( !isFirst.isSet() ) { sb.append( " " ).append( connective ).append( " " ); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/collection/EmbeddableListEntity3.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/collection/EmbeddableListEntity3.java new file mode 100644 index 0000000000..e6f7a6a2f8 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/entities/collection/EmbeddableListEntity3.java @@ -0,0 +1,77 @@ +/* + * 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.entities.collection; + +import org.hibernate.envers.Audited; +import org.hibernate.envers.test.entities.components.relations.ManyToOneEagerComponent; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +/** + * Entity with an List of Embeddable Components that have ManyToOne relationships + * + * @author Cankut Guven + */ +@Entity +@Table(name = "EmbListEnt3") +@Audited +public class EmbeddableListEntity3 { + @Id + @GeneratedValue + private Integer id; + + @ElementCollection + @OrderColumn + @CollectionTable(name = "EmbListEnt3_list") + private List componentList = new ArrayList(); + + public EmbeddableListEntity3() { + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getComponentList() { + return componentList; + } + + public void setComponentList(List componentList) { + this.componentList = componentList; + } + + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( !(o instanceof EmbeddableListEntity3) ) { + return false; + } + + EmbeddableListEntity3 that = (EmbeddableListEntity3) o; + + if ( id != null ? !id.equals( that.id ) : that.id != null ) { + return false; + } + + return true; + } + + public int hashCode() { + return (id != null ? id.hashCode() : 0); + } + + public String toString() { + return "ELE3(id = " + id + ", componentList = " + componentList + ")"; + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/collection/embeddable/EmbeddableList3.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/collection/embeddable/EmbeddableList3.java new file mode 100644 index 0000000000..a0683e506e --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/collection/embeddable/EmbeddableList3.java @@ -0,0 +1,71 @@ +/* + * 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.collection.embeddable; + +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.envers.test.entities.StrTestNoProxyEntity; +import org.hibernate.envers.test.entities.collection.EmbeddableListEntity1; +import org.hibernate.envers.test.entities.collection.EmbeddableListEntity3; +import org.hibernate.envers.test.entities.components.relations.ManyToOneEagerComponent; +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import javax.persistence.EntityManager; +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +/** + * @author Cankut Guven + */ +@TestForIssue(jiraKey = "HHH-11364") +public class EmbeddableList3 extends BaseEnversJPAFunctionalTestCase { + private Integer ele3_id = null; + + private ManyToOneEagerComponent component = new ManyToOneEagerComponent(null, "data"); + + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {EmbeddableListEntity3.class, StrTestNoProxyEntity.class}; + } + + @Test + @Priority(10) + public void initData() { + EntityManager em = getEntityManager(); + + EmbeddableListEntity3 ele3 = new EmbeddableListEntity3(); + + // Revision 1 (persist the entity ) + em.getTransaction().begin(); + ele3.getComponentList().add(component); + em.persist( ele3 ); + em.getTransaction().commit(); + + em.close(); + + ele3_id = ele3.getId(); + + } + + @Test + public void testRevisionsCounts() { + assertEquals( + Arrays.asList(1), getAuditReader().getRevisions( + EmbeddableListEntity3.class, + ele3_id) + ); + } + + @Test + public void testCollectionOfEmbeddableWithNullJoinColumn() { + final EmbeddableListEntity3 ele3 = getAuditReader().find( EmbeddableListEntity3.class, ele3_id, 1 ); + assertEquals("Expected there to be elements in the list", 1, ele3.getComponentList().size()); + } +}