Author: adamw
Date: 2009-12-11 02:17:36 -0500 (Fri, 11 Dec 2009)
New Revision: 18203
Added:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java
Removed:
core/branches/envers-hibernate-3.3/src/main/java/org/jboss/
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java
Log:
svn merge -r 18152:18202
https://svn.jboss.org/repos/hibernate/core/trunk/envers .
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -40,6 +40,7 @@
import org.hibernate.envers.entities.mapper.SubclassPropertyMapper;
import org.hibernate.envers.tools.StringTools;
import org.hibernate.envers.tools.Triple;
+import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
@@ -380,7 +381,7 @@
String parentEntityName = null;
EntityConfiguration entityCfg = new EntityConfiguration(entityName, idMapper,
propertyMapper,
parentEntityName);
- notAuditedEntitiesConfigurations.put(pc.getEntityName(), entityCfg);
+ notAuditedEntitiesConfigurations.put(entityName, entityCfg);
return;
}
@@ -513,6 +514,36 @@
throw new MappingException(message);
}
+ /**
+ * Reads the id mapping data of a referenced entity.
+ * @param entityName Name of the entity which is the source of the relation.
+ * @param referencedEntityName Name of the entity which is the target of the
relation.
+ * @param propertyAuditingData Auditing data of the property that is the source of
the relation.
+ * @param allowNotAuditedTarget Are not-audited target entities allowed.
+ * @throws MappingException If a relation from an audited to a non-audited entity is
detected, which is not
+ * mapped using {@link RelationTargetAuditMode#NOT_AUDITED}.
+ * @return The id mapping data of the related entity.
+ */
+ IdMappingData getReferencedIdMappingData(String entityName, String
referencedEntityName,
+ PropertyAuditingData propertyAuditingData,
+ boolean allowNotAuditedTarget) {
+ EntityConfiguration configuration =
getEntitiesConfigurations().get(referencedEntityName);
+ if (configuration == null) {
+ RelationTargetAuditMode relationTargetAuditMode =
propertyAuditingData.getRelationTargetAuditMode();
+ configuration = getNotAuditedEntitiesConfigurations().get(referencedEntityName);
+
+ if (configuration == null || !allowNotAuditedTarget ||
!RelationTargetAuditMode.NOT_AUDITED.equals(relationTargetAuditMode)) {
+ throw new MappingException("An audited relation from " + entityName +
"."
+ + propertyAuditingData.getName() + " to a not audited entity " +
referencedEntityName + "!"
+ + (allowNotAuditedTarget ?
+ " Such mapping is possible, but has to be explicitly
defined using @Audited(targetAuditMode = NOT_AUDITED)." :
+ ""));
+ }
+ }
+
+ return configuration.getIdMappingData();
+ }
+
/**
* Get the notAuditedEntitiesConfigurations property.
*
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/CollectionMetadataGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -155,28 +155,26 @@
}
}
+ private MiddleIdData createMiddleIdData(IdMappingData idMappingData, String prefix,
String entityName) {
+ return new MiddleIdData(mainGenerator.getVerEntCfg(), idMappingData, prefix,
entityName,
+ mainGenerator.getEntitiesConfigurations().containsKey(entityName));
+ }
+
@SuppressWarnings({"unchecked"})
private void addOneToManyAttached() {
String mappedBy = getMappedBy(propertyValue);
- EntityConfiguration referencedEntityConfiguration =
mainGenerator.getEntitiesConfigurations()
- .get(referencedEntityName);
-
- if (referencedEntityConfiguration == null) {
- throwRelationNotAudited(referencedEntityName);
- // Impossible to get here.
- throw new AssertionError();
- }
- IdMappingData referencedIdMapping =
referencedEntityConfiguration.getIdMappingData();
+ IdMappingData referencedIdMapping =
mainGenerator.getReferencedIdMappingData(referencingEntityName,
+ referencedEntityName, propertyAuditingData, false);
IdMappingData referencingIdMapping =
referencingEntityConfiguration.getIdMappingData();
// Generating the id mappers data for the referencing side of the relation.
- MiddleIdData referencingIdData = new MiddleIdData(mainGenerator.getVerEntCfg(),
referencingIdMapping,
+ MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping,
mappedBy + "_", referencingEntityName);
// And for the referenced side. The prefixed mapper won't be used (as this
collection isn't persisted
// in a join table, so the prefix value is arbitrary).
- MiddleIdData referencedIdData = new MiddleIdData(mainGenerator.getVerEntCfg(),
referencedIdMapping,
+ MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping,
null, referencedEntityName);
// Generating the element mapping.
@@ -293,7 +291,7 @@
}
// Storing the id data of the referencing entity: original mapper, prefixed
mapper and entity name.
- MiddleIdData referencingIdData = new MiddleIdData(mainGenerator.getVerEntCfg(),
referencingIdMapping,
+ MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping,
referencingPrefixRelated, referencingEntityName);
// Creating a query generator builder, to which additional id data will be added,
in case this collection
@@ -390,15 +388,10 @@
String prefixRelated = prefix + "_";
String referencedEntityName = getReferencedEntityName(value);
- EntityConfiguration referencedEntityConfiguration =
mainGenerator.getEntitiesConfigurations()
- .get(referencedEntityName);
- if (referencedEntityConfiguration == null) {
- throwRelationNotAudited(referencedEntityName);
- // Impossible to get here.
- throw new AssertionError();
- }
- IdMappingData referencedIdMapping =
referencedEntityConfiguration.getIdMappingData();
+ IdMappingData referencedIdMapping =
mainGenerator.getReferencedIdMappingData(referencingEntityName,
+ referencedEntityName, propertyAuditingData, true);
+
// Adding related-entity (in this case: the referenced entities id) id
mapping to the xml only if the
// relation isn't inverse (so when <code>xmlMapping</code> is
not null).
if (xmlMapping != null) {
@@ -410,7 +403,7 @@
}
// Storing the id data of the referenced entity: original mapper, prefixed
mapper and entity name.
- MiddleIdData referencedIdData = new
MiddleIdData(mainGenerator.getVerEntCfg(), referencedIdMapping,
+ MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping,
prefixRelated, referencedEntityName);
// And adding it to the generator builder.
queryGeneratorBuilder.addRelation(referencedIdData);
@@ -541,9 +534,4 @@
throw new MappingException("Unable to read the mapped by attribute for
" + propertyName + " in "
+ referencingEntityName + "!");
}
-
- private void throwRelationNotAudited(String referencedEntityName) {
- throw new MappingException("An audited relation from " +
referencingEntityName +
- " to a non-audited entity: " + referencedEntityName);
- }
}
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/QueryGeneratorBuilder.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -30,10 +30,8 @@
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
-import org.hibernate.envers.entities.mapper.relation.query.OneEntityQueryGenerator;
-import org.hibernate.envers.entities.mapper.relation.query.RelationQueryGenerator;
-import org.hibernate.envers.entities.mapper.relation.query.ThreeEntityQueryGenerator;
-import org.hibernate.envers.entities.mapper.relation.query.TwoEntityQueryGenerator;
+import org.hibernate.envers.entities.mapper.relation.query.*;
+import org.hibernate.MappingException;
/**
* Builds query generators, for reading collection middle tables, along with any related
entities.
@@ -66,9 +64,19 @@
return new OneEntityQueryGenerator(verEntCfg, auditMiddleEntityName,
referencingIdData,
componentDatas);
} else if (idDatas.size() == 1) {
- return new TwoEntityQueryGenerator(globalCfg, verEntCfg,
auditMiddleEntityName, referencingIdData,
- idDatas.get(0), componentDatas);
+ if (idDatas.get(0).isAudited()) {
+ return new TwoEntityQueryGenerator(globalCfg, verEntCfg,
auditMiddleEntityName, referencingIdData,
+ idDatas.get(0), componentDatas);
+ } else {
+ return new TwoEntityOneAuditedQueryGenerator(verEntCfg,
auditMiddleEntityName, referencingIdData,
+ idDatas.get(0), componentDatas);
+ }
} else if (idDatas.size() == 2) {
+ // All entities must be audited.
+ if (!idDatas.get(0).isAudited() || !idDatas.get(1).isAudited()) {
+ throw new MappingException("Ternary relations using
@Audited(targetAuditMode = NOT_AUDITED) are not supported.");
+ }
+
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg,
auditMiddleEntityName, referencingIdData,
idDatas.get(0), idDatas.get(1), componentDatas);
} else {
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/configuration/metadata/ToOneRelationMetadataGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -24,7 +24,6 @@
package org.hibernate.envers.configuration.metadata;
import org.dom4j.Element;
-import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.entities.EntityConfiguration;
import org.hibernate.envers.entities.IdMappingData;
import org.hibernate.envers.entities.PropertyData;
@@ -55,25 +54,9 @@
CompositeMapperBuilder mapper, String entityName, boolean insertable)
{
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
- EntityConfiguration configuration =
mainGenerator.getEntitiesConfigurations().get(referencedEntityName);
- if (configuration == null) {
- 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 = mainGenerator.getReferencedIdMappingData(entityName,
referencedEntityName,
+ propertyAuditingData, true);
- IdMappingData idMapping = configuration.getIdMappingData();
-
String lastPropertyPrefix = propertyAuditingData.getName() + "_";
// Generating the id mapper for the relation
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/MiddleIdData.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -33,44 +33,51 @@
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleIdData {
- /**
- * Original id mapper of the related entity.
- */
private final IdMapper originalMapper;
- /**
- * Prefixed id mapper (with the names for the id fields that are used in the middle
table) of the related entity.
- */
private final IdMapper prefixedMapper;
- /**
- * Name of the related entity.
- */
private final String entityName;
- /**
- * Versions name of the related entity.
- */
- private final String versionsEntityName;
+ private final String auditEntityName;
public MiddleIdData(AuditEntitiesConfiguration verEntCfg, IdMappingData mappingData,
String prefix,
- String entityName) {
+ String entityName, boolean audited) {
this.originalMapper = mappingData.getIdMapper();
this.prefixedMapper = mappingData.getIdMapper().prefixMappedProperties(prefix);
this.entityName = entityName;
- this.versionsEntityName = verEntCfg.getAuditEntityName(entityName);
+ this.auditEntityName = audited ? verEntCfg.getAuditEntityName(entityName) :
null;
}
+ /**
+ * @return Original id mapper of the related entity.
+ */
public IdMapper getOriginalMapper() {
return originalMapper;
}
+ /**
+ * @return prefixed id mapper (with the names for the id fields that are used in the
middle table) of the related entity.
+ */
public IdMapper getPrefixedMapper() {
return prefixedMapper;
}
+ /**
+ * @return Name of the related entity (regular, not audited).
+ */
public String getEntityName() {
return entityName;
}
- public String getVersionsEntityName() {
- return versionsEntityName;
+ /**
+ * @return Audit name of the related entity.
+ */
+ public String getAuditEntityName() {
+ return auditEntityName;
}
+
+ /**
+ * @return Is the entity, to which this middle id data correspond, audited.
+ */
+ public boolean isAudited() {
+ return auditEntityName != null;
+ }
}
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/initializor/BasicCollectionInitializor.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -66,8 +66,16 @@
@SuppressWarnings({"unchecked"})
protected void addToCollection(T collection, Object collectionRow) {
Object elementData = ((List)
collectionRow).get(elementComponentData.getComponentIndex());
- Object element =
elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
- (Map<String, Object>) elementData, null, revision);
+
+ // If the target entity is not audited, the elements may be the entities already,
so we have to check
+ // if they are maps or not.
+ Object element;
+ if (elementData instanceof Map) {
+ element =
elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
+ (Map<String, Object>) elementData, null, revision);
+ } else {
+ element = elementData;
+ }
collection.add(element);
}
}
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/QueryGeneratorTools.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -37,7 +37,7 @@
MiddleIdData idData, String
revisionPropertyPath, String originalIdPropertyName,
String alias1, String alias2) {
// SELECT max(e.revision) FROM versionsReferencedEntity e2
- QueryBuilder maxERevQb = qb.newSubQueryBuilder(idData.getVersionsEntityName(),
alias2);
+ QueryBuilder maxERevQb = qb.newSubQueryBuilder(idData.getAuditEntityName(),
alias2);
maxERevQb.addProjection("max", revisionPropertyPath, false);
// WHERE
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/RelationQueryGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -28,6 +28,8 @@
import org.hibernate.Query;
/**
+ * TODO: cleanup implementations and extract common code
+ *
* Implementations of this interface provide a method to generate queries on a relation
table (a table used
* for mapping relations). The query can select, apart from selecting the content of the
relation table, also data of
* other "related" entities.
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/ThreeEntityQueryGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -85,8 +85,8 @@
// SELECT new list(ee) FROM middleEntity ee
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
- qb.addFrom(referencedIdData.getVersionsEntityName(), "e");
- qb.addFrom(indexIdData.getVersionsEntityName(), "f");
+ qb.addFrom(referencedIdData.getAuditEntityName(), "e");
+ qb.addFrom(indexIdData.getAuditEntityName(), "f");
qb.addProjection("new list", "ee, e, f", false, false);
// WHERE
Parameters rootParameters = qb.getRootParameters();
Copied:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java
(from rev 18202,
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java)
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java
(rev 0)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityOneAuditedQueryGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -0,0 +1,108 @@
+/*
+ * 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.entities.mapper.relation.query;
+
+import java.util.Collections;
+
+import org.hibernate.envers.RevisionType;
+import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
+import org.hibernate.envers.entities.mapper.id.QueryParameterData;
+import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
+import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
+import org.hibernate.envers.reader.AuditReaderImplementor;
+import org.hibernate.envers.tools.query.Parameters;
+import org.hibernate.envers.tools.query.QueryBuilder;
+
+import org.hibernate.Query;
+
+/**
+ * Selects data from a relation middle-table and a related non-audited entity.
+ * @author Adam Warski (adam at warski dot org)
+ */
+public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGenerator {
+ private final String queryString;
+ private final MiddleIdData referencingIdData;
+
+ public TwoEntityOneAuditedQueryGenerator(
+ AuditEntitiesConfiguration verEntCfg,
+ String versionsMiddleEntityName,
+ MiddleIdData referencingIdData,
+ MiddleIdData referencedIdData,
+ MiddleComponentData... componentDatas) {
+ this.referencingIdData = referencingIdData;
+
+ /*
+ * The query that we need to create:
+ * SELECT new list(ee, e) FROM referencedEntity e, middleEntity ee
+ * WHERE
+ * (entities referenced by the middle table; id_ref_ed = id of the referenced
entity)
+ * ee.id_ref_ed = e.id_ref_ed AND
+ * (only entities referenced by the association; id_ref_ing = id of the
referencing entity)
+ * ee.id_ref_ing = :id_ref_ing AND
+ * (the association at revision :revision)
+ * ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
+ * WHERE ee2.revision <= :revision AND ee2.originalId.* =
ee.originalId.*) AND
+ * (only non-deleted entities and associations)
+ * ee.revision_type != DEL
+ */
+ String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
+ String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
+
+ String eeOriginalIdPropertyPath = "ee." + originalIdPropertyName;
+
+ // SELECT new list(ee) FROM middleEntity ee
+ QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
+ qb.addFrom(referencedIdData.getEntityName(), "e");
+ qb.addProjection("new list", "ee, e", false, false);
+ // WHERE
+ Parameters rootParameters = qb.getRootParameters();
+ // ee.id_ref_ed = e.id_ref_ed
+ referencedIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters,
eeOriginalIdPropertyPath,
+ referencedIdData.getOriginalMapper(), "e");
+ // ee.originalId.id_ref_ing = :id_ref_ing
+ referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters,
originalIdPropertyName, true);
+
+ // ee.revision = (SELECT max(...) ...)
+ QueryGeneratorTools.addAssociationAtRevision(qb, rootParameters,
referencingIdData, versionsMiddleEntityName,
+ eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName,
componentDatas);
+
+ // ee.revision_type != DEL
+ rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(),
"!=", "delrevisiontype");
+
+ StringBuilder sb = new StringBuilder();
+ qb.build(sb, Collections.<String, Object>emptyMap());
+ queryString = sb.toString();
+ }
+
+ public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey,
Number revision) {
+ Query query = versionsReader.getSession().createQuery(queryString);
+ query.setParameter("revision", revision);
+ query.setParameter("delrevisiontype", RevisionType.DEL);
+ for (QueryParameterData paramData:
referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
+ paramData.setParameterValue(query);
+ }
+
+ return query;
+ }
+}
\ No newline at end of file
Modified:
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java
===================================================================
---
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java 2009-12-10
21:47:01 UTC (rev 18202)
+++
core/branches/envers-hibernate-3.3/src/main/java/org/hibernate/envers/entities/mapper/relation/query/TwoEntityQueryGenerator.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -78,7 +78,7 @@
// SELECT new list(ee) FROM middleEntity ee
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
- qb.addFrom(referencedIdData.getVersionsEntityName(), "e");
+ qb.addFrom(referencedIdData.getAuditEntityName(), "e");
qb.addProjection("new list", "ee, e", false, false);
// WHERE
Parameters rootParameters = qb.getRootParameters();
Copied:
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java
(from rev 18202,
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java)
===================================================================
---
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java
(rev 0)
+++
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/entities/manytomany/unidirectional/M2MTargetNotAuditedEntity.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -0,0 +1,116 @@
+/*
+ * 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.manytomany.unidirectional;
+
+import javax.persistence.*;
+
+import org.hibernate.envers.Audited;
+import org.hibernate.envers.RelationTargetAuditMode;
+import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
+
+import java.util.List;
+
+/**
+ * Audited entity with a many-to-many-reference to not audited entity.
+ * @author Toamsz Bech
+ * @author Adam Warski
+ */
+@Entity
+public class M2MTargetNotAuditedEntity {
+ @Id
+ private Integer id;
+
+ @Audited
+ private String data;
+
+ @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
+ @ManyToMany(fetch = FetchType.LAZY)
+ private List<UnversionedStrTestEntity> references;
+
+ public M2MTargetNotAuditedEntity() { }
+
+ public M2MTargetNotAuditedEntity(Integer id, String data,
List<UnversionedStrTestEntity> references) {
+ this.id = id;
+ this.data = data;
+ this.references = references;
+ }
+
+ public M2MTargetNotAuditedEntity(String data, List<UnversionedStrTestEntity>
references) {
+ this.data = data;
+ this.references = references;
+ }
+
+ public M2MTargetNotAuditedEntity(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 List<UnversionedStrTestEntity> getReferences() {
+ return references;
+ }
+
+ public void setReferences(List<UnversionedStrTestEntity> references) {
+ this.references = references;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof M2MTargetNotAuditedEntity)) return false;
+
+ M2MTargetNotAuditedEntity that = (M2MTargetNotAuditedEntity) o;
+
+ if (data != null ? !data.equals(that.getData()) : that.getData() != null) return
false;
+ //noinspection RedundantIfStatement
+ if (id != null ? !id.equals(that.getId()) : that.getId() != 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 "M2MTargetNotAuditedEntity(id = " + id + ", data = " + data
+ ")";
+ }
+}
Copied:
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java
(from rev 18202,
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java)
===================================================================
---
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java
(rev 0)
+++
core/branches/envers-hibernate-3.3/src/test/java/org/hibernate/envers/test/integration/manytomany/unidirectional/M2MRelationNotAuditedTarget.java 2009-12-11
07:17:36 UTC (rev 18203)
@@ -0,0 +1,167 @@
+/*
+ * 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.manytomany.unidirectional;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.ejb.Ejb3Configuration;
+import org.hibernate.envers.test.AbstractEntityTest;
+import static org.hibernate.envers.test.tools.TestTools.*;
+import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
+import
org.hibernate.envers.test.entities.manytomany.unidirectional.M2MTargetNotAuditedEntity;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * A test for auditing a many-to-many relation where the target entity is not audited.
+ * @author Adam Warski
+ */
+public class M2MRelationNotAuditedTarget 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(M2MTargetNotAuditedEntity.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());
+
+ M2MTargetNotAuditedEntity tnae1 = new M2MTargetNotAuditedEntity(1, "tnae1",
new ArrayList<UnversionedStrTestEntity>());
+ M2MTargetNotAuditedEntity tnae2 = new M2MTargetNotAuditedEntity(2, "tnae2",
new ArrayList<UnversionedStrTestEntity>());
+ tnae2.getReferences().add(uste1);
+ tnae2.getReferences().add(uste2);
+ em.persist(tnae1);
+ em.persist(tnae2);
+
+ em.getTransaction().commit();
+
+ // Revision 2
+ em.getTransaction().begin();
+
+ tnae1 = em.find(M2MTargetNotAuditedEntity.class, tnae1.getId());
+ tnae2 = em.find(M2MTargetNotAuditedEntity.class, tnae2.getId());
+
+ tnae1.getReferences().add(uste1);
+ tnae2.getReferences().remove(uste1);
+
+ em.getTransaction().commit();
+
+ // Revision 3
+ em.getTransaction().begin();
+
+ tnae1 = em.find(M2MTargetNotAuditedEntity.class, tnae1.getId());
+ tnae2 = em.find(M2MTargetNotAuditedEntity.class, tnae2.getId());
+
+ //field not changed!!!
+ tnae1.getReferences().add(uste1);
+ tnae2.getReferences().remove(uste2);
+
+ em.getTransaction().commit();
+
+ // Revision 4
+ em.getTransaction().begin();
+
+ tnae1 = em.find(M2MTargetNotAuditedEntity.class, tnae1.getId());
+ tnae2 = em.find(M2MTargetNotAuditedEntity.class, tnae2.getId());
+
+ tnae1.getReferences().add(uste2);
+ tnae2.getReferences().add(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(M2MTargetNotAuditedEntity.class, tnae1_id);
+ assert Arrays.asList(1, 2, 4).equals(revisions);
+ revisions = getAuditReader().getRevisions(M2MTargetNotAuditedEntity.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);
+
+ M2MTargetNotAuditedEntity rev1 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae1_id, 1);
+ M2MTargetNotAuditedEntity rev2 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae1_id, 2);
+ M2MTargetNotAuditedEntity rev3 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae1_id, 3);
+ M2MTargetNotAuditedEntity rev4 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae1_id, 4);
+
+ checkList(rev1.getReferences());
+ checkList(rev2.getReferences(), uste1);
+ checkList(rev3.getReferences(), uste1);
+ checkList(rev4.getReferences(), uste1, uste2);
+ }
+
+ @Test
+ public void testHistoryOfTnae2_id() {
+ UnversionedStrTestEntity uste1 =
getEntityManager().find(UnversionedStrTestEntity.class, uste1_id);
+ UnversionedStrTestEntity uste2 =
getEntityManager().find(UnversionedStrTestEntity.class, uste2_id);
+
+ M2MTargetNotAuditedEntity rev1 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae2_id, 1);
+ M2MTargetNotAuditedEntity rev2 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae2_id, 2);
+ M2MTargetNotAuditedEntity rev3 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae2_id, 3);
+ M2MTargetNotAuditedEntity rev4 = getAuditReader().find(M2MTargetNotAuditedEntity.class,
tnae2_id, 4);
+
+ checkList(rev1.getReferences(), uste1, uste2);
+ checkList(rev2.getReferences(), uste2);
+ checkList(rev3.getReferences());
+ checkList(rev4.getReferences(), uste1);
+ }
+}