HHH-8174 - Envers support for @NotFound

This commit is contained in:
Lukasz Antoniak 2013-06-11 09:08:56 -07:00
parent b4ab20a97b
commit f2d435ddc1
11 changed files with 531 additions and 139 deletions

View File

@ -380,8 +380,12 @@
<para>
If you want to audit a relation, where the target entity is not audited (that is the case for example with
dictionary-like entities, which don't change and don't have to be audited), just annotate it with
<literal>@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)</literal>. Then, when reading historic
versions of your entity, the relation will always point to the "current" related entity.
<literal>@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)</literal>. Then, while reading historic
versions of your entity, the relation will always point to the "current" related entity. By default Envers
throws <classname>javax.persistence.EntityNotFoundException</classname> when "current" entity does not
exist in the database. Apply <literal>@NotFound(action = NotFoundAction.IGNORE)</literal> annotation
to silence the exception and assign null value instead. Hereby solution causes implicit eager loading
of to-one relations.
</para>
<para>

View File

@ -77,10 +77,8 @@ public final class ToOneRelationMetadataGenerator {
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(),
referencedEntityName,
relMapper,
insertable
propertyAuditingData.getName(), referencedEntityName, relMapper,
insertable, MappingTools.ignoreNotFound( value )
);
// If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
@ -154,10 +152,8 @@ public final class ToOneRelationMetadataGenerator {
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneNotOwningRelation(
propertyAuditingData.getName(),
owningReferencePropertyName,
referencedEntityName,
ownedIdMapper
propertyAuditingData.getName(), owningReferencePropertyName, referencedEntityName,
ownedIdMapper, MappingTools.ignoreNotFound( value )
);
// Adding mapper for the id
@ -191,10 +187,8 @@ public final class ToOneRelationMetadataGenerator {
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get( entityName ).addToOneRelation(
propertyAuditingData.getName(),
referencedEntityName,
relMapper,
insertable
propertyAuditingData.getName(), referencedEntityName, relMapper, insertable,
MappingTools.ignoreNotFound( value )
);
// Adding mapper for the id

View File

@ -46,8 +46,7 @@ public class EntityConfiguration {
private Map<String, RelationDescription> relations;
private String parentEntityName;
public EntityConfiguration(
String versionsEntityName, String entityClassName, IdMappingData idMappingData,
public EntityConfiguration(String versionsEntityName, String entityClassName, IdMappingData idMappingData,
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
this.versionsEntityName = versionsEntityName;
this.entityClassName = entityClassName;
@ -58,60 +57,36 @@ public class EntityConfiguration {
this.relations = new HashMap<String, RelationDescription>();
}
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable) {
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper, boolean insertable,
boolean ignoreNotFound) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_ONE,
toEntityName,
null,
idMapper,
null,
null,
insertable
RelationDescription.toOne(
fromPropertyName, RelationType.TO_ONE, toEntityName, null, idMapper, null,
null, insertable, ignoreNotFound
)
);
}
public void addToOneNotOwningRelation(
String fromPropertyName,
String mappedByPropertyName,
String toEntityName,
IdMapper idMapper) {
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName,
String toEntityName, IdMapper idMapper, boolean ignoreNotFound) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_ONE_NOT_OWNING,
toEntityName,
mappedByPropertyName,
idMapper,
null,
null,
true
RelationDescription.toOne(
fromPropertyName, RelationType.TO_ONE_NOT_OWNING, toEntityName, mappedByPropertyName,
idMapper, null, null, true, ignoreNotFound
)
);
}
public void addToManyNotOwningRelation(
String fromPropertyName,
String mappedByPropertyName,
String toEntityName,
IdMapper idMapper,
PropertyMapper fakeBidirectionalRelationMapper,
public void addToManyNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper,
PropertyMapper fakeBidirectionalRelationIndexMapper) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_MANY_NOT_OWNING,
toEntityName,
mappedByPropertyName,
idMapper,
fakeBidirectionalRelationMapper,
fakeBidirectionalRelationIndexMapper,
true
RelationDescription.toMany(
fromPropertyName, RelationType.TO_MANY_NOT_OWNING, toEntityName, mappedByPropertyName,
idMapper, fakeBidirectionalRelationMapper, fakeBidirectionalRelationIndexMapper, true
)
);
}
@ -119,34 +94,18 @@ public class EntityConfiguration {
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_MANY_MIDDLE,
toEntityName,
null,
null,
null,
null,
true
RelationDescription.toMany(
fromPropertyName, RelationType.TO_MANY_MIDDLE, toEntityName, null, null, null, null, true
)
);
}
public void addToManyMiddleNotOwningRelation(
String fromPropertyName,
String mappedByPropertyName,
String toEntityName) {
public void addToManyMiddleNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName) {
relations.put(
fromPropertyName,
new RelationDescription(
fromPropertyName,
RelationType.TO_MANY_MIDDLE_NOT_OWNING,
toEntityName,
mappedByPropertyName,
null,
null,
null,
true
RelationDescription.toMany(
fromPropertyName, RelationType.TO_MANY_MIDDLE_NOT_OWNING, toEntityName, mappedByPropertyName,
null, null, null, true
)
);
}
@ -175,6 +134,13 @@ public class EntityConfiguration {
return parentEntityName;
}
/**
* @return the className for the configured entity
*/
public String getEntityClassName() {
return entityClassName;
}
// For use by EntitiesConfigurations
String getVersionsEntityName() {
@ -184,11 +150,4 @@ public class EntityConfiguration {
Iterable<RelationDescription> getRelationsIterator() {
return relations.values();
}
/**
* @return the className for the configured entity
*/
public String getEntityClassName() {
return entityClassName;
}
}

View File

@ -34,21 +34,44 @@ public class RelationDescription {
private final RelationType relationType;
private final String toEntityName;
private final String mappedByPropertyName;
private final boolean ignoreNotFound;
private final IdMapper idMapper;
private final PropertyMapper fakeBidirectionalRelationMapper;
private final PropertyMapper fakeBidirectionalRelationIndexMapper;
private final boolean insertable;
private boolean bidirectional;
public RelationDescription(
String fromPropertyName, RelationType relationType, String toEntityName,
String mappedByPropertyName, IdMapper idMapper,
PropertyMapper fakeBidirectionalRelationMapper,
public static RelationDescription toOne(String fromPropertyName, RelationType relationType, String toEntityName,
String mappedByPropertyName, IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper,
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable,
boolean ignoreNotFound) {
return new RelationDescription(
fromPropertyName, relationType, toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper,
fakeBidirectionalRelationIndexMapper, insertable, ignoreNotFound
);
}
public static RelationDescription toMany(String fromPropertyName, RelationType relationType, String toEntityName,
String mappedByPropertyName, IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper,
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable) {
// Envers populates collections by executing dedicated queries. Special handling of
// @NotFound(action = NotFoundAction.IGNORE) can be omitted in such case as exceptions
// (e.g. EntityNotFoundException, ObjectNotFoundException) are never thrown.
// Therefore assigning false to ignoreNotFound.
return new RelationDescription(
fromPropertyName, relationType, toEntityName, mappedByPropertyName, idMapper, fakeBidirectionalRelationMapper,
fakeBidirectionalRelationIndexMapper, insertable, false
);
}
private RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName,
String mappedByPropertyName, IdMapper idMapper, PropertyMapper fakeBidirectionalRelationMapper,
PropertyMapper fakeBidirectionalRelationIndexMapper, boolean insertable, boolean ignoreNotFound) {
this.fromPropertyName = fromPropertyName;
this.relationType = relationType;
this.toEntityName = toEntityName;
this.mappedByPropertyName = mappedByPropertyName;
this.ignoreNotFound = ignoreNotFound;
this.idMapper = idMapper;
this.fakeBidirectionalRelationMapper = fakeBidirectionalRelationMapper;
this.fakeBidirectionalRelationIndexMapper = fakeBidirectionalRelationIndexMapper;
@ -73,6 +96,10 @@ public class RelationDescription {
return mappedByPropertyName;
}
public boolean isIgnoreNotFound() {
return ignoreNotFound;
}
public IdMapper getIdMapper() {
return idMapper;
}

View File

@ -35,7 +35,8 @@ import org.hibernate.persister.entity.EntityPersister;
*/
public class ToOneEntityLoader {
/**
* Immediately loads historical entity or its current state when excluded from audit process.
* Immediately loads historical entity or its current state when excluded from audit process. Returns {@code null}
* reference if entity has not been found in the database.
*/
public static Object loadImmediate(
AuditReaderImplementor versionsReader,

View File

@ -45,10 +45,7 @@ public class ToOneIdMapper extends AbstractToOneMapper {
private final String referencedEntityName;
private final boolean nonInsertableFake;
public ToOneIdMapper(
IdMapper delegate,
PropertyData propertyData,
String referencedEntityName,
public ToOneIdMapper(IdMapper delegate, PropertyData propertyData, String referencedEntityName,
boolean nonInsertableFake) {
super( propertyData );
this.delegate = delegate;
@ -57,10 +54,7 @@ public class ToOneIdMapper extends AbstractToOneMapper {
}
@Override
public boolean mapToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
public boolean mapToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj,
Object oldObj) {
final HashMap<String, Object> newData = new HashMap<String, Object>();
@ -77,10 +71,7 @@ public class ToOneIdMapper extends AbstractToOneMapper {
}
@Override
public void mapModifiedFlagsToMapFromEntity(
SessionImplementor session,
Map<String, Object> data,
Object newObj,
public void mapModifiedFlagsToMapFromEntity(SessionImplementor session, Map<String, Object> data, Object newObj,
Object oldObj) {
if ( getPropertyData().isUsingModifiedFlag() ) {
data.put( getPropertyData().getModifiedFlagPropertyName(), checkModified( session, newObj, oldObj ) );
@ -103,8 +94,7 @@ public class ToOneIdMapper extends AbstractToOneMapper {
}
@Override
public void nullSafeMapToEntityFromMap(
AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
public void nullSafeMapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
AuditReaderImplementor versionsReader, Number revision) {
final Object entityId = delegate.mapToIdFromMap( data );
Object value = null;
@ -114,27 +104,35 @@ public class ToOneIdMapper extends AbstractToOneMapper {
}
else {
final EntityInfo referencedEntity = getEntityInfo( verCfg, referencedEntityName );
boolean ignoreNotFound = false;
if ( !referencedEntity.isAudited() ) {
final String referencingEntityName = verCfg.getEntCfg().getEntityNameForVersionsEntityName( (String) data.get( "$type$" ) );
ignoreNotFound = verCfg.getEntCfg().get( referencingEntityName ).getRelationDescription( getPropertyData().getName() ).isIgnoreNotFound();
}
if ( ignoreNotFound ) {
// Eagerly loading referenced entity to silence potential (in case of proxy)
// EntityNotFoundException or ObjectNotFoundException. Assigning null reference.
value = ToOneEntityLoader.loadImmediate(
versionsReader, referencedEntity.getEntityClass(), referencedEntityName,
entityId, revision, RevisionType.DEL.equals( data.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) ),
verCfg
);
}
else {
value = ToOneEntityLoader.createProxyOrLoadImmediate(
versionsReader, referencedEntity.getEntityClass(), referencedEntityName,
entityId, revision, RevisionType.DEL.equals(
data.get(
verCfg.getAuditEntCfg()
.getRevisionTypePropName()
)
), verCfg
entityId, revision, RevisionType.DEL.equals( data.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) ),
verCfg
);
}
}
}
setPropertyValue( obj, value );
}
public void addMiddleEqualToQuery(
Parameters parameters,
String idPrefix1,
String prefix1,
String idPrefix2,
String prefix2) {
public void addMiddleEqualToQuery(Parameters parameters, String idPrefix1, String prefix1,
String idPrefix2, String prefix2) {
delegate.addIdsEqualToQuery( parameters, prefix1, delegate, prefix2 );
}
}

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.internal.tools;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
@ -63,4 +64,18 @@ public abstract class MappingTools {
return null;
}
/**
* @param value Persistent property.
* @return {@code false} if lack of associated entity shall raise an exception, {@code true} otherwise.
*/
public static boolean ignoreNotFound(Value value) {
if ( value instanceof ManyToOne ) {
return ( (ManyToOne) value ).isIgnoreNotFound();
}
else if ( value instanceof OneToMany ) {
return ( (OneToMany) value ).isIgnoreNotFound();
}
return false;
}
}

View File

@ -0,0 +1,111 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.manytomany.unidirectional;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Audited
@Entity
@Table(name = "M2M_N_AUD_NULL")
public class ManyToManyNotAuditedNullEntity implements Serializable {
@Id
private Integer id;
private String data;
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@ManyToMany(fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE)
private List<UnversionedStrTestEntity> references = new ArrayList<UnversionedStrTestEntity>();
protected ManyToManyNotAuditedNullEntity() {
}
public ManyToManyNotAuditedNullEntity(Integer id, String data) {
this.id = id;
this.data = data;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof ManyToManyNotAuditedNullEntity ) ) return false;
ManyToManyNotAuditedNullEntity that = (ManyToManyNotAuditedNullEntity) o;
if ( data != null ? !data.equals( that.getData() ) : that.getData() != null ) return false;
if ( id != null ? !id.equals( that.getId() ) : that.getId() != null ) return false;
return true;
}
public int hashCode() {
int result = ( id != null ? id.hashCode() : 0 );
result = 31 * result + ( data != null ? data.hashCode() : 0 );
return result;
}
public String toString() {
return "ManyToManyNotAuditedNullEntity(id = " + id + ", data = " + data + ")";
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public List<UnversionedStrTestEntity> getReferences() {
return references;
}
public void setReferences(List<UnversionedStrTestEntity> references) {
this.references = references;
}
}

View File

@ -0,0 +1,110 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.manytoone.unidirectional;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Audited
@Entity
@Table(name = "M2O_N_AUD_NULL")
public class ManyToOneNotAuditedNullEntity implements Serializable {
@Id
private Integer id;
private String data;
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@NotFound(action = NotFoundAction.IGNORE)
private UnversionedStrTestEntity reference;
protected ManyToOneNotAuditedNullEntity() {
}
public ManyToOneNotAuditedNullEntity(Integer id, String data, UnversionedStrTestEntity reference) {
this.id = id;
this.data = data;
this.reference = reference;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof ManyToOneNotAuditedNullEntity ) ) return false;
ManyToOneNotAuditedNullEntity that = (ManyToOneNotAuditedNullEntity) o;
if ( data != null ? !data.equals( that.getData() ) : that.getData() != null ) return false;
if ( id != null ? !id.equals( that.getId() ) : that.getId() != null ) return false;
return true;
}
public int hashCode() {
int result = ( id != null ? id.hashCode() : 0 );
result = 31 * result + ( data != null ? data.hashCode() : 0 );
return result;
}
public String toString() {
return "ManyToOneNotAuditedNullEntity(id = " + id + ", data = " + data + ")";
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public UnversionedStrTestEntity getReference() {
return reference;
}
public void setReference(UnversionedStrTestEntity reference) {
this.reference = reference;
}
}

View File

@ -0,0 +1,111 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.onetomany;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Audited
@Entity
@Table(name = "O2M_N_AUD_NULL")
public class OneToManyNotAuditedNullEntity implements Serializable {
@Id
private Integer id;
private String data;
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@OneToMany(fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE)
private List<UnversionedStrTestEntity> references = new ArrayList<UnversionedStrTestEntity>();
protected OneToManyNotAuditedNullEntity() {
}
public OneToManyNotAuditedNullEntity(Integer id, String data) {
this.id = id;
this.data = data;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( !( o instanceof OneToManyNotAuditedNullEntity ) ) return false;
OneToManyNotAuditedNullEntity that = (OneToManyNotAuditedNullEntity) o;
if ( data != null ? !data.equals( that.getData() ) : that.getData() != null ) return false;
if ( id != null ? !id.equals( that.getId() ) : that.getId() != null ) return false;
return true;
}
public int hashCode() {
int result = ( id != null ? id.hashCode() : 0 );
result = 31 * result + ( data != null ? data.hashCode() : 0 );
return result;
}
public String toString() {
return "OneToManyNotAuditedNullEntity(id = " + id + ", data = " + data + ")";
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public List<UnversionedStrTestEntity> getReferences() {
return references;
}
public void setReferences(List<UnversionedStrTestEntity> references) {
this.references = references;
}
}

View File

@ -25,26 +25,37 @@ package org.hibernate.envers.test.integration.proxy;
import javax.persistence.EntityManager;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
import org.hibernate.envers.test.entities.manytomany.unidirectional.ManyToManyNotAuditedNullEntity;
import org.hibernate.envers.test.entities.manytoone.unidirectional.ManyToOneNotAuditedNullEntity;
import org.hibernate.envers.test.entities.manytoone.unidirectional.TargetNotAuditedEntity;
import org.hibernate.envers.test.entities.onetomany.OneToManyNotAuditedNullEntity;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.junit.Test;
import org.hibernate.testing.TestForIssue;
/**
* @author Eugene Goroschenya
*/
public class ProxyIdentifier extends BaseEnversJPAFunctionalTestCase {
private TargetNotAuditedEntity tnae1;
private UnversionedStrTestEntity uste1;
private TargetNotAuditedEntity tnae1 = null;
private ManyToOneNotAuditedNullEntity mtonane1 = null;
private ManyToManyNotAuditedNullEntity mtmnane1 = null;
private OneToManyNotAuditedNullEntity otmnane1 = null;
private UnversionedStrTestEntity uste1 = null;
private UnversionedStrTestEntity uste2 = null;
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {TargetNotAuditedEntity.class, UnversionedStrTestEntity.class};
return new Class[] {
TargetNotAuditedEntity.class, ManyToOneNotAuditedNullEntity.class, UnversionedStrTestEntity.class,
ManyToManyNotAuditedNullEntity.class, OneToManyNotAuditedNullEntity.class
};
}
@Test
@ -53,10 +64,12 @@ public class ProxyIdentifier extends BaseEnversJPAFunctionalTestCase {
EntityManager em = getEntityManager();
uste1 = new UnversionedStrTestEntity( "str1" );
uste2 = new UnversionedStrTestEntity( "str2" );
// No revision
em.getTransaction().begin();
em.persist( uste1 );
em.persist( uste2 );
em.getTransaction().commit();
// Revision 1
@ -65,24 +78,73 @@ public class ProxyIdentifier extends BaseEnversJPAFunctionalTestCase {
tnae1 = new TargetNotAuditedEntity( 1, "tnae1", uste1 );
em.persist( tnae1 );
em.getTransaction().commit();
// Revision 2
em.getTransaction().begin();
uste2 = em.find( UnversionedStrTestEntity.class, uste2.getId() );
mtonane1 = new ManyToOneNotAuditedNullEntity( 2, "mtonane1", uste2 );
mtmnane1 = new ManyToManyNotAuditedNullEntity( 3, "mtmnane1" );
mtmnane1.getReferences().add( uste2 );
otmnane1 = new OneToManyNotAuditedNullEntity( 4, "otmnane1" );
otmnane1.getReferences().add( uste2 );
em.persist( mtonane1 );
em.persist( mtmnane1 );
em.persist( otmnane1 );
em.getTransaction().commit();
em.clear();
// Revision 3
// Remove not audited target entity, so we can verify null reference
// when @NotFound(action = NotFoundAction.IGNORE) applied.
em.getTransaction().begin();
ManyToOneNotAuditedNullEntity tmp1 = em.find( ManyToOneNotAuditedNullEntity.class, mtonane1.getId() );
tmp1.setReference( null );
tmp1 = em.merge( tmp1 );
ManyToManyNotAuditedNullEntity tmp2 = em.find( ManyToManyNotAuditedNullEntity.class, mtmnane1.getId() );
tmp2.setReferences( null );
tmp2 = em.merge( tmp2 );
OneToManyNotAuditedNullEntity tmp3 = em.find( OneToManyNotAuditedNullEntity.class, otmnane1.getId() );
tmp3.setReferences( null );
tmp3 = em.merge( tmp3 );
em.remove( em.getReference( UnversionedStrTestEntity.class, uste2.getId() ) );
em.getTransaction().commit();
em.close();
}
@Test
public void testProxyIdentifier() {
TargetNotAuditedEntity rev1 = getAuditReader().find( TargetNotAuditedEntity.class, tnae1.getId(), 1 );
assert rev1.getReference() instanceof HibernateProxy;
Assert.assertTrue( rev1.getReference() instanceof HibernateProxy );
HibernateProxy proxyCreateByEnvers = (HibernateProxy) rev1.getReference();
LazyInitializer lazyInitializer = proxyCreateByEnvers.getHibernateLazyInitializer();
assert lazyInitializer.isUninitialized();
assert lazyInitializer.getIdentifier() != null;
assert lazyInitializer.getIdentifier().equals( tnae1.getId() );
assert lazyInitializer.isUninitialized();
Assert.assertTrue( lazyInitializer.isUninitialized() );
Assert.assertNotNull( lazyInitializer.getIdentifier() );
Assert.assertEquals( tnae1.getId(), lazyInitializer.getIdentifier() );
Assert.assertTrue( lazyInitializer.isUninitialized() );
assert rev1.getReference().getId().equals( uste1.getId() );
assert rev1.getReference().getStr().equals( uste1.getStr() );
assert !lazyInitializer.isUninitialized();
Assert.assertEquals( uste1.getId(), rev1.getReference().getId() );
Assert.assertEquals( uste1.getStr(), rev1.getReference().getStr() );
Assert.assertFalse( lazyInitializer.isUninitialized() );
}
@Test
@TestForIssue( jiraKey = "HHH-8174" )
public void testNullReferenceWithNotFoundActionIgnore() {
ManyToOneNotAuditedNullEntity mtoRev2 = getAuditReader().find( ManyToOneNotAuditedNullEntity.class, mtonane1.getId(), 2 );
Assert.assertEquals( mtonane1, mtoRev2 );
Assert.assertNull( mtoRev2.getReference() );
ManyToManyNotAuditedNullEntity mtmRev2 = getAuditReader().find( ManyToManyNotAuditedNullEntity.class, mtmnane1.getId(), 2 );
Assert.assertEquals( mtmnane1, mtmRev2 );
Assert.assertTrue( mtmRev2.getReferences().isEmpty() );
OneToManyNotAuditedNullEntity otmRev2 = getAuditReader().find( OneToManyNotAuditedNullEntity.class, otmnane1.getId(), 2 );
Assert.assertEquals( otmnane1, otmRev2 );
Assert.assertTrue( otmRev2.getReferences().isEmpty() );
}
}