HHH-9432 Fix audit queries when `@Where` applied to discriminator mappings

This commit is contained in:
Chris Cranford 2017-01-10 11:15:22 -05:00 committed by Chris Cranford
parent 9ace8a9dd3
commit 921a958e88
4 changed files with 526 additions and 2 deletions

View File

@ -6,13 +6,13 @@
*/
package org.hibernate.envers.configuration.internal.metadata;
import org.hibernate.envers.configuration.internal.metadata.EntityMappingData;
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.internal.entities.EntityConfiguration;
import org.hibernate.envers.internal.entities.mapper.CompositeMapperBuilder;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.SingleTableSubclass;
import org.hibernate.type.BagType;
import org.hibernate.type.ListType;
import org.hibernate.type.MapType;
@ -74,4 +74,10 @@ public interface CollectionMetadataContext {
|| isOwningManyToOneWithBidrectionalJoinTable() ) );
}
default boolean isOneToManySingleTableSubclass() {
if ( getCollection().getElement() instanceof OneToMany ) {
return ( (OneToMany) getCollection().getElement() ).getAssociatedClass() instanceof SingleTableSubclass;
}
return false;
}
}

View File

@ -208,7 +208,13 @@ public class MiddleTableCollectionMetadataGenerator extends AbstractCollectionMe
);
final RootPersistentEntity entity = new RootPersistentEntity( auditTableData, null );
entity.setWhereClause( context.getCollection().getWhere() );
// When collection element uses a single table discriminator pattern; if any type of WHERE
// conditions are present in the ORM mapping; they should be ignored by Envers; however,
// otherwise all other use cases should be applied.
if ( !context.isOneToManySingleTableSubclass() ) {
entity.setWhereClause( context.getCollection().getWhere() );
}
CompositeIdentifier id = new CompositeIdentifier( getMetadataBuildingContext() );
entity.setIdentifier( id );

View File

@ -0,0 +1,255 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.manytomany;
import java.util.Set;
import jakarta.persistence.DiscriminatorColumn;
import jakarta.persistence.DiscriminatorType;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import org.hibernate.annotations.Where;
import org.hibernate.envers.AuditJoinTable;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
import org.hibernate.orm.test.envers.Priority;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.transaction.TransactionUtil;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Provides test cases for the following {@link ManyToMany} mapping:
*
* <ul>
* <li>An {@link AuditJoinTable} with a {@link Where} clause.</li>
* <li>A non join-table mapping with a {@link Where} clause.</li>
* </ul>
*
* @author Chris Cranford
*/
@TestForIssue(jiraKey = "HHH-9432")
public class BasicWhereTest extends BaseEnversJPAFunctionalTestCase {
private Integer aId;
private Integer xId;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
EntityA.class,
EntityB.class,
EntityC.class,
EntityX.class,
EntityY.class,
EntityZ.class
};
}
@Test
@Priority(10)
public void initData() {
aId = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityA a = new EntityA();
a.setName( "a" );
entityManager.persist( a );
return a.getId();
} );
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityA a = entityManager.find( EntityA.class, aId );
final EntityC c = new EntityC();
c.setName( "c" );
a.getAllMyC().add( c );
entityManager.persist( c );
entityManager.merge( a );
} );
xId = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityX x = new EntityX();
x.setName( "x" );
entityManager.persist( x );
return x.getId();
} );
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityX x = entityManager.find( EntityX.class, xId );
final EntityZ z = new EntityZ();
z.setName( "z" );
x.getAllMyZ().add( z );
entityManager.persist( z );
entityManager.merge( x );
} );
}
@Test
public void testWherePredicateWithAuditJoinTable() {
final EntityA a = getAuditReader().find( EntityA.class, aId, 2 );
assertEquals( 1, a.getAllMyC().size() );
}
@Test
public void testWherePredicateWithoutAuditJoinTable() {
final EntityX x = getAuditReader().find( EntityX.class, xId, 4 );
assertEquals( 1, x.getAllMyZ().size() );
}
@Audited
@Entity(name = "EntityA")
@Table(name = "a_tab")
public static class EntityA {
@Id
@GeneratedValue
private Integer id;
private String name;
@ManyToMany
@JoinColumn(name = "allC")
@Where(clause = "TYPE = 'C'")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@AuditJoinTable(name = "A_C_AUD")
private Set<EntityC> allMyC;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<EntityC> getAllMyC() {
return allMyC;
}
public void setAllMyC(Set<EntityC> allMyC) {
this.allMyC = allMyC;
}
}
@Audited
@Entity(name = "EntityB")
@Table(name = "b_tab")
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue( value = "B")
public static class EntityB {
@Id
@GeneratedValue
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity(name = "EntityC")
@DiscriminatorValue(value = "C")
public static class EntityC extends EntityB {
}
@Audited
@Entity(name = "EntityX")
@Table(name = "x_tab")
public static class EntityX {
@Id
@GeneratedValue
private Integer id;
private String name;
@ManyToMany
@Where(clause = "TYPE = 'Z'")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
private Set<EntityZ> allMyZ;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<EntityZ> getAllMyZ() {
return allMyZ;
}
public void setAllMyZ(Set<EntityZ> allMyZ) {
this.allMyZ = allMyZ;
}
}
@Entity(name = "EntityY")
@Table(name = "y_tab")
@Audited
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue(value = "Y")
public static class EntityY {
@Id
@GeneratedValue
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity(name = "EntityZ")
@DiscriminatorValue(value = "Z")
public static class EntityZ extends EntityY {
}
}

View File

@ -0,0 +1,257 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.envers.integration.onetomany;
import java.util.Set;
import jakarta.persistence.DiscriminatorColumn;
import jakarta.persistence.DiscriminatorType;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.hibernate.annotations.Where;
import org.hibernate.envers.AuditJoinTable;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
import org.hibernate.orm.test.envers.Priority;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.transaction.TransactionUtil;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Provides test cases for the following {@link OneToMany} mapping:
*
* <ul>
* <li>An {@link AuditJoinTable} with a {@link Where} clause.</li>
* <li>A non join-table mapping with a {@link Where} clause.</li>
* </ul>
*
* @author Chris Cranford
*/
@TestForIssue(jiraKey = "HHH-9432")
public class BasicWhereTest extends BaseEnversJPAFunctionalTestCase {
private Integer aId;
private Integer xId;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
EntityA.class,
EntityB.class,
EntityC.class,
EntityX.class,
EntityY.class,
EntityZ.class
};
}
@Test
@Priority(10)
public void initData() {
aId = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityA a = new EntityA();
a.setName( "a" );
entityManager.persist( a );
return a.getId();
} );
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityA a = entityManager.find( EntityA.class, aId );
final EntityC c = new EntityC();
c.setName( "c" );
a.getAllMyC().add( c );
entityManager.persist( c );
entityManager.merge( a );
} );
xId = TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityX x = new EntityX();
x.setName( "x" );
entityManager.persist( x );
return x.getId();
} );
TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> {
final EntityX x = entityManager.find( EntityX.class, xId );
final EntityZ z = new EntityZ();
z.setName( "z" );
x.getAllMyZ().add( z );
entityManager.persist( z );
entityManager.merge( x );
} );
}
@Test
public void testWherePredicateWithAuditJoinTable() {
final EntityA a = getAuditReader().find( EntityA.class, aId, 2 );
assertEquals( 1, a.getAllMyC().size() );
}
@Test
public void testWherePredicateWithoutAuditJoinTable() {
final EntityX x = getAuditReader().find( EntityX.class, xId, 4 );
assertEquals( 1, x.getAllMyZ().size() );
}
@Audited
@Entity(name = "EntityA")
@Table(name = "a_tab")
public static class EntityA {
@Id
@GeneratedValue
private Integer id;
private String name;
@OneToMany
@JoinColumn(name = "allC")
@Where(clause = "TYPE = 'C'")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@AuditJoinTable(name = "A_C_AUD")
private Set<EntityC> allMyC;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<EntityC> getAllMyC() {
return allMyC;
}
public void setAllMyC(Set<EntityC> allMyC) {
this.allMyC = allMyC;
}
}
@Audited
@Entity(name = "EntityB")
@Table(name = "b_tab")
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue( value = "B")
public static class EntityB {
@Id
@GeneratedValue
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity(name = "EntityC")
@DiscriminatorValue(value = "C")
public static class EntityC extends EntityB {
}
@Audited
@Entity(name = "EntityX")
@Table(name = "x_tab")
public static class EntityX {
@Id
@GeneratedValue
private Integer id;
private String name;
@OneToMany
@Where(clause = "TYPE = 'Z'")
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
private Set<EntityZ> allMyZ;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<EntityZ> getAllMyZ() {
return allMyZ;
}
public void setAllMyZ(Set<EntityZ> allMyZ) {
this.allMyZ = allMyZ;
}
}
@Audited
@Entity(name = "EntityY")
@Table(name = "y_tab")
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue( value = "Y")
public static class EntityY {
@Id
@GeneratedValue
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity(name = "EntityZ")
@DiscriminatorValue(value = "Z")
public static class EntityZ extends EntityY {
}
}