HHH-4010:

- applying patch: allow audited relations to non-audited entities
- doc update

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17248 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Adam Warski 2009-08-06 18:21:38 +00:00
parent 8465009b4b
commit 5d08386293
15 changed files with 450 additions and 32 deletions

View File

@ -218,4 +218,11 @@
please see <xref linkend="exceptions"/> for a description of the additional please see <xref linkend="exceptions"/> for a description of the additional
<literal>@AuditJoinTable</literal> annotation that you'll probably want to use. <literal>@AuditJoinTable</literal> annotation that you'll probably want to use.
</para> </para>
<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.
</para>
</chapter> </chapter>

View File

@ -32,9 +32,17 @@ import java.lang.annotation.Target;
* When applied to a class, indicates that all of its properties should be audited. * When applied to a class, indicates that all of its properties should be audited.
* When applied to a field, indicates that this field should be audited. * When applied to a field, indicates that this field should be audited.
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Tomasz Bech
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface Audited { public @interface Audited {
ModificationStore modStore() default ModificationStore.FULL; ModificationStore modStore() default ModificationStore.FULL;
/**
* @return Specifies if the entity that is the target of the relation should be audited or not. If not, then when
* reading a historic version an audited entity, the realtion will always point to the "current" entity.
* This is useful for dictionary-like entities, which don't change and don't need to be audited.
*/
RelationTargetAuditMode targetAuditMode() default RelationTargetAuditMode.AUDITED;
} }

View File

@ -0,0 +1,32 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
*
* 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;
/**
* @author Tomasz Bech
*/
public enum RelationTargetAuditMode {
AUDITED,
NOT_AUDITED
}

View File

@ -84,9 +84,13 @@ public class EntitiesConfigurator {
} }
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData(); EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData); auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, true);
xmlMappings.put(pc, xmlMappingData); xmlMappings.put(pc, xmlMappingData);
} } else {
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, false);
xmlMappings.put(pc, xmlMappingData);
}
} }
// Second pass // Second pass
@ -123,7 +127,8 @@ public class EntitiesConfigurator {
} }
} }
return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations()); return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations(),
auditMetaGen.getNotAuditedEntitiesConfigurations());
} }
// todo // todo

View File

@ -53,6 +53,7 @@ import org.hibernate.type.*;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander * @author Sebastian Komander
* @author Tomasz Bech
*/ */
public final class AuditMetadataGenerator { public final class AuditMetadataGenerator {
private final Configuration cfg; private final Configuration cfg;
@ -66,6 +67,7 @@ public final class AuditMetadataGenerator {
private final ToOneRelationMetadataGenerator toOneRelationMetadataGenerator; private final ToOneRelationMetadataGenerator toOneRelationMetadataGenerator;
private final Map<String, EntityConfiguration> entitiesConfigurations; private final Map<String, EntityConfiguration> entitiesConfigurations;
private final Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
// Map entity name -> (join descriptor -> element describing the "versioned" join) // Map entity name -> (join descriptor -> element describing the "versioned" join)
private final Map<String, Map<Join, Element>> entitiesJoins; private final Map<String, Map<Join, Element>> entitiesJoins;
@ -84,6 +86,7 @@ public final class AuditMetadataGenerator {
this.toOneRelationMetadataGenerator = new ToOneRelationMetadataGenerator(this); this.toOneRelationMetadataGenerator = new ToOneRelationMetadataGenerator(this);
entitiesConfigurations = new HashMap<String, EntityConfiguration>(); entitiesConfigurations = new HashMap<String, EntityConfiguration>();
notAuditedEntitiesConfigurations = new HashMap<String, EntityConfiguration>();
entitiesJoins = new HashMap<String, Map<Join, Element>>(); entitiesJoins = new HashMap<String, Map<Join, Element>>();
} }
@ -278,7 +281,7 @@ public final class AuditMetadataGenerator {
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
public void generateFirstPass(PersistentClass pc, ClassAuditingData auditingData, public void generateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
EntityXmlMappingData xmlMappingData) { EntityXmlMappingData xmlMappingData, boolean isAudited) {
String schema = auditingData.getAuditTable().schema(); String schema = auditingData.getAuditTable().schema();
if (StringTools.isEmpty(schema)) { if (StringTools.isEmpty(schema)) {
schema = pc.getTable().getSchema(); schema = pc.getTable().getSchema();
@ -289,6 +292,17 @@ public final class AuditMetadataGenerator {
catalog = pc.getTable().getCatalog(); catalog = pc.getTable().getCatalog();
} }
if (!isAudited) {
String entityName = pc.getEntityName();
IdMappingData idMapper = idMetadataGenerator.addId(pc);
ExtendedPropertyMapper propertyMapper = null;
String parentEntityName = null;
EntityConfiguration entityCfg = new EntityConfiguration(entityName, idMapper, propertyMapper,
parentEntityName);
notAuditedEntitiesConfigurations.put(pc.getEntityName(), entityCfg);
return;
}
String entityName = pc.getEntityName(); String entityName = pc.getEntityName();
String auditEntityName = verEntCfg.getAuditEntityName(entityName); String auditEntityName = verEntCfg.getAuditEntityName(entityName);
String auditTableName = verEntCfg.getAuditTableName(entityName, pc.getTable().getName()); String auditTableName = verEntCfg.getAuditTableName(entityName, pc.getTable().getName());
@ -400,4 +414,13 @@ public final class AuditMetadataGenerator {
throw new MappingException(message); throw new MappingException(message);
} }
/**
* Get the notAuditedEntitiesConfigurations property.
*
* @return the notAuditedEntitiesConfigurations property value
*/
public Map<String, EntityConfiguration> getNotAuditedEntitiesConfigurations() {
return notAuditedEntitiesConfigurations;
}
} }

View File

@ -36,6 +36,7 @@ import javax.persistence.JoinColumn;
import org.dom4j.Element; import org.dom4j.Element;
import org.hibernate.envers.ModificationStore; import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData; import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.EntityConfiguration; import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData; import org.hibernate.envers.entities.IdMappingData;
@ -231,7 +232,7 @@ public final class CollectionMetadataGenerator {
// middle table for mapping this relation. // middle table for mapping this relation.
return StringTools.getLastComponent(entityName) + "_" + StringTools.getLastComponent(getReferencedEntityName(value.getElement())); return StringTools.getLastComponent(entityName) + "_" + StringTools.getLastComponent(getReferencedEntityName(value.getElement()));
} else { } else {
// Hibernate uses a middle table for mapping this relation, so we get it's name directly. // Hibernate uses a middle table for mapping this relation, so we get it's name directly.
return value.getCollectionTable().getName(); return value.getCollectionTable().getName();
} }
} }
@ -413,7 +414,7 @@ public final class CollectionMetadataGenerator {
} else { } else {
// Last but one parameter: collection components are always insertable // Last but one parameter: collection components are always insertable
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping, boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(xmlMapping,
new PropertyAuditingData(prefix, "field", ModificationStore.FULL), value, null, new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED), value, null,
true, true); true, true);
if (mapped) { if (mapped) {

View File

@ -28,6 +28,7 @@ import java.util.Iterator;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
import org.hibernate.envers.ModificationStore; import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData; import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
import org.hibernate.envers.entities.IdMappingData; import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData; import org.hibernate.envers.entities.PropertyData;
@ -133,6 +134,6 @@ public final class IdMetadataGenerator {
private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) { private PropertyAuditingData getIdPersistentPropertyAuditingData(Property property) {
return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(), return new PropertyAuditingData(property.getName(), property.getPropertyAccessorName(),
ModificationStore.FULL); ModificationStore.FULL, RelationTargetAuditMode.AUDITED);
} }
} }

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.configuration.metadata; package org.hibernate.envers.configuration.metadata;
import org.dom4j.Element; import org.dom4j.Element;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.entities.EntityConfiguration; import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData; import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData; import org.hibernate.envers.entities.PropertyData;
@ -54,10 +55,22 @@ public final class ToOneRelationMetadataGenerator {
CompositeMapperBuilder mapper, String entityName, boolean insertable) { CompositeMapperBuilder mapper, String entityName, boolean insertable) {
String referencedEntityName = ((ToOne) value).getReferencedEntityName(); String referencedEntityName = ((ToOne) value).getReferencedEntityName();
EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(referencedEntityName); EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(referencedEntityName);
if (configuration == null) { if (configuration == null) {
throw new MappingException("An audited relation to a non-audited entity " + referencedEntityName + "!"); configuration = mainGenerator.getNotAuditedEntitiesConfigurations().get(referencedEntityName);
} if (configuration != null) {
RelationTargetAuditMode relationTargetAuditMode = propertyAuditingData.getRelationTargetAuditMode();
if (!RelationTargetAuditMode.NOT_AUDITED.equals(relationTargetAuditMode)) {
throw new MappingException("An audited relation from " + entityName + "."
+ propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!"
+ ". Such mapping is possible, but has to be strictly defined using RelationTargetAuditMode.NOT_AUDITED in @Audited.");
}
}
}
if (configuration == null) {
throw new MappingException("An audited relation from " + entityName + "."
+ propertyAuditingData.getName() + " to a not audited entity " + referencedEntityName + "!");
}
IdMappingData idMapping = configuration.getIdMappingData(); IdMappingData idMapping = configuration.getIdMappingData();

View File

@ -160,6 +160,7 @@ public class AuditedPropertiesReader {
Versioned ver = property.getAnnotation(Versioned.class); Versioned ver = property.getAnnotation(Versioned.class);
if (aud != null) { if (aud != null) {
propertyData.setStore(aud.modStore()); propertyData.setStore(aud.modStore());
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
} else if (ver != null) { } else if (ver != null) {
propertyData.setStore(ModificationStore.FULL); propertyData.setStore(ModificationStore.FULL);
} else { } else {
@ -203,7 +204,7 @@ public class AuditedPropertiesReader {
/*** /***
* Add the {@link org.hibernate.envers.AuditOverride} annotations. * Add the {@link org.hibernate.envers.AuditOverride} annotations.
* *
* @param property the property being processed * @param property the property being processed
* @param propertyData the Envers auditing data for this property * @param propertyData the Envers auditing data for this property
*/ */
@ -220,13 +221,13 @@ public class AuditedPropertiesReader {
/** /**
* Process the {@link org.hibernate.envers.AuditOverride} annotations for this property. * Process the {@link org.hibernate.envers.AuditOverride} annotations for this property.
* *
* @param property * @param property
* the property for which the {@link org.hibernate.envers.AuditOverride} * the property for which the {@link org.hibernate.envers.AuditOverride}
* annotations are being processed * annotations are being processed
* @param propertyData * @param propertyData
* the Envers auditing data for this property * the Envers auditing data for this property
* @return {@code false} if isAudited() of the override annotation was set to * @return {@code false} if isAudited() of the override annotation was set to
*/ */
private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) { private boolean processPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
// if this property is part of a component, process all override annotations // if this property is part of a component, process all override annotations
@ -236,7 +237,7 @@ public class AuditedPropertiesReader {
if (property.getName().equals(override.name())) { if (property.getName().equals(override.name())) {
// the override applies to this property // the override applies to this property
if (!override.isAudited()) { if (!override.isAudited()) {
return false; return false;
} else { } else {
if (override.auditJoinTable() != null) { if (override.auditJoinTable() != null) {
propertyData.setJoinTable(override.auditJoinTable()); propertyData.setJoinTable(override.auditJoinTable());
@ -267,7 +268,7 @@ public class AuditedPropertiesReader {
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
throw new MappingException(e); throw new MappingException(e);
} }
this.component = component; this.component = component;
} }

View File

@ -31,6 +31,7 @@ import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.AuditOverrides; import org.hibernate.envers.AuditOverrides;
import org.hibernate.envers.ModificationStore; import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.AuditJoinTable; import org.hibernate.envers.AuditJoinTable;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.entities.PropertyData; import org.hibernate.envers.entities.PropertyData;
/** /**
@ -44,15 +45,18 @@ public class PropertyAuditingData {
private AuditJoinTable joinTable; private AuditJoinTable joinTable;
private String accessType; private String accessType;
private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>(0); private final List<AuditOverride> auditJoinTableOverrides = new ArrayList<AuditOverride>(0);
private RelationTargetAuditMode relationTargetAuditMode;
public PropertyAuditingData() { public PropertyAuditingData() {
} }
public PropertyAuditingData(String name, String accessType, ModificationStore store) { public PropertyAuditingData(String name, String accessType, ModificationStore store,
RelationTargetAuditMode relationTargetAuditMode) {
this.name = name; this.name = name;
this.beanName = name; this.beanName = name;
this.accessType = accessType; this.accessType = accessType;
this.store = store; this.store = store;
this.relationTargetAuditMode = relationTargetAuditMode;
} }
public String getName() { public String getName() {
@ -108,7 +112,7 @@ public class PropertyAuditingData {
} }
public List<AuditOverride> getAuditingOverrides() { public List<AuditOverride> getAuditingOverrides() {
return auditJoinTableOverrides; return auditJoinTableOverrides;
} }
public void addAuditingOverride(AuditOverride annotation) { public void addAuditingOverride(AuditOverride annotation) {
@ -135,4 +139,22 @@ public class PropertyAuditingData {
} }
} }
/**
* Get the relationTargetAuditMode property.
*
* @return the relationTargetAuditMode property value
*/
public RelationTargetAuditMode getRelationTargetAuditMode() {
return relationTargetAuditMode;
}
/**
* Set the relationTargetAuditMode property value.
*
* @param relationTargetAuditMode the relationTargetAuditMode to set
*/
public void setRelationTargetAuditMode(RelationTargetAuditMode relationTargetAuditMode) {
this.relationTargetAuditMode = relationTargetAuditMode;
}
} }

View File

@ -32,12 +32,15 @@ import java.util.Map;
*/ */
public class EntitiesConfigurations { public class EntitiesConfigurations {
private Map<String, EntityConfiguration> entitiesConfigurations; private Map<String, EntityConfiguration> entitiesConfigurations;
private Map<String, EntityConfiguration> notAuditedEntitiesConfigurations;
// Map versions entity name -> entity name // Map versions entity name -> entity name
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>(); private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations) { public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations,
Map<String, EntityConfiguration> notAuditedEntitiesConfigurations) {
this.entitiesConfigurations = entitiesConfigurations; this.entitiesConfigurations = entitiesConfigurations;
this.notAuditedEntitiesConfigurations = notAuditedEntitiesConfigurations;
generateBidirectionRelationInfo(); generateBidirectionRelationInfo();
generateVersionsEntityToEntityNames(); generateVersionsEntityToEntityNames();
@ -61,14 +64,17 @@ public class EntitiesConfigurations {
// If this is an "owned" relation, checking the related entity, if it has a relation that has // If this is an "owned" relation, checking the related entity, if it has a relation that has
// a mapped-by attribute to the currently checked. If so, this is a bidirectional relation. // a mapped-by attribute to the currently checked. If so, this is a bidirectional relation.
if (relDesc.getRelationType() == RelationType.TO_ONE || if (relDesc.getRelationType() == RelationType.TO_ONE ||
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) { relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) {
for (RelationDescription other : entitiesConfigurations.get(relDesc.getToEntityName()).getRelationsIterator()) { EntityConfiguration entityConfiguration = entitiesConfigurations.get(relDesc.getToEntityName());
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) && if (entityConfiguration != null) {
(entityName.equals(other.getToEntityName()))) { for (RelationDescription other : entityConfiguration.getRelationsIterator()) {
relDesc.setBidirectional(true); if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
other.setBidirectional(true); (entityName.equals(other.getToEntityName()))) {
} relDesc.setBidirectional(true);
} other.setBidirectional(true);
}
}
}
} }
} }
} }
@ -78,6 +84,10 @@ public class EntitiesConfigurations {
return entitiesConfigurations.get(entityName); return entitiesConfigurations.get(entityName);
} }
public EntityConfiguration getNotVersionEntityConfiguration(String entityName) {
return notAuditedEntitiesConfigurations.get(entityName);
}
public String getEntityNameForVersionsEntityName(String versionsEntityName) { public String getEntityNameForVersionsEntityName(String versionsEntityName) {
return entityNamesForVersionsEntityNames.get(versionsEntityName); return entityNamesForVersionsEntityNames.get(versionsEntityName);
} }
@ -98,4 +108,5 @@ public class EntitiesConfigurations {
return null; return null;
} }
} }
} }

View File

@ -82,7 +82,7 @@ public class ToOneIdMapper implements PropertyMapper {
Class<?> entityClass = ReflectionTools.loadClass(referencedEntityName); Class<?> entityClass = ReflectionTools.loadClass(referencedEntityName);
value = versionsReader.getSessionImplementor().getFactory().getEntityPersister(referencedEntityName). value = versionsReader.getSessionImplementor().getFactory().getEntityPersister(referencedEntityName).
createProxy(null, new ToOneDelegateSessionImplementor(versionsReader, entityClass, entityId, revision)); createProxy(null, new ToOneDelegateSessionImplementor(versionsReader, entityClass, entityId, revision, verCfg));
} }
} }

View File

@ -23,29 +23,47 @@
*/ */
package org.hibernate.envers.entities.mapper.relation.lazy; package org.hibernate.envers.entities.mapper.relation.lazy;
import java.io.Serializable;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.EntitiesConfigurations;
import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.reader.AuditReaderImplementor; import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Session;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Tomasz Bech
*/ */
public class ToOneDelegateSessionImplementor extends AbstractDelegateSessionImplementor { public class ToOneDelegateSessionImplementor extends AbstractDelegateSessionImplementor {
private static final long serialVersionUID = 4770438372940785488L;
private final AuditReaderImplementor versionsReader; private final AuditReaderImplementor versionsReader;
private final Class<?> entityClass; private final Class<?> entityClass;
private final Object entityId; private final Object entityId;
private final Number revision; private final Number revision;
private EntityConfiguration notVersionedEntityConfiguration;
public ToOneDelegateSessionImplementor(AuditReaderImplementor versionsReader, public ToOneDelegateSessionImplementor(AuditReaderImplementor versionsReader,
Class<?> entityClass, Object entityId, Number revision) { Class<?> entityClass, Object entityId, Number revision,
AuditConfiguration verCfg) {
super(versionsReader.getSessionImplementor()); super(versionsReader.getSessionImplementor());
this.versionsReader = versionsReader; this.versionsReader = versionsReader;
this.entityClass = entityClass; this.entityClass = entityClass;
this.entityId = entityId; this.entityId = entityId;
this.revision = revision; this.revision = revision;
EntitiesConfigurations entCfg = verCfg.getEntCfg();
notVersionedEntityConfiguration = entCfg.getNotVersionEntityConfiguration(entityClass.getName());
} }
public Object doImmediateLoad(String entityName) throws HibernateException { public Object doImmediateLoad(String entityName) throws HibernateException {
return versionsReader.find(entityClass, entityId, revision); if (notVersionedEntityConfiguration == null) {
return versionsReader.find(entityClass, entityId, revision);
} else {
Session session = versionsReader.getSession();
return session.get(entityClass, (Serializable) entityId);
}
} }
} }

View File

@ -0,0 +1,115 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
*
* 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 javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
/**
* Audited entity with a reference to not audited entity.
* @author Toamsz Bech
*/
@Entity
public class TargetNotAuditedEntity {
@Id
private Integer id;
@Audited
private String data;
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
@ManyToOne(fetch = FetchType.EAGER)
private UnversionedStrTestEntity reference;
public TargetNotAuditedEntity() { }
public TargetNotAuditedEntity(Integer id, String data, UnversionedStrTestEntity reference) {
this.id = id;
this.data = data;
this.reference = reference;
}
public TargetNotAuditedEntity(String data, UnversionedStrTestEntity reference) {
this.data = data;
this.reference = reference;
}
public TargetNotAuditedEntity(Integer id, String data) {
this.id = id;
this.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;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TargetNotAuditedEntity)) return false;
TargetNotAuditedEntity that = (TargetNotAuditedEntity) o;
if (data != null ? !data.equals(that.data) : that.data != null) return false;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
public int hashCode() {
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (data != null ? data.hashCode() : 0);
return result;
}
public String toString() {
return "TargetNotAuditedEntity(id = " + id + ", data = " + data + ")";
}
}

View File

@ -0,0 +1,161 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
*
* 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.integration.manytoone.unidirectional;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
import org.hibernate.envers.test.entities.manytoone.unidirectional.TargetNotAuditedEntity;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* @author Tomasz Bech
*/
public class RelationNotAuditedTarget extends AbstractEntityTest {
private Integer tnae1_id;
private Integer tnae2_id;
private Integer uste1_id;
private Integer uste2_id;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(TargetNotAuditedEntity.class);
cfg.addAnnotatedClass(UnversionedStrTestEntity.class);
}
@BeforeClass(dependsOnMethods = "init")
public void initData() {
EntityManager em = getEntityManager();
UnversionedStrTestEntity uste1 = new UnversionedStrTestEntity("str1");
UnversionedStrTestEntity uste2 = new UnversionedStrTestEntity("str2");
// No revision
em.getTransaction().begin();
em.persist(uste1);
em.persist(uste2);
em.getTransaction().commit();
// Revision 1
em.getTransaction().begin();
uste1 = em.find(UnversionedStrTestEntity.class, uste1.getId());
uste2 = em.find(UnversionedStrTestEntity.class, uste2.getId());
TargetNotAuditedEntity tnae1 = new TargetNotAuditedEntity(1, "tnae1", uste1);
TargetNotAuditedEntity tnae2 = new TargetNotAuditedEntity(2, "tnae2", uste2);
em.persist(tnae1);
em.persist(tnae2);
em.getTransaction().commit();
// Revision 2
em.getTransaction().begin();
tnae1 = em.find(TargetNotAuditedEntity.class, tnae1.getId());
tnae2 = em.find(TargetNotAuditedEntity.class, tnae2.getId());
tnae1.setReference(uste2);
tnae2.setReference(uste1);
em.getTransaction().commit();
// Revision 3
em.getTransaction().begin();
tnae1 = em.find(TargetNotAuditedEntity.class, tnae1.getId());
tnae2 = em.find(TargetNotAuditedEntity.class, tnae2.getId());
//field not changed!!!
tnae1.setReference(uste2);
tnae2.setReference(uste2);
em.getTransaction().commit();
// Revision 4
em.getTransaction().begin();
tnae1 = em.find(TargetNotAuditedEntity.class, tnae1.getId());
tnae2 = em.find(TargetNotAuditedEntity.class, tnae2.getId());
tnae1.setReference(uste1);
tnae2.setReference(uste1);
em.getTransaction().commit();
//
tnae1_id = tnae1.getId();
tnae2_id = tnae2.getId();
uste1_id = uste1.getId();
uste2_id = uste2.getId();
}
@Test
public void testRevisionsCounts() {
List<Number> revisions = getAuditReader().getRevisions(TargetNotAuditedEntity.class, tnae1_id);
assert Arrays.asList(1, 2, 4).equals(revisions);
revisions = getAuditReader().getRevisions(TargetNotAuditedEntity.class, tnae2_id);
assert Arrays.asList(1, 2, 3, 4).equals(revisions);
}
@Test
public void testHistoryOfTnae1_id() {
UnversionedStrTestEntity uste1 = getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
UnversionedStrTestEntity uste2 = getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
TargetNotAuditedEntity rev1 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 1);
TargetNotAuditedEntity rev2 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 2);
TargetNotAuditedEntity rev3 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 3);
TargetNotAuditedEntity rev4 = getAuditReader().find(TargetNotAuditedEntity.class, tnae1_id, 4);
assert rev1.getReference().equals(uste1);
assert rev2.getReference().equals(uste2);
assert rev3.getReference().equals(uste2);
assert rev4.getReference().equals(uste1);
}
@Test
public void testHistoryOfTnae2_id() {
UnversionedStrTestEntity uste1 = getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
UnversionedStrTestEntity uste2 = getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
TargetNotAuditedEntity rev1 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 1);
TargetNotAuditedEntity rev2 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 2);
TargetNotAuditedEntity rev3 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 3);
TargetNotAuditedEntity rev4 = getAuditReader().find(TargetNotAuditedEntity.class, tnae2_id, 4);
assert rev1.getReference().equals(uste2);
assert rev2.getReference().equals(uste1);
assert rev3.getReference().equals(uste2);
assert rev4.getReference().equals(uste1);
}
}