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:
parent
8465009b4b
commit
5d08386293
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -84,7 +84,11 @@ 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);
|
||||||
|
} else {
|
||||||
|
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
|
||||||
|
auditMetaGen.generateFirstPass(pc, auditData, xmlMappingData, false);
|
||||||
xmlMappings.put(pc, xmlMappingData);
|
xmlMappings.put(pc, xmlMappingData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +127,8 @@ public class EntitiesConfigurator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations());
|
return new EntitiesConfigurations(auditMetaGen.getEntitiesConfigurations(),
|
||||||
|
auditMetaGen.getNotAuditedEntitiesConfigurations());
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo
|
// todo
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -56,7 +57,19 @@ public final class ToOneRelationMetadataGenerator {
|
||||||
|
|
||||||
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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -62,7 +65,9 @@ public class EntitiesConfigurations {
|
||||||
// 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 (entityConfiguration != null) {
|
||||||
|
for (RelationDescription other : entityConfiguration.getRelationsIterator()) {
|
||||||
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
|
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
|
||||||
(entityName.equals(other.getToEntityName()))) {
|
(entityName.equals(other.getToEntityName()))) {
|
||||||
relDesc.setBidirectional(true);
|
relDesc.setBidirectional(true);
|
||||||
|
@ -73,11 +78,16 @@ public class EntitiesConfigurations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public EntityConfiguration get(String entityName) {
|
public EntityConfiguration get(String entityName) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
if (notVersionedEntityConfiguration == null) {
|
||||||
return versionsReader.find(entityClass, entityId, revision);
|
return versionsReader.find(entityClass, entityId, revision);
|
||||||
|
} else {
|
||||||
|
Session session = versionsReader.getSession();
|
||||||
|
return session.get(entityClass, (Serializable) entityId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue