HHH-5372:
applying patch by Matthew B. Jones and Erik-Berndt Scheper Using the revend column in queries that retrieve historical data, which is much faster then doing the subselect. git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20315 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
28dae5c9f3
commit
9c919ee9dc
|
@ -83,7 +83,7 @@ public class AuditConfiguration {
|
|||
public AuditConfiguration(Configuration cfg) {
|
||||
Properties properties = cfg.getProperties();
|
||||
|
||||
ReflectionManager reflectionManager = ((AnnotationConfiguration) cfg).getReflectionManager();
|
||||
ReflectionManager reflectionManager = cfg.getReflectionManager();
|
||||
RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration();
|
||||
RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure(cfg, reflectionManager);
|
||||
auditEntCfg = new AuditEntitiesConfiguration(properties, revInfoCfgResult.getRevisionInfoEntityName());
|
||||
|
@ -99,7 +99,7 @@ public class AuditConfiguration {
|
|||
|
||||
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
|
||||
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
|
||||
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg,
|
||||
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg, auditStrategy,
|
||||
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping());
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.envers.configuration.metadata.reader.ClassAuditingData;
|
|||
import org.hibernate.envers.configuration.metadata.AuditMetadataGenerator;
|
||||
import org.hibernate.envers.configuration.metadata.AuditEntityNameRegister;
|
||||
import org.hibernate.envers.entities.EntitiesConfigurations;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.envers.tools.StringTools;
|
||||
import org.hibernate.envers.tools.graph.GraphTopologicalSort;
|
||||
|
||||
|
@ -57,6 +58,7 @@ import org.hibernate.mapping.PersistentClass;
|
|||
public class EntitiesConfigurator {
|
||||
public EntitiesConfigurations configure(Configuration cfg, ReflectionManager reflectionManager,
|
||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
|
||||
// Creating a name register to capture all audit entity names created.
|
||||
AuditEntityNameRegister auditEntityNameRegister = new AuditEntityNameRegister();
|
||||
|
@ -83,7 +85,7 @@ public class EntitiesConfigurator {
|
|||
// Now that all information is read we can update the calculated fields.
|
||||
classesAuditingData.updateCalculatedFields();
|
||||
|
||||
AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(cfg, globalCfg, verEntCfg,
|
||||
AuditMetadataGenerator auditMetaGen = new AuditMetadataGenerator(cfg, globalCfg, verEntCfg, auditStrategy,
|
||||
revisionInfoRelationMapping, auditEntityNameRegister);
|
||||
|
||||
// First pass
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
|
||||
import org.dom4j.Element;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.metadata.reader.ClassAuditingData;
|
||||
|
@ -38,6 +39,7 @@ import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
|||
import org.hibernate.envers.entities.mapper.ExtendedPropertyMapper;
|
||||
import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
|
||||
import org.hibernate.envers.entities.mapper.SubclassPropertyMapper;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
|
||||
import org.hibernate.envers.tools.StringTools;
|
||||
import org.hibernate.envers.tools.Triple;
|
||||
|
@ -63,6 +65,7 @@ public final class AuditMetadataGenerator {
|
|||
private final Configuration cfg;
|
||||
private final GlobalConfiguration globalCfg;
|
||||
private final AuditEntitiesConfiguration verEntCfg;
|
||||
private final AuditStrategy auditStrategy;
|
||||
private final Element revisionInfoRelationMapping;
|
||||
|
||||
/*
|
||||
|
@ -86,11 +89,13 @@ public final class AuditMetadataGenerator {
|
|||
|
||||
public AuditMetadataGenerator(Configuration cfg, GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
Element revisionInfoRelationMapping,
|
||||
AuditEntityNameRegister auditEntityNameRegister) {
|
||||
this.cfg = cfg;
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.revisionInfoRelationMapping = revisionInfoRelationMapping;
|
||||
|
||||
this.basicMetadataGenerator = new BasicMetadataGenerator();
|
||||
|
@ -490,6 +495,10 @@ public final class AuditMetadataGenerator {
|
|||
return verEntCfg;
|
||||
}
|
||||
|
||||
AuditStrategy getAuditStrategy() {
|
||||
return auditStrategy;
|
||||
}
|
||||
|
||||
AuditEntityNameRegister getAuditEntityNameRegister() {
|
||||
return auditEntityNameRegister;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,11 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
import org.dom4j.Element;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.envers.ModificationStore;
|
||||
import org.hibernate.envers.RelationTargetAuditMode;
|
||||
import org.hibernate.envers.configuration.metadata.reader.PropertyAuditingData;
|
||||
|
@ -45,8 +47,19 @@ import org.hibernate.envers.entities.mapper.CompositeMapperBuilder;
|
|||
import org.hibernate.envers.entities.mapper.PropertyMapper;
|
||||
import org.hibernate.envers.entities.mapper.SinglePropertyMapper;
|
||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.*;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.*;
|
||||
import org.hibernate.envers.entities.mapper.relation.BasicCollectionMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.CommonCollectionMapperData;
|
||||
import org.hibernate.envers.entities.mapper.relation.ListCollectionMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.MapCollectionMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.entities.mapper.relation.ToOneIdMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.MiddleDummyComponentMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyIdComponentMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.MiddleMapKeyPropertyComponentMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.MiddleRelatedComponentMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.MiddleSimpleComponentMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.component.MiddleStraightComponentMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.lazy.proxy.ListProxy;
|
||||
import org.hibernate.envers.entities.mapper.relation.lazy.proxy.MapProxy;
|
||||
import org.hibernate.envers.entities.mapper.relation.lazy.proxy.SetProxy;
|
||||
|
@ -54,11 +67,9 @@ import org.hibernate.envers.entities.mapper.relation.lazy.proxy.SortedMapProxy;
|
|||
import org.hibernate.envers.entities.mapper.relation.lazy.proxy.SortedSetProxy;
|
||||
import org.hibernate.envers.entities.mapper.relation.query.OneAuditEntityQueryGenerator;
|
||||
import org.hibernate.envers.entities.mapper.relation.query.RelationQueryGenerator;
|
||||
import org.hibernate.envers.tools.MappingTools;
|
||||
import org.hibernate.envers.tools.StringTools;
|
||||
import org.hibernate.envers.tools.Tools;
|
||||
import org.hibernate.envers.tools.MappingTools;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.IndexedCollection;
|
||||
import org.hibernate.mapping.OneToMany;
|
||||
|
@ -184,8 +195,8 @@ public final class CollectionMetadataGenerator {
|
|||
|
||||
// Generating the query generator - it should read directly from the related entity.
|
||||
RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(mainGenerator.getGlobalCfg(),
|
||||
mainGenerator.getVerEntCfg(), referencingIdData, referencedEntityName,
|
||||
referencedIdMapping.getIdMapper());
|
||||
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(),
|
||||
referencingIdData, referencedEntityName, referencedIdData);
|
||||
|
||||
// Creating common mapper data.
|
||||
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
|
||||
|
@ -332,8 +343,9 @@ public final class CollectionMetadataGenerator {
|
|||
// Creating a query generator builder, to which additional id data will be added, in case this collection
|
||||
// references some entities (either from the element or index). At the end, this will be used to build
|
||||
// a query generator to read the raw data collection from the middle table.
|
||||
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
|
||||
mainGenerator.getVerEntCfg(), referencingIdData, auditMiddleEntityName);
|
||||
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
|
||||
mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData,
|
||||
auditMiddleEntityName);
|
||||
|
||||
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
|
||||
if (middleEntityXml != null) {
|
||||
|
|
|
@ -26,12 +26,17 @@ package org.hibernate.envers.configuration.metadata;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.entities.mapper.relation.query.*;
|
||||
import org.hibernate.MappingException;
|
||||
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.TwoEntityOneAuditedQueryGenerator;
|
||||
import org.hibernate.envers.entities.mapper.relation.query.TwoEntityQueryGenerator;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
|
||||
/**
|
||||
* Builds query generators, for reading collection middle tables, along with any related entities.
|
||||
|
@ -41,14 +46,17 @@ import org.hibernate.MappingException;
|
|||
public final class QueryGeneratorBuilder {
|
||||
private final GlobalConfiguration globalCfg;
|
||||
private final AuditEntitiesConfiguration verEntCfg;
|
||||
private final AuditStrategy auditStrategy;
|
||||
private final MiddleIdData referencingIdData;
|
||||
private final String auditMiddleEntityName;
|
||||
private final List<MiddleIdData> idDatas;
|
||||
|
||||
QueryGeneratorBuilder(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
MiddleIdData referencingIdData, String auditMiddleEntityName) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.referencingIdData = referencingIdData;
|
||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||
|
||||
|
@ -61,14 +69,14 @@ public final class QueryGeneratorBuilder {
|
|||
|
||||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||
if (idDatas.size() == 0) {
|
||||
return new OneEntityQueryGenerator(verEntCfg, auditMiddleEntityName, referencingIdData,
|
||||
return new OneEntityQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
componentDatas);
|
||||
} else if (idDatas.size() == 1) {
|
||||
if (idDatas.get(0).isAudited()) {
|
||||
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditMiddleEntityName, referencingIdData,
|
||||
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), componentDatas);
|
||||
} else {
|
||||
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditMiddleEntityName, referencingIdData,
|
||||
return new TwoEntityOneAuditedQueryGenerator(verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), componentDatas);
|
||||
}
|
||||
} else if (idDatas.size() == 2) {
|
||||
|
@ -77,7 +85,7 @@ public final class QueryGeneratorBuilder {
|
|||
throw new MappingException("Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported.");
|
||||
}
|
||||
|
||||
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditMiddleEntityName, referencingIdData,
|
||||
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get(0), idDatas.get(1), componentDatas);
|
||||
} else {
|
||||
throw new IllegalStateException("Illegal number of related entities.");
|
||||
|
|
|
@ -25,18 +25,17 @@ package org.hibernate.envers.entities.mapper.relation.query;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
import org.hibernate.Query;
|
||||
|
||||
/**
|
||||
* Selects data from an audit entity.
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -46,8 +45,9 @@ public final class OneAuditEntityQueryGenerator implements RelationQueryGenerato
|
|||
private final MiddleIdData referencingIdData;
|
||||
|
||||
public OneAuditEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
MiddleIdData referencingIdData, String referencedEntityName,
|
||||
IdMapper referencedIdMapper) {
|
||||
AuditStrategy auditStrategy,
|
||||
MiddleIdData referencingIdData,
|
||||
String referencedEntityName, MiddleIdData referencedIdData) {
|
||||
this.referencingIdData = referencingIdData;
|
||||
|
||||
/*
|
||||
|
@ -57,8 +57,14 @@ public final class OneAuditEntityQueryGenerator implements RelationQueryGenerato
|
|||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||
* e.id_ref_ing = :id_ref_ing AND
|
||||
* (selecting e entities at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id) AND
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
* (only non-deleted entities)
|
||||
* e.revision_type != DEL
|
||||
*/
|
||||
|
@ -75,19 +81,11 @@ public final class OneAuditEntityQueryGenerator implements RelationQueryGenerato
|
|||
// e.id_ref_ed = :id_ref_ed
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, null, true);
|
||||
|
||||
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
||||
QueryBuilder maxERevQb = qb.newSubQueryBuilder(versionsReferencedEntityName, "e2");
|
||||
maxERevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
||||
// e2.revision <= :revision
|
||||
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
|
||||
// e2.id = e.id
|
||||
referencedIdMapper.addIdsEqualToQuery(maxERevQbParameters,
|
||||
"e." + originalIdPropertyName, "e2." + originalIdPropertyName);
|
||||
|
||||
// e.revision = (SELECT max(...) ...)
|
||||
rootParameters.addWhere(revisionPropertyPath, false, globalCfg.getCorrelatedSubqueryOperator(), maxERevQb);
|
||||
// (selecting e entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData,
|
||||
revisionPropertyPath, originalIdPropertyName, "e", "e2");
|
||||
|
||||
// e.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
|
||||
|
|
|
@ -25,17 +25,17 @@ package org.hibernate.envers.entities.mapper.relation.query;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.Query;
|
||||
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.strategy.AuditStrategy;
|
||||
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 only.
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -45,6 +45,7 @@ public final class OneEntityQueryGenerator implements RelationQueryGenerator {
|
|||
private final MiddleIdData referencingIdData;
|
||||
|
||||
public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleComponentData... componentDatas) {
|
||||
|
@ -55,9 +56,17 @@ public final class OneEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* SELECT new list(ee) FROM middleEntity ee WHERE
|
||||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||
* ee.originalId.id_ref_ing = :id_ref_ing AND
|
||||
*
|
||||
* (the association at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
*
|
||||
* (only non-deleted entities and associations)
|
||||
* ee.revision_type != DEL
|
||||
*/
|
||||
|
@ -71,22 +80,15 @@ public final class OneEntityQueryGenerator implements RelationQueryGenerator {
|
|||
Parameters rootParameters = qb.getRootParameters();
|
||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
||||
// SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
QueryBuilder maxRevQb = qb.newSubQueryBuilder(versionsMiddleEntityName, "ee2");
|
||||
maxRevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxRevQbParameters = maxRevQb.getRootParameters();
|
||||
// ee2.revision <= :revision
|
||||
maxRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
|
||||
// ee2.originalId.* = ee.originalId.*
|
||||
|
||||
String eeOriginalIdPropertyPath = "ee." + originalIdPropertyName;
|
||||
String ee2OriginalIdPropertyPath = "ee2." + originalIdPropertyName;
|
||||
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
for (MiddleComponentData componentData : componentDatas) {
|
||||
componentData.getComponentMapper().addMiddleEqualToQuery(maxRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
}
|
||||
// ee.revision = (SELECT max(...) ...)
|
||||
rootParameters.addWhere(revisionPropertyPath, "=", maxRevQb);
|
||||
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
|
||||
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* 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 org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
*/
|
||||
public class QueryGeneratorTools {
|
||||
public static void addEntityAtRevision(GlobalConfiguration globalCfg, QueryBuilder qb, Parameters rootParameters,
|
||||
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
|
||||
String alias1, String alias2) {
|
||||
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
||||
QueryBuilder maxERevQb = qb.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
|
||||
maxERevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
||||
// e2.revision <= :revision
|
||||
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
|
||||
// e2.id_ref_ed = e.id_ref_ed
|
||||
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
|
||||
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
|
||||
|
||||
// e.revision = (SELECT max(...) ...)
|
||||
rootParameters.addWhere("e." + revisionPropertyPath, false, globalCfg.getCorrelatedSubqueryOperator(), maxERevQb);
|
||||
}
|
||||
|
||||
public static void addAssociationAtRevision(QueryBuilder qb, Parameters rootParameters,
|
||||
MiddleIdData referencingIdData, String versionsMiddleEntityName,
|
||||
String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
// SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
QueryBuilder maxEeRevQb = qb.newSubQueryBuilder(versionsMiddleEntityName, "ee2");
|
||||
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
|
||||
// ee2.revision <= :revision
|
||||
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
|
||||
// ee2.originalId.* = ee.originalId.*
|
||||
String ee2OriginalIdPropertyPath = "ee2." + originalIdPropertyName;
|
||||
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
for (MiddleComponentData componentData : componentDatas) {
|
||||
componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
}
|
||||
|
||||
// ee.revision = (SELECT max(...) ...)
|
||||
rootParameters.addWhere(revisionPropertyPath, "=", maxEeRevQb);
|
||||
}
|
||||
}
|
|
@ -25,18 +25,18 @@ package org.hibernate.envers.entities.mapper.relation.query;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
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.strategy.AuditStrategy;
|
||||
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 two related versions entity.
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -47,6 +47,7 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
|
||||
public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
|
@ -65,14 +66,48 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||
* ee.id_ref_ing = :id_ref_ing AND
|
||||
* (selecting e entities at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id_ref_ed = e.id_ref_ed) AND
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
*
|
||||
* (selecting f entities at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* f.revision = (SELECT max(f2.revision) FROM versionsIndexEntity f2
|
||||
* WHERE f2.revision <= :revision AND f2.id_ref_ed = f.id_ref_ed) AND
|
||||
* WHERE f2.revision <= :revision AND f2.id_ref_ed = f.id_ref_ed)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* f.revision <= :revision and (f.endRevision > :revision or f.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
*
|
||||
* (the association at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
and (
|
||||
strtestent1_.REVEND>?
|
||||
or strtestent1_.REVEND is null
|
||||
)
|
||||
and (
|
||||
strtestent1_.REVEND>?
|
||||
or strtestent1_.REVEND is null
|
||||
)
|
||||
and (
|
||||
ternarymap0_.REVEND>?
|
||||
or ternarymap0_.REVEND is null
|
||||
)
|
||||
*
|
||||
*
|
||||
*
|
||||
* (only non-deleted entities and associations)
|
||||
* ee.revision_type != DEL AND
|
||||
* e.revision_type != DEL AND
|
||||
|
@ -80,7 +115,6 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
*/
|
||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
|
||||
String eeOriginalIdPropertyPath = "ee." + originalIdPropertyName;
|
||||
|
||||
// SELECT new list(ee) FROM middleEntity ee
|
||||
|
@ -99,17 +133,23 @@ public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
|
|||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
||||
|
||||
// e.revision = (SELECT max(...) ...)
|
||||
QueryGeneratorTools.addEntityAtRevision(globalCfg, qb, rootParameters, referencedIdData, revisionPropertyPath,
|
||||
originalIdPropertyName, "e", "e2");
|
||||
// (selecting e entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, "e." + revisionPropertyPath,
|
||||
"e." + verEntCfg.getRevisionEndFieldName(), false,
|
||||
referencedIdData, revisionPropertyPath, originalIdPropertyName, "e", "e2");
|
||||
|
||||
// f.revision = (SELECT max(...) ...)
|
||||
QueryGeneratorTools.addEntityAtRevision(globalCfg, qb, rootParameters, indexIdData, revisionPropertyPath,
|
||||
originalIdPropertyName, "f", "f2");
|
||||
// (selecting f entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, "e." + revisionPropertyPath,
|
||||
"e." + verEntCfg.getRevisionEndFieldName(), false,
|
||||
referencedIdData, revisionPropertyPath, originalIdPropertyName, "f", "f2");
|
||||
|
||||
// ee.revision = (SELECT max(...) ...)
|
||||
QueryGeneratorTools.addAssociationAtRevision(qb, rootParameters, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
|
||||
|
|
|
@ -26,11 +26,14 @@ package org.hibernate.envers.entities.mapper.relation.query;
|
|||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
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.strategy.AuditStrategy;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
|
@ -44,8 +47,7 @@ public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGen
|
|||
private final String queryString;
|
||||
private final MiddleIdData referencingIdData;
|
||||
|
||||
public TwoEntityOneAuditedQueryGenerator(
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
|
@ -60,9 +62,17 @@ public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGen
|
|||
* 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)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
*
|
||||
* (only non-deleted entities and associations)
|
||||
* ee.revision_type != DEL
|
||||
*/
|
||||
|
@ -83,9 +93,11 @@ public final class TwoEntityOneAuditedQueryGenerator implements RelationQueryGen
|
|||
// 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);
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
|
||||
|
|
|
@ -25,18 +25,18 @@ package org.hibernate.envers.entities.mapper.relation.query;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
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.strategy.AuditStrategy;
|
||||
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 versions entity.
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -47,6 +47,7 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
|
||||
public TwoEntityQueryGenerator(GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
|
@ -61,12 +62,25 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
* 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
|
||||
*
|
||||
* (selecting e entities at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id_ref_ed = e.id_ref_ed) AND
|
||||
* (the association at revision :revision)
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
*
|
||||
* (the association at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
|
||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||
*
|
||||
* (only non-deleted entities and associations)
|
||||
* ee.revision_type != DEL AND
|
||||
* e.revision_type != DEL
|
||||
|
@ -88,13 +102,17 @@ public final class TwoEntityQueryGenerator implements RelationQueryGenerator {
|
|||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
||||
|
||||
// e.revision = (SELECT max(...) ...)
|
||||
QueryGeneratorTools.addEntityAtRevision(globalCfg, qb, rootParameters, referencedIdData, revisionPropertyPath,
|
||||
originalIdPropertyName, "e", "e2");
|
||||
// (selecting e entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, "e." + revisionPropertyPath,
|
||||
"e." + verEntCfg.getRevisionEndFieldName(), false,
|
||||
referencedIdData, revisionPropertyPath, originalIdPropertyName, "e", "e2");
|
||||
|
||||
// ee.revision = (SELECT max(...) ...)
|
||||
QueryGeneratorTools.addAssociationAtRevision(qb, rootParameters, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
|
||||
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
|
||||
|
|
|
@ -86,10 +86,14 @@ public abstract class AbstractAuditQuery implements AuditQuery {
|
|||
qb = new QueryBuilder(versionsEntityName, "e");
|
||||
}
|
||||
|
||||
protected List buildAndExecuteQuery() {
|
||||
protected Query buildQuery() {
|
||||
Query query = qb.toQuery(versionsReader.getSession());
|
||||
|
||||
setQueryProperties(query);
|
||||
return query;
|
||||
}
|
||||
|
||||
protected List buildAndExecuteQuery() {
|
||||
Query query = buildQuery();
|
||||
|
||||
return query.list();
|
||||
}
|
||||
|
|
|
@ -24,14 +24,16 @@
|
|||
package org.hibernate.envers.query.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.query.criteria.AuditCriterion;
|
||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
|
@ -56,39 +58,50 @@ public class EntitiesAtRevisionQuery extends AbstractAuditQuery {
|
|||
@SuppressWarnings({"unchecked"})
|
||||
public List list() {
|
||||
/*
|
||||
The query that should be executed in the versions table:
|
||||
SELECT e FROM ent_ver e WHERE
|
||||
(all specified conditions, transformed, on the "e" entity) AND
|
||||
e.revision_type != DEL AND
|
||||
e.revision = (SELECT max(e2.revision) FROM ent_ver e2 WHERE
|
||||
e2.revision <= :revision AND e2.originalId.id = e.originalId.id)
|
||||
* The query that we need to create:
|
||||
* SELECT new list(e) FROM versionsReferencedEntity e
|
||||
* WHERE
|
||||
* (all specified conditions, transformed, on the "e" entity) AND
|
||||
* (selecting e entities at revision :revision)
|
||||
* --> for DefaultAuditStrategy:
|
||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||
*
|
||||
* --> for ValidTimeAuditStrategy:
|
||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||
*
|
||||
* AND
|
||||
* (only non-deleted entities)
|
||||
* e.revision_type != DEL
|
||||
*/
|
||||
|
||||
QueryBuilder maxRevQb = qb.newSubQueryBuilder(versionsEntityName, "e2");
|
||||
|
||||
AuditEntitiesConfiguration verEntCfg = verCfg.getAuditEntCfg();
|
||||
|
||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
|
||||
// SELECT max(e2.revision)
|
||||
maxRevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// e2.revision <= :revision
|
||||
maxRevQb.getRootParameters().addWhereWithParam(revisionPropertyPath, "<=", revision);
|
||||
// e2.id = e.id
|
||||
verCfg.getEntCfg().get(entityName).getIdMapper().addIdsEqualToQuery(maxRevQb.getRootParameters(),
|
||||
"e." + originalIdPropertyName, "e2." + originalIdPropertyName);
|
||||
MiddleIdData referencedIdData = new MiddleIdData(verEntCfg, verCfg.getEntCfg().get(entityName).getIdMappingData(),
|
||||
null, entityName, verCfg.getEntCfg().isVersioned(entityName));
|
||||
|
||||
// (selecting e entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
verCfg.getAuditStrategy().addEntityAtRevisionRestriction(verCfg.getGlobalCfg(), qb, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData,
|
||||
revisionPropertyPath, originalIdPropertyName, "e", "e2");
|
||||
|
||||
// e.revision_type != DEL
|
||||
qb.getRootParameters().addWhereWithParam(verEntCfg.getRevisionTypePropName(), "<>", RevisionType.DEL);
|
||||
|
||||
// e.revision_type != DEL AND
|
||||
qb.getRootParameters().addWhereWithParam(verEntCfg.getRevisionTypePropName(), "<>", RevisionType.DEL);
|
||||
// e.revision = (SELECT max(...) ...)
|
||||
qb.getRootParameters().addWhere(revisionPropertyPath, verCfg.getGlobalCfg().getCorrelatedSubqueryOperator(), maxRevQb);
|
||||
// all specified conditions
|
||||
for (AuditCriterion criterion : criterions) {
|
||||
criterion.addToQuery(verCfg, entityName, qb, qb.getRootParameters());
|
||||
}
|
||||
|
||||
List queryResult = buildAndExecuteQuery();
|
||||
Query query = buildQuery();
|
||||
// add named parameter (only used for ValidAuditTimeStrategy)
|
||||
List<String> params = Arrays.asList(query.getNamedParameters());
|
||||
if (params.contains("revision")) {
|
||||
query.setParameter("revision", revision);
|
||||
}
|
||||
List queryResult = query.list();
|
||||
|
||||
if (hasProjection) {
|
||||
return queryResult;
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* Behaviours of different audit strategy for populating audit data.
|
||||
|
@ -36,4 +40,61 @@ public interface AuditStrategy {
|
|||
*/
|
||||
void performCollectionChange(Session session, AuditConfiguration auditCfg,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
|
||||
|
||||
|
||||
/**
|
||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a two-entity relation.
|
||||
* This WHERE clause depends on the AuditStrategy, as follows:
|
||||
* <ul>
|
||||
* <li>For {@link DefaultAuditStrategy} a subquery is created:
|
||||
* <p><code>e.revision = (SELECT max(...) ...)</code></p>
|
||||
* </li>
|
||||
* <li>for {@link ValidTimeAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param globalCfg the {@link GlobalConfiguration}
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||
* @param idData id-information for the two-entity relation (only used for {@link DefaultAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param alias1 an alias used for subquery (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param alias2 an alias used for subquery (only used for {@link ValidTimeAuditStrategy})
|
||||
*/
|
||||
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
|
||||
String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2);
|
||||
|
||||
/**
|
||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity
|
||||
* association. This WHERE clause depends on the AuditStrategy, as follows:
|
||||
* <ul>
|
||||
* <li>For {@link DefaultAuditStrategy} a subquery is created:
|
||||
* <p><code>e.revision = (SELECT max(...) ...)</code></p>
|
||||
* </li>
|
||||
* <li>for {@link ValidTimeAuditStrategy} the revision-end column is used:
|
||||
* <p><code>e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)</code></p>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||
* @param revisionProperty property of the revision column
|
||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||
* @param referencingIdData id-information for the middle-entity association (only used for {@link DefaultAuditStrategy})
|
||||
* @param versionsMiddleEntityName name of the middle-entity
|
||||
* @param eeOriginalIdPropertyPath name of the id property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidTimeAuditStrategy})
|
||||
* @param componentDatas information about the middle-entity relation
|
||||
*/
|
||||
void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
package org.hibernate.envers.strategy;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
* Default strategy is to simply persist the audit data.
|
||||
|
@ -22,4 +27,52 @@ public class DefaultAuditStrategy implements AuditStrategy {
|
|||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
|
||||
}
|
||||
|
||||
|
||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath,
|
||||
String originalIdPropertyName, String alias1, String alias2) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
|
||||
// create a subquery builder
|
||||
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
||||
QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
|
||||
maxERevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
||||
// e2.revision <= :revision
|
||||
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
|
||||
// e2.id_ref_ed = e.id_ref_ed
|
||||
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
|
||||
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
|
||||
|
||||
// add subquery to rootParameters
|
||||
String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator();
|
||||
rootParameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb);
|
||||
}
|
||||
|
||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
|
||||
String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
|
||||
// SELECT max(ee2.revision) FROM middleEntity ee2
|
||||
QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, "ee2");
|
||||
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
|
||||
// WHERE
|
||||
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
|
||||
// ee2.revision <= :revision
|
||||
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
|
||||
// ee2.originalId.* = ee.originalId.*
|
||||
String ee2OriginalIdPropertyPath = "ee2." + originalIdPropertyName;
|
||||
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
for (MiddleComponentData componentData : componentDatas) {
|
||||
componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||
}
|
||||
|
||||
// add subquery to rootParameters
|
||||
rootParameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,12 @@ import org.hibernate.Session;
|
|||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.AuditConfiguration;
|
||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||
import org.hibernate.envers.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.tools.query.Parameters;
|
||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||
|
||||
/**
|
||||
|
@ -75,6 +79,32 @@ public class ValidTimeAuditStrategy implements AuditStrategy {
|
|||
session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
|
||||
}
|
||||
|
||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||
String revisionProperty,String revisionEndProperty, boolean addAlias,
|
||||
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
|
||||
String alias1, String alias2) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||
String originalIdPropertyName, MiddleComponentData... componentDatas) {
|
||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
||||
}
|
||||
|
||||
private void addRevisionRestriction(Parameters rootParameters,
|
||||
String revisionProperty, String revisionEndProperty, boolean addAlias) {
|
||||
|
||||
// e.revision <= _revision and (e.endRevision > _revision or e.endRevision is null)
|
||||
Parameters subParm = rootParameters.addSubParameters("or");
|
||||
rootParameters.addWhereWithNamedParam(revisionProperty, addAlias, "<=", "revision");
|
||||
subParm.addWhereWithNamedParam(revisionEndProperty + ".id", addAlias, ">", "revision");
|
||||
subParm.addWhere(revisionEndProperty, addAlias, "is", "null", false);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private RevisionType getRevisionType(AuditConfiguration auditCfg, Object data) {
|
||||
return (RevisionType) ((Map<String, Object>) data).get(auditCfg.getAuditEntCfg().getRevisionTypePropName());
|
||||
|
|
Loading…
Reference in New Issue