HHH-13361 Allow auditing entities with nested identifiers
This commit is contained in:
parent
c5f719ef39
commit
b5755b6945
|
@ -24,6 +24,7 @@ import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
|
|||
import org.hibernate.envers.internal.entities.mapper.id.EmbeddedIdMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.MultipleIdMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.NestedEmbeddedIdMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.SimpleIdMapperBuilder;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.SingleIdMapper;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
|
@ -32,6 +33,7 @@ import org.hibernate.mapping.PersistentClass;
|
|||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.ManyToOneType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -63,7 +65,8 @@ public final class IdMetadataGenerator extends AbstractMetadataGenerator {
|
|||
boolean key,
|
||||
SimpleIdMapperBuilder mapper,
|
||||
Property mappedProperty,
|
||||
Property virtualProperty) {
|
||||
Property virtualProperty,
|
||||
boolean audited) {
|
||||
|
||||
if ( PropertyPath.IDENTIFIER_MAPPER_PROPERTY.equals( mappedProperty.getName() ) ) {
|
||||
return false;
|
||||
|
@ -93,6 +96,19 @@ public final class IdMetadataGenerator extends AbstractMetadataGenerator {
|
|||
|
||||
return added;
|
||||
}
|
||||
else if ( ComponentType.class.isInstance( mappedProperty.getType() ) ) {
|
||||
final Component component = (Component) mappedProperty.getValue();
|
||||
final NestedEmbeddedIdMapper nestedMapper;
|
||||
if ( mapper != null ) {
|
||||
final PropertyData propertyData = propertyAuditingData.resolvePropertyData();
|
||||
nestedMapper = new NestedEmbeddedIdMapper( propertyData, component );
|
||||
mapper.add( propertyData, nestedMapper );
|
||||
}
|
||||
else {
|
||||
nestedMapper = null;
|
||||
}
|
||||
return addIdProperties( attributeContainer, component, null, nestedMapper, key, audited );
|
||||
}
|
||||
|
||||
return addBasic( attributeContainer, propertyAuditingData, mappedProperty.getValue(), mapper, key );
|
||||
}
|
||||
|
@ -116,7 +132,7 @@ public final class IdMetadataGenerator extends AbstractMetadataGenerator {
|
|||
virtualProperty = null;
|
||||
}
|
||||
|
||||
if ( !addIdProperty( attributeContainer, key, mapper, property, virtualProperty ) ) {
|
||||
if ( !addIdProperty( attributeContainer, key, mapper, property, virtualProperty, audited ) ) {
|
||||
// If the entity is audited, and a non-supported id component is used, throw exception.
|
||||
if ( audited ) {
|
||||
throw new EnversMappingException(
|
||||
|
@ -196,7 +212,7 @@ public final class IdMetadataGenerator extends AbstractMetadataGenerator {
|
|||
if ( idMapper != null ) {
|
||||
// Multiple id
|
||||
final Component virtualComponent = (Component) persistentClass.getIdentifier();
|
||||
mapper = new MultipleIdMapper( loadClass( virtualComponent ), persistentClass.getServiceRegistry() );
|
||||
mapper = new MultipleIdMapper( virtualComponent );
|
||||
|
||||
if ( !addIdProperties( relation, idMapper, virtualComponent, mapper, false, audited ) ) {
|
||||
return null;
|
||||
|
@ -210,8 +226,7 @@ public final class IdMetadataGenerator extends AbstractMetadataGenerator {
|
|||
else if ( idProp.isComposite() ) {
|
||||
// Embedded id
|
||||
final Component idComponent = (Component) idProp.getValue();
|
||||
final Class<?> embeddableClass = loadClass( idComponent );
|
||||
mapper = new EmbeddedIdMapper( getIdPropertyData( idProp ), embeddableClass, persistentClass.getServiceRegistry() );
|
||||
mapper = new EmbeddedIdMapper( getIdPropertyData( idProp ), idComponent );
|
||||
|
||||
if ( !addIdProperties( relation, idComponent, null, mapper, false, audited ) ) {
|
||||
return null;
|
||||
|
|
|
@ -17,15 +17,18 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* An abstract identifier mapper implementation specific for composite identifiers.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
||||
protected final Class compositeIdClass;
|
||||
protected final Class<?> compositeIdClass;
|
||||
|
||||
protected Map<PropertyData, SingleIdMapper> ids;
|
||||
protected Map<PropertyData, AbstractIdMapper> ids;
|
||||
|
||||
protected AbstractCompositeIdMapper(Class compositeIdClass, ServiceRegistry serviceRegistry) {
|
||||
protected AbstractCompositeIdMapper(Class<?> compositeIdClass, ServiceRegistry serviceRegistry) {
|
||||
super( serviceRegistry );
|
||||
this.compositeIdClass = compositeIdClass;
|
||||
ids = Tools.newLinkedHashMap();
|
||||
|
@ -33,7 +36,12 @@ public abstract class AbstractCompositeIdMapper extends AbstractIdMapper impleme
|
|||
|
||||
@Override
|
||||
public void add(PropertyData propertyData) {
|
||||
ids.put( propertyData, new SingleIdMapper( getServiceRegistry(), propertyData ) );
|
||||
add( propertyData, new SingleIdMapper( getServiceRegistry(), propertyData ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(PropertyData propertyData, AbstractIdMapper idMapper) {
|
||||
ids.put( propertyData, idMapper );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,7 +51,7 @@ public abstract class AbstractCompositeIdMapper extends AbstractIdMapper impleme
|
|||
}
|
||||
|
||||
final Object compositeId = instantiateCompositeId();
|
||||
for ( SingleIdMapper mapper : ids.values() ) {
|
||||
for ( AbstractIdMapper mapper : ids.values() ) {
|
||||
if ( !mapper.mapToEntityFromMap( compositeId, data ) ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -52,6 +60,11 @@ public abstract class AbstractCompositeIdMapper extends AbstractIdMapper impleme
|
|||
return compositeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapToEntityFromEntity(Object objectTo, Object objectFrom) {
|
||||
// no-op; does nothing
|
||||
}
|
||||
|
||||
protected Object instantiateCompositeId() {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<Object>() {
|
||||
|
|
|
@ -13,6 +13,8 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* The base abstract class implementation for identifier mappers.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
|
@ -139,6 +141,8 @@ public abstract class AbstractIdMapper implements IdMapper {
|
|||
}
|
||||
}
|
||||
|
||||
public abstract void mapToEntityFromEntity(Object objectTo, Object objectFrom);
|
||||
|
||||
private void handleNullValue(Parameters parameters, String alias, String propertyName, boolean equals) {
|
||||
if ( equals ) {
|
||||
parameters.addNullRestriction( alias, propertyName );
|
||||
|
|
|
@ -16,19 +16,27 @@ import java.util.Map;
|
|||
import org.hibernate.envers.exception.AuditException;
|
||||
import org.hibernate.envers.internal.entities.PropertyData;
|
||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
import org.hibernate.property.access.spi.Setter;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* An identifier mapper implementation for {@link jakarta.persistence.EmbeddedId} mappings.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
||||
private PropertyData idPropertyData;
|
||||
|
||||
public EmbeddedIdMapper(PropertyData idPropertyData, Class compositeIdClass, ServiceRegistry serviceRegistry) {
|
||||
super( compositeIdClass, serviceRegistry );
|
||||
public EmbeddedIdMapper(PropertyData propertyData, Component component) {
|
||||
super( component.getComponentClass(), component.getServiceRegistry() );
|
||||
this.idPropertyData = propertyData;
|
||||
}
|
||||
|
||||
private EmbeddedIdMapper(PropertyData idPropertyData, Class<?> compositeIdClass, ServiceRegistry serviceRegistry) {
|
||||
super( compositeIdClass, serviceRegistry );
|
||||
this.idPropertyData = idPropertyData;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* Base contract for all identifier mappers.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
|
|
|
@ -13,14 +13,23 @@ import java.util.Map;
|
|||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.internal.entities.PropertyData;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* An implementation of an identifier mapper for {@link jakarta.persistence.IdClass} or multiple
|
||||
* {@link jakarta.persistence.Id} identifier mappings.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
|
||||
public MultipleIdMapper(Class compositeIdClass, ServiceRegistry serviceRegistry) {
|
||||
|
||||
public MultipleIdMapper(Component component) {
|
||||
super( component.getComponentClass(), component.getServiceRegistry() );
|
||||
}
|
||||
|
||||
private MultipleIdMapper(Class<?> compositeIdClass, ServiceRegistry serviceRegistry) {
|
||||
super( compositeIdClass, serviceRegistry );
|
||||
}
|
||||
|
||||
|
@ -32,9 +41,9 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
|
|||
@Override
|
||||
public void mapToMapFromId(Session session, Map<String, Object> data, Object obj) {
|
||||
if ( compositeIdClass.isInstance( obj ) ) {
|
||||
for ( Map.Entry<PropertyData, SingleIdMapper> entry : ids.entrySet() ) {
|
||||
for ( Map.Entry<PropertyData, AbstractIdMapper> entry : ids.entrySet() ) {
|
||||
final PropertyData propertyData = entry.getKey();
|
||||
final SingleIdMapper idMapper = entry.getValue();
|
||||
final AbstractIdMapper idMapper = entry.getValue();
|
||||
|
||||
if ( propertyData.getVirtualReturnClass() == null ) {
|
||||
idMapper.mapToMapFromEntity( data, obj );
|
||||
|
@ -92,7 +101,7 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
|
|||
}
|
||||
|
||||
final Object compositeId = instantiateCompositeId();
|
||||
for ( SingleIdMapper mapper : ids.values() ) {
|
||||
for ( AbstractIdMapper mapper : ids.values() ) {
|
||||
mapper.mapToEntityFromEntity( compositeId, data );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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.envers.internal.entities.mapper.id;
|
||||
|
||||
import org.hibernate.envers.internal.entities.PropertyData;
|
||||
import org.hibernate.mapping.Component;
|
||||
|
||||
/**
|
||||
* An identifier mapper that is meant to support nested {@link jakarta.persistence.Embeddable} instances
|
||||
* inside an existing {@link jakarta.persistence.EmbeddedId} identifier hierarchy.
|
||||
*
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class NestedEmbeddedIdMapper extends EmbeddedIdMapper {
|
||||
public NestedEmbeddedIdMapper(PropertyData propertyData, Component component) {
|
||||
super( propertyData, component );
|
||||
}
|
||||
}
|
|
@ -6,10 +6,21 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.id;
|
||||
|
||||
import org.hibernate.envers.internal.entities.PropertyData;
|
||||
import org.hibernate.envers.internal.entities.mapper.SimpleMapperBuilder;
|
||||
|
||||
/**
|
||||
* A simple identifier builder contract.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public interface SimpleIdMapperBuilder extends IdMapper, SimpleMapperBuilder {
|
||||
/**
|
||||
* Add a custom identifier mapper to the builder.
|
||||
*
|
||||
* @param propertyData the property data
|
||||
* @param idMapper the mapper
|
||||
*/
|
||||
void add(PropertyData propertyData, AbstractIdMapper idMapper);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,10 @@ import org.hibernate.proxy.HibernateProxy;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* An implementation of an identifier mapper for a single basic attribute property.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
|
||||
private PropertyData propertyData;
|
||||
|
@ -44,6 +47,11 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
|
|||
this.propertyData = propertyData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(PropertyData propertyData, AbstractIdMapper idMapper) {
|
||||
throw new AuditException( "This method is not allowed for a single identifier mapper" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mapToEntityFromMap(final Object obj, Map data) {
|
||||
if ( data == null || obj == null ) {
|
||||
|
@ -143,6 +151,7 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapToEntityFromEntity(final Object objTo, final Object objFrom) {
|
||||
if ( objTo == null || objFrom == null ) {
|
||||
return;
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.envers.integration.ids.embeddedid;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.AccessType;
|
||||
import jakarta.persistence.EmbeddedId;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
@Entity
|
||||
@Audited
|
||||
@Table(name = "compositeentity")
|
||||
@Access(value = AccessType.FIELD)
|
||||
public class CompositeEntity {
|
||||
|
||||
@EmbeddedId
|
||||
private CompositeEntityId codeObject = new CompositeEntityId();
|
||||
|
||||
@OneToMany(targetEntity = OwnerOfRelationCode.class, fetch = FetchType.LAZY, mappedBy = "compositeEntity")
|
||||
private Set<OwnerOfRelationCode> ownerOfRelationCodes = new java.util.HashSet<>();
|
||||
|
||||
public CompositeEntityId getCodeObject() {
|
||||
return codeObject;
|
||||
}
|
||||
|
||||
public void setCodeObject(CompositeEntityId codeObject) {
|
||||
this.codeObject = codeObject;
|
||||
}
|
||||
|
||||
public Set<OwnerOfRelationCode> getOwnerOfRelationCodes() {
|
||||
return ownerOfRelationCodes;
|
||||
}
|
||||
|
||||
public void setOwnerOfRelationCodes(Set<OwnerOfRelationCode> ownerOfRelationCodes) {
|
||||
this.ownerOfRelationCodes = ownerOfRelationCodes;
|
||||
}
|
||||
|
||||
public String getFirstCode() {
|
||||
return codeObject == null ? null : codeObject.getFirstCode();
|
||||
}
|
||||
|
||||
public void setFirstCode(String firstCode) {
|
||||
if ( codeObject == null ) {
|
||||
codeObject = new CompositeEntityId();
|
||||
}
|
||||
codeObject.setFirstCode( firstCode );
|
||||
}
|
||||
|
||||
public String getSecondCode() {
|
||||
return codeObject == null ? null : codeObject.getSecondCode();
|
||||
}
|
||||
|
||||
public void setSecondCode(String secondCode) {
|
||||
if ( codeObject == null ) {
|
||||
codeObject = new CompositeEntityId();
|
||||
}
|
||||
codeObject.setSecondCode( secondCode );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.ids.embeddedid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
@Embeddable
|
||||
public class CompositeEntityId implements Serializable{
|
||||
|
||||
private String firstCode;
|
||||
private String secondCode;
|
||||
|
||||
public String getFirstCode() {
|
||||
return firstCode;
|
||||
}
|
||||
|
||||
public void setFirstCode(String firstCode) {
|
||||
this.firstCode = firstCode;
|
||||
}
|
||||
|
||||
public String getSecondCode() {
|
||||
return secondCode;
|
||||
}
|
||||
|
||||
public void setSecondCode(String secondCode) {
|
||||
this.secondCode = secondCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CompositeEntityId{" +
|
||||
"firstCode='" + firstCode + '\'' +
|
||||
", secondCode='" + secondCode + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.ids.embeddedid;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.orm.test.envers.BaseEnversFunctionalTestCase;
|
||||
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.orm.test.envers.Priority;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-13361")
|
||||
public class NestedEmbeddedIdentifiersTest extends BaseEnversJPAFunctionalTestCase {
|
||||
|
||||
private OwnerOfRelationCodeId id;
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { OwnerOfRelationCode.class, CompositeEntity.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@Priority(10)
|
||||
public void initData() {
|
||||
// Revision 1, test insert
|
||||
final OwnerOfRelationCode owner = doInJPA( this::entityManagerFactory, session -> {
|
||||
CompositeEntity compositeEntity = new CompositeEntity();
|
||||
compositeEntity.setFirstCode( "firstCode" );
|
||||
compositeEntity.setSecondCode( "secondCode" );
|
||||
session.persist( compositeEntity );
|
||||
|
||||
OwnerOfRelationCode ownerEntity = new OwnerOfRelationCode();
|
||||
ownerEntity.setCompositeEntity( compositeEntity );
|
||||
ownerEntity.setSecondIdentifier( "secondIdentifier" );
|
||||
|
||||
session.persist( ownerEntity );
|
||||
return ownerEntity;
|
||||
} );
|
||||
|
||||
this.id = owner.getCodeObject();
|
||||
|
||||
// Revision 2, test update
|
||||
doInJPA( this::entityManagerFactory, session -> {
|
||||
OwnerOfRelationCode ownerEntity = session.find( OwnerOfRelationCode.class, id );
|
||||
ownerEntity.setDescription( "first description" );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevisionCounts() {
|
||||
assertEquals( Arrays.asList( 1, 2 ), getAuditReader().getRevisions( OwnerOfRelationCode.class, id ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdentifierAtRevision1() {
|
||||
// select e__
|
||||
// from org.hibernate.orm.test.envers.integration.ids.embeddedid.OwnerOfRelationCode_AUD e__
|
||||
// where e__.originalId.REV.id = (select max(e2__.originalId.REV.id)
|
||||
// from org.hibernate.orm.test.envers.integration.ids.embeddedid.OwnerOfRelationCode_AUD e2__
|
||||
// where e2__.originalId.REV.id <= :revision
|
||||
// and e__.originalId.compositeEntity = e2__.originalId.compositeEntity
|
||||
// and e__.originalId.secondIdentifier = e2__.originalId.secondIdentifier)
|
||||
// and e__.REVTYPE <> :_p0
|
||||
// and e__.originalId.compositeEntity_firstCode = :_p1
|
||||
// and e__.originalId.compositeEntity_secondCode = :_p2
|
||||
// and e__.originalId.secondIdentifier = :_p3
|
||||
//
|
||||
// select e__
|
||||
// from org.hibernate.orm.test.envers.integration.ids.embeddedid.OwnerOfRelationCode_AUD e__
|
||||
// where e__.originalId.REV.id = (select max(e2__.originalId.REV.id)
|
||||
// from org.hibernate.orm.test.envers.integration.ids.embeddedid.OwnerOfRelationCode_AUD e2__
|
||||
// where e2__.originalId.REV.id <= :revision
|
||||
// and e__.originalId.compositeEntity_firstCode = e2__.originalId.compositeEntity_firstCode
|
||||
// and e__.originalId.compositeEntity_secondCode = e2__.originalId.compositeEntity_secondCode
|
||||
// and e__.originalId.secondIdentifier = e2__.originalId.secondIdentifier)
|
||||
// and e__.REVTYPE <> :_p0
|
||||
// and e__.originalId.compositeEntity_firstCode = :_p1
|
||||
// and e__.originalId.compositeEntity_secondCode = :_p2
|
||||
// and e__.originalId.secondIdentifier = :_p3
|
||||
final OwnerOfRelationCode rev1 = getAuditReader().find( OwnerOfRelationCode.class, id, 1 );
|
||||
System.out.println( rev1 );
|
||||
assertEquals( rev1.getCodeObject().getSecondIdentifier(), "secondIdentifier" );
|
||||
assertEquals( rev1.getCodeObject().getCompositeEntity().getFirstCode(), "firstCode" );
|
||||
assertEquals( rev1.getCodeObject().getCompositeEntity().getSecondCode(), "secondCode" );
|
||||
assertNull( rev1.getDescription() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdentifierAtRevision2() {
|
||||
final OwnerOfRelationCode rev2 = getAuditReader().find( OwnerOfRelationCode.class, id, 2 );
|
||||
System.out.println( rev2 );
|
||||
assertEquals( rev2.getCodeObject().getSecondIdentifier(), "secondIdentifier" );
|
||||
assertEquals( rev2.getCodeObject().getCompositeEntity().getFirstCode(), "firstCode" );
|
||||
assertEquals( rev2.getCodeObject().getCompositeEntity().getSecondCode(), "secondCode" );
|
||||
assertEquals( rev2.getDescription(), "first description" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.ids.embeddedid;
|
||||
|
||||
import jakarta.persistence.Access;
|
||||
import jakarta.persistence.AccessType;
|
||||
import jakarta.persistence.EmbeddedId;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinColumns;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.MapsId;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
@Entity
|
||||
@Audited
|
||||
@Table(name = "ownerOfRelationcode")
|
||||
@Access(value = AccessType.FIELD)
|
||||
public class OwnerOfRelationCode {
|
||||
|
||||
@EmbeddedId
|
||||
private OwnerOfRelationCodeId codeObject = new OwnerOfRelationCodeId();
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "compositeEntity_firstCode", referencedColumnName = "firstCode", unique = false, nullable = false),
|
||||
@JoinColumn(name = "compositeEntity_secondCode", referencedColumnName = "secondCode", unique = false, nullable = false) })
|
||||
@MapsId("compositeEntity")
|
||||
private CompositeEntity compositeEntity;
|
||||
|
||||
private String description;
|
||||
|
||||
public OwnerOfRelationCodeId getCodeObject() {
|
||||
return codeObject;
|
||||
}
|
||||
|
||||
public CompositeEntity getCompositeEntity() {
|
||||
return compositeEntity;
|
||||
}
|
||||
|
||||
public void setCompositeEntity(CompositeEntity compositeEntity) {
|
||||
if ( codeObject == null ) {
|
||||
codeObject = new OwnerOfRelationCodeId();
|
||||
}
|
||||
if ( compositeEntity != null ) {
|
||||
codeObject.setCompositeEntity( compositeEntity.getCodeObject() );
|
||||
}
|
||||
this.compositeEntity = compositeEntity;
|
||||
}
|
||||
|
||||
public String getSecondIdentifier() {
|
||||
return codeObject == null ? null : codeObject.getSecondIdentifier();
|
||||
|
||||
}
|
||||
|
||||
public void setSecondIdentifier(String secondIdentifier) {
|
||||
if ( codeObject == null ) {
|
||||
codeObject = new OwnerOfRelationCodeId();
|
||||
}
|
||||
codeObject.setSecondIdentifier( secondIdentifier );
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OwnerOfRelationCode{" +
|
||||
"codeObject=" + codeObject +
|
||||
", compositeEntity=" + compositeEntity +
|
||||
", description='" + description + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.ids.embeddedid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
|
||||
@Embeddable
|
||||
public class OwnerOfRelationCodeId implements Serializable {
|
||||
|
||||
@Embedded
|
||||
private CompositeEntityId compositeEntity;
|
||||
|
||||
private String secondIdentifier;
|
||||
|
||||
public CompositeEntityId getCompositeEntity() {
|
||||
return compositeEntity;
|
||||
}
|
||||
|
||||
public void setCompositeEntity(CompositeEntityId compositeEntity) {
|
||||
this.compositeEntity = compositeEntity;
|
||||
}
|
||||
|
||||
public String getSecondIdentifier() {
|
||||
return secondIdentifier;
|
||||
}
|
||||
|
||||
public void setSecondIdentifier(String secondIdentifier) {
|
||||
this.secondIdentifier = secondIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OwnerOfRelationCodeId{" +
|
||||
"compositeEntity=" + compositeEntity +
|
||||
", secondIdentifier='" + secondIdentifier + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue