HHH-12992 - Fix proper support for order-by annotation on audited entity associations.
This commit is contained in:
parent
334e064272
commit
eff27db90a
|
@ -64,6 +64,7 @@ import org.hibernate.envers.internal.tools.MappingTools;
|
|||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||
import org.hibernate.envers.internal.tools.StringTools;
|
||||
import org.hibernate.envers.internal.tools.Tools;
|
||||
import org.hibernate.mapping.Bag;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.IndexedCollection;
|
||||
|
@ -237,7 +238,8 @@ public final class CollectionMetadataGenerator {
|
|||
referencedIdData,
|
||||
isEmbeddableElementType(),
|
||||
mappedBy,
|
||||
isMappedByKey( propertyValue, mappedBy )
|
||||
isMappedByKey( propertyValue, mappedBy ),
|
||||
propertyValue.getOrderBy()
|
||||
);
|
||||
|
||||
// Creating common mapper data.
|
||||
|
@ -290,7 +292,15 @@ public final class CollectionMetadataGenerator {
|
|||
|
||||
// Checking if there's an index defined. If so, adding a mapper for it.
|
||||
if ( positionMappedBy != null ) {
|
||||
final Type indexType = ( (IndexedCollection) propertyValue ).getIndex().getType();
|
||||
final Type indexType;
|
||||
if ( IndexedCollection.class.isInstance( propertyValue ) ) {
|
||||
indexType = ( (IndexedCollection) propertyValue ).getIndex().getType();
|
||||
}
|
||||
else {
|
||||
// todo - do we need to reverse lookup the type anyway?
|
||||
indexType = null;
|
||||
}
|
||||
|
||||
fakeBidirectionalRelationIndexMapper = new SinglePropertyMapper(
|
||||
PropertyData.forProperty( positionMappedBy, indexType )
|
||||
);
|
||||
|
@ -451,7 +461,10 @@ public final class CollectionMetadataGenerator {
|
|||
mainGenerator.getAuditStrategy(),
|
||||
referencingIdData,
|
||||
auditMiddleEntityName,
|
||||
isRevisionTypeInId()
|
||||
isRevisionTypeInId(),
|
||||
propertyValue.getOrderBy() == null
|
||||
? propertyValue.getManyToManyOrdering()
|
||||
: propertyValue.getOrderBy()
|
||||
);
|
||||
|
||||
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
|
||||
|
|
|
@ -36,6 +36,7 @@ public final class QueryGeneratorBuilder {
|
|||
private final String auditMiddleEntityName;
|
||||
private final List<MiddleIdData> idDatas;
|
||||
private final boolean revisionTypeInId;
|
||||
private final String orderBy;
|
||||
|
||||
QueryGeneratorBuilder(
|
||||
GlobalConfiguration globalCfg,
|
||||
|
@ -43,12 +44,14 @@ public final class QueryGeneratorBuilder {
|
|||
AuditStrategy auditStrategy,
|
||||
MiddleIdData referencingIdData,
|
||||
String auditMiddleEntityName,
|
||||
boolean revisionTypeInId) {
|
||||
boolean revisionTypeInId,
|
||||
String orderBy) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.referencingIdData = referencingIdData;
|
||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||
this.orderBy = orderBy;
|
||||
this.revisionTypeInId = revisionTypeInId;
|
||||
|
||||
idDatas = new ArrayList<>();
|
||||
|
@ -61,7 +64,7 @@ public final class QueryGeneratorBuilder {
|
|||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||
if ( idDatas.size() == 0 ) {
|
||||
return new OneEntityQueryGenerator(
|
||||
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
revisionTypeInId, componentDatas
|
||||
);
|
||||
}
|
||||
|
@ -69,13 +72,13 @@ public final class QueryGeneratorBuilder {
|
|||
if ( idDatas.get( 0 ).isAudited() ) {
|
||||
return new TwoEntityQueryGenerator(
|
||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
||||
idDatas.get( 0 ), revisionTypeInId, orderBy, componentDatas
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new TwoEntityOneAuditedQueryGenerator(
|
||||
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get( 0 ), revisionTypeInId, orderBy, componentDatas
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -86,10 +89,9 @@ public final class QueryGeneratorBuilder {
|
|||
"Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported."
|
||||
);
|
||||
}
|
||||
|
||||
return new ThreeEntityQueryGenerator(
|
||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||
idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, componentDatas
|
||||
idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, orderBy, componentDatas
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.envers.boot.internal.EnversService;
|
||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
||||
|
@ -46,7 +47,8 @@ public abstract class AbstractCollectionInitializor<T> implements Initializor<T>
|
|||
|
||||
@Override
|
||||
public T initialize() {
|
||||
final List<?> collectionContent = queryGenerator.getQuery( versionsReader, primaryKey, revision, removed ).list();
|
||||
final SharedSessionContractImplementor session = versionsReader.getSessionImplementor();
|
||||
final List<?> collectionContent = queryGenerator.getQuery( session, primaryKey, revision, removed ).list();
|
||||
|
||||
final T collection = initializeCollection( collectionContent.size() );
|
||||
|
||||
|
|
|
@ -9,12 +9,17 @@ package org.hibernate.envers.internal.entities.mapper.relation.query;
|
|||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.QueryParameterData;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||
|
@ -27,57 +32,127 @@ import static org.hibernate.envers.internal.entities.mapper.relation.query.Query
|
|||
* @author Chris Cranford
|
||||
*/
|
||||
public abstract class AbstractRelationQueryGenerator implements RelationQueryGenerator {
|
||||
protected final GlobalConfiguration globalCfg;
|
||||
protected final AuditEntitiesConfiguration verEntCfg;
|
||||
protected final AuditStrategy auditStrategy;
|
||||
protected final MiddleIdData referencingIdData;
|
||||
protected final boolean revisionTypeInId;
|
||||
protected final String entityName;
|
||||
protected final String orderBy;
|
||||
|
||||
private String queryString;
|
||||
private String queryRemovedString;
|
||||
|
||||
protected AbstractRelationQueryGenerator(
|
||||
GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String entityName,
|
||||
MiddleIdData referencingIdData,
|
||||
boolean revisionTypeInId) {
|
||||
boolean revisionTypeInId,
|
||||
String orderBy) {
|
||||
this.globalCfg = globalCfg;
|
||||
this.verEntCfg = verEntCfg;
|
||||
this.entityName = entityName;
|
||||
this.auditStrategy = auditStrategy;
|
||||
this.referencingIdData = referencingIdData;
|
||||
this.revisionTypeInId = revisionTypeInId;
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Query used to retrieve state of audited entity valid at a given revision.
|
||||
*/
|
||||
protected abstract String getQueryString();
|
||||
|
||||
/**
|
||||
* @return Query executed to retrieve state of audited entity valid at previous revision
|
||||
* or removed during exactly specified revision number. Used only when traversing deleted
|
||||
* entities graph.
|
||||
*/
|
||||
protected abstract String getQueryRemovedString();
|
||||
|
||||
@Override
|
||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision, boolean removed) {
|
||||
final Query query = versionsReader.getSession().createQuery( removed ? getQueryRemovedString() : getQueryString() );
|
||||
public Query getQuery(SharedSessionContractImplementor session, Object primaryKey, Number revision, boolean removed) {
|
||||
final String queryString = getQueryString( session.getFactory(), removed );
|
||||
|
||||
final Query query = session.createQuery( queryString );
|
||||
query.setParameter( DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL );
|
||||
query.setParameter( REVISION_PARAMETER, revision );
|
||||
for ( QueryParameterData paramData : referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(
|
||||
primaryKey
|
||||
) ) {
|
||||
|
||||
final IdMapper prefixIdMapper = referencingIdData.getPrefixedMapper();
|
||||
for ( QueryParameterData paramData : prefixIdMapper.mapToQueryParametersFromId( primaryKey ) ) {
|
||||
paramData.setParameterValue( query );
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
protected String queryToString(QueryBuilder query) {
|
||||
/**
|
||||
* Build the common aspects of a {@link QueryBuilder} used by both query and query-remove strings.
|
||||
*
|
||||
* @param sessionFactory The session factory.
|
||||
* @return The constructed query builder instance.
|
||||
*/
|
||||
protected abstract QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory);
|
||||
|
||||
/**
|
||||
* Apply predicates used to fetch actual data.
|
||||
*
|
||||
* @param qb The query builder instance to apply predicates against.
|
||||
* @param parameters The root query parameters
|
||||
* @param inclusive Whether its inclusive or not.
|
||||
*/
|
||||
protected abstract void applyValidPredicates(QueryBuilder qb, Parameters parameters, boolean inclusive);
|
||||
|
||||
/**
|
||||
* Apply predicates to fetch data and deletions that took place during the same revision.
|
||||
*
|
||||
* @param qb The query builder instance to apply predicates against.
|
||||
*/
|
||||
protected abstract void applyValidAndRemovePredicates(QueryBuilder qb);
|
||||
|
||||
protected String getRevisionTypePath() {
|
||||
if ( revisionTypeInId ) {
|
||||
return verEntCfg.getOriginalIdPropName() + "." + verEntCfg.getRevisionTypePropName();
|
||||
}
|
||||
return verEntCfg.getRevisionTypePropName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query to be used.
|
||||
*
|
||||
* If {@code removed} is specified as {@code true}, the removal query will be returned.
|
||||
* If {@code removed} is specified as {@code false}, the non-removal query will be returned.
|
||||
*
|
||||
* This method internally will cache the built queries so that subsequent calls will not
|
||||
* require the rebuilding of the queries.
|
||||
*
|
||||
* @param sessionFactory The session factory.
|
||||
* @param removed Whether to return the removal query or non-removal query.
|
||||
* @return The query string to be used.
|
||||
*/
|
||||
private String getQueryString(SessionFactoryImplementor sessionFactory, boolean removed) {
|
||||
if ( removed ) {
|
||||
if ( queryRemovedString == null ) {
|
||||
queryRemovedString = buildQueryRemoveString( sessionFactory );
|
||||
}
|
||||
return queryRemovedString;
|
||||
}
|
||||
|
||||
if ( queryString == null ) {
|
||||
queryString = buildQueryString( sessionFactory );
|
||||
}
|
||||
return queryString;
|
||||
}
|
||||
|
||||
private String buildQueryString(SessionFactoryImplementor sessionFactory) {
|
||||
final QueryBuilder builder = buildQueryBuilderCommon( sessionFactory );
|
||||
applyValidPredicates( builder, builder.getRootParameters(), true );
|
||||
return queryToString( builder );
|
||||
}
|
||||
|
||||
private String buildQueryRemoveString(SessionFactoryImplementor sessionFactory) {
|
||||
final QueryBuilder builder = buildQueryBuilderCommon( sessionFactory );
|
||||
applyValidAndRemovePredicates( builder );
|
||||
return queryToString( builder );
|
||||
}
|
||||
|
||||
private String queryToString(QueryBuilder query) {
|
||||
return queryToString( query, Collections.emptyMap() );
|
||||
}
|
||||
|
||||
protected String queryToString(QueryBuilder query, Map<String, Object> queryParamValues) {
|
||||
private String queryToString(QueryBuilder query, Map<String, Object> queryParamValues) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
query.build( sb, queryParamValues );
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected String getRevisionTypePath() {
|
||||
return revisionTypeInId
|
||||
? verEntCfg.getOriginalIdPropName() + "." + verEntCfg.getRevisionTypePropName()
|
||||
: verEntCfg.getRevisionTypePropName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.internal.entities.mapper.id.AbstractCompositeIdMapper;
|
||||
|
@ -14,6 +15,7 @@ import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
|||
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.REFERENCED_ENTITY_ALIAS;
|
||||
|
@ -28,10 +30,9 @@ import static org.hibernate.envers.internal.entities.mapper.relation.query.Query
|
|||
* @author Chris Cranford
|
||||
*/
|
||||
public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||
private final String queryString;
|
||||
private final String queryRemovedString;
|
||||
private final String mappedBy;
|
||||
private final boolean multipleIdMapperKey;
|
||||
private final MiddleIdData referencedIdData;
|
||||
|
||||
public OneAuditEntityQueryGenerator(
|
||||
GlobalConfiguration globalCfg,
|
||||
|
@ -42,10 +43,20 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId,
|
||||
String mappedBy,
|
||||
boolean mappedByKey) {
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
boolean mappedByKey,
|
||||
String orderBy) {
|
||||
super(
|
||||
globalCfg,
|
||||
verEntCfg,
|
||||
auditStrategy,
|
||||
verEntCfg.getAuditEntityName( referencedEntityName ),
|
||||
referencingIdData,
|
||||
revisionTypeInId,
|
||||
orderBy
|
||||
);
|
||||
|
||||
this.mappedBy = mappedBy;
|
||||
this.referencedIdData = referencedIdData;
|
||||
|
||||
// HHH-11770 We use AbstractCompositeIdMapper here to handle EmbeddedIdMapper and MultipleIdMappper support
|
||||
// so that OneAuditEntityQueryGenerator supports mappings to both @IdClass and @EmbeddedId components.
|
||||
|
@ -74,24 +85,12 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
* (only non-deleted entities)
|
||||
* e.revision_type != DEL
|
||||
*/
|
||||
final QueryBuilder commonPart = commonQueryPart( verEntCfg.getAuditEntityName( referencedEntityName ) );
|
||||
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||
createValidDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, validQuery, validQuery.getRootParameters()
|
||||
);
|
||||
createValidAndRemovedDataRestrictions( globalCfg, auditStrategy, referencedIdData, removedQuery );
|
||||
|
||||
queryString = queryToString( validQuery );
|
||||
queryRemovedString = queryToString( removedQuery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute common part for both queries.
|
||||
*/
|
||||
private QueryBuilder commonQueryPart(String versionsReferencedEntityName) {
|
||||
@Override
|
||||
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||
// SELECT e FROM versionsEntity e
|
||||
final QueryBuilder qb = new QueryBuilder( versionsReferencedEntityName, REFERENCED_ENTITY_ALIAS );
|
||||
final QueryBuilder qb = new QueryBuilder( entityName, REFERENCED_ENTITY_ALIAS, sessionFactory );
|
||||
qb.addProjection( null, REFERENCED_ENTITY_ALIAS, null, false );
|
||||
// WHERE
|
||||
if ( multipleIdMapperKey ) {
|
||||
|
@ -105,57 +104,53 @@ public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGen
|
|||
// e.id_ref_ed = :id_ref_ed
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( qb.getRootParameters(), null, true );
|
||||
}
|
||||
|
||||
// ORDER BY
|
||||
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||
}
|
||||
|
||||
return qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates query restrictions used to retrieve only actual data.
|
||||
*/
|
||||
private void createValidDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||
MiddleIdData referencedIdData, QueryBuilder qb, Parameters rootParameters) {
|
||||
@Override
|
||||
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
// (selecting e entities at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addEntityAtRevisionRestriction(
|
||||
globalCfg, qb, rootParameters, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData, revisionPropertyPath,
|
||||
verEntCfg.getOriginalIdPropName(), REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
||||
globalCfg,
|
||||
qb,
|
||||
rootParameters,
|
||||
revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(),
|
||||
true,
|
||||
referencedIdData,
|
||||
revisionPropertyPath,
|
||||
verEntCfg.getOriginalIdPropName(),
|
||||
REFERENCED_ENTITY_ALIAS,
|
||||
REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
||||
true
|
||||
);
|
||||
// e.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||
*/
|
||||
private void createValidAndRemovedDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||
MiddleIdData referencedIdData, QueryBuilder remQb) {
|
||||
@Override
|
||||
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||
// Restrictions to match all valid rows.
|
||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||
// Restrictions to match all rows deleted at exactly given revision.
|
||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||
// Excluding current revision, because we need to match data valid at the previous one.
|
||||
createValidDataRestrictions( globalCfg, auditStrategy, referencedIdData, remQb, valid );
|
||||
applyValidPredicates( remQb, valid, false );
|
||||
// e.revision = :revision
|
||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), false, "=", REVISION_PARAMETER );
|
||||
// e.revision_type = DEL
|
||||
removed.addWhereWithNamedParam( getRevisionTypePath(), false, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryRemovedString() {
|
||||
return queryRemovedString;
|
||||
}
|
||||
|
||||
private IdMapper getMultipleIdPrefixedMapper() {
|
||||
final String prefix = verEntCfg.getOriginalIdPropName() + "." + mappedBy + ".";
|
||||
return referencingIdData.getOriginalMapper().prefixMappedProperties( prefix );
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||
|
@ -22,16 +24,30 @@ import static org.hibernate.envers.internal.entities.mapper.relation.query.Query
|
|||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||
private final String queryString;
|
||||
private final String queryRemovedString;
|
||||
private final MiddleComponentData[] componentDatas;
|
||||
|
||||
public OneEntityQueryGenerator(
|
||||
AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName, MiddleIdData referencingIdData,
|
||||
boolean revisionTypeInId, MiddleComponentData... componentData) {
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
boolean revisionTypeInId,
|
||||
MiddleComponentData... componentData) {
|
||||
super(
|
||||
globalCfg,
|
||||
verEntCfg,
|
||||
auditStrategy,
|
||||
versionsMiddleEntityName,
|
||||
referencingIdData,
|
||||
revisionTypeInId,
|
||||
null
|
||||
);
|
||||
|
||||
this.componentDatas = componentData;
|
||||
|
||||
/*
|
||||
* The valid query that we need to create:
|
||||
|
@ -52,24 +68,12 @@ public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
* (only non-deleted entities and associations)
|
||||
* ee.revision_type != DEL
|
||||
*/
|
||||
final QueryBuilder commonPart = commonQueryPart( versionsMiddleEntityName );
|
||||
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||
createValidDataRestrictions(
|
||||
auditStrategy, versionsMiddleEntityName, validQuery, validQuery.getRootParameters(), true, componentData
|
||||
);
|
||||
createValidAndRemovedDataRestrictions( auditStrategy, versionsMiddleEntityName, removedQuery, componentData );
|
||||
|
||||
queryString = queryToString( validQuery );
|
||||
queryRemovedString = queryToString( removedQuery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute common part for both queries.
|
||||
*/
|
||||
private QueryBuilder commonQueryPart(String versionsMiddleEntityName) {
|
||||
@Override
|
||||
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||
// SELECT ee FROM middleEntity ee
|
||||
final QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||
final QueryBuilder qb = new QueryBuilder( entityName, MIDDLE_ENTITY_ALIAS, sessionFactory );
|
||||
qb.addProjection( null, MIDDLE_ENTITY_ALIAS, null, false );
|
||||
// WHERE
|
||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
|
@ -78,56 +82,55 @@ public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
verEntCfg.getOriginalIdPropName(),
|
||||
true
|
||||
);
|
||||
|
||||
// NOTE:
|
||||
// No `orderBy` fragment is specified because this generator is used for
|
||||
// embeddables and enumerations where either a Set-based container will
|
||||
// force the SETORDINAL property to give us a unique primary key tuple
|
||||
// or an @IndexColumn/@OrderColumn must be specified that takes priority
|
||||
// over an @OrderBy fragment.
|
||||
|
||||
return qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates query restrictions used to retrieve only actual data.
|
||||
*/
|
||||
private void createValidDataRestrictions(
|
||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||
QueryBuilder qb, Parameters rootParameters, boolean inclusive,
|
||||
MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(
|
||||
qb, rootParameters, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true,
|
||||
referencingIdData, versionsMiddleEntityName, eeOriginalIdPropertyPath, revisionPropertyPath,
|
||||
originalIdPropertyName, MIDDLE_ENTITY_ALIAS, inclusive, componentData
|
||||
qb,
|
||||
rootParameters,
|
||||
revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(),
|
||||
true,
|
||||
referencingIdData,
|
||||
entityName,
|
||||
eeOriginalIdPropertyPath,
|
||||
revisionPropertyPath,
|
||||
originalIdPropertyName,
|
||||
MIDDLE_ENTITY_ALIAS,
|
||||
inclusive,
|
||||
componentDatas
|
||||
);
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||
*/
|
||||
private void createValidAndRemovedDataRestrictions(
|
||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||
QueryBuilder remQb, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||
// Restrictions to match all valid rows.
|
||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||
// Restrictions to match all rows deleted at exactly given revision.
|
||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||
// Excluding current revision, because we need to match data valid at the previous one.
|
||||
createValidDataRestrictions( auditStrategy, versionsMiddleEntityName, remQb, valid, false, componentData );
|
||||
applyValidPredicates( remQb, valid, false );
|
||||
// ee.revision = :revision
|
||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
||||
// ee.revision_type = DEL
|
||||
removed.addWhereWithNamedParam( getRevisionTypePath(), "=", DEL_REVISION_TYPE_PARAMETER );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryRemovedString() {
|
||||
return queryRemovedString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,26 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
||||
|
||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
/**
|
||||
* TODO: cleanup implementations and extract common code
|
||||
* <p/>
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public interface RelationQueryGenerator {
|
||||
Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision, boolean removed);
|
||||
/**
|
||||
* Return the query to fetch the relation.
|
||||
*
|
||||
* @param session The session.
|
||||
* @param primaryKey The primary key of the owning object.
|
||||
* @param revision The revision to be fetched.
|
||||
* @param removed Whether to return a query that includes the removed audit rows.
|
||||
*/
|
||||
Query getQuery(SharedSessionContractImplementor session, Object primaryKey, Number revision, boolean removed);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||
|
@ -13,6 +14,7 @@ import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
|||
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.INDEX_ENTITY_ALIAS;
|
||||
|
@ -27,18 +29,37 @@ import static org.hibernate.envers.internal.entities.mapper.relation.query.Query
|
|||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||
private final String queryString;
|
||||
private final String queryRemovedString;
|
||||
private final MiddleIdData referencedIdData;
|
||||
private final MiddleIdData indexIdData;
|
||||
private final MiddleComponentData[] componentDatas;
|
||||
|
||||
public ThreeEntityQueryGenerator(
|
||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData, MiddleIdData referencedIdData,
|
||||
MiddleIdData indexIdData, boolean revisionTypeInId,
|
||||
GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
MiddleIdData indexIdData,
|
||||
boolean revisionTypeInId,
|
||||
String orderBy,
|
||||
MiddleComponentData... componentData) {
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
super(
|
||||
globalCfg,
|
||||
verEntCfg,
|
||||
auditStrategy,
|
||||
versionsMiddleEntityName,
|
||||
referencingIdData,
|
||||
revisionTypeInId,
|
||||
orderBy
|
||||
);
|
||||
|
||||
this.referencedIdData = referencedIdData;
|
||||
this.indexIdData = indexIdData;
|
||||
this.componentDatas = componentData;
|
||||
|
||||
/*
|
||||
* The valid query that we need to create:
|
||||
|
@ -86,35 +107,14 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
* e.revision_type != DEL AND
|
||||
* f.revision_type != DEL
|
||||
*/
|
||||
final QueryBuilder commonPart = commonQueryPart(
|
||||
referencedIdData,
|
||||
indexIdData,
|
||||
versionsMiddleEntityName,
|
||||
verEntCfg.getOriginalIdPropName()
|
||||
);
|
||||
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||
createValidDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, validQuery,
|
||||
validQuery.getRootParameters(), true, indexIdData, componentData
|
||||
);
|
||||
createValidAndRemovedDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, removedQuery, indexIdData, componentData
|
||||
);
|
||||
|
||||
queryString = queryToString( validQuery );
|
||||
queryRemovedString = queryToString( removedQuery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute common part for both queries.
|
||||
*/
|
||||
private QueryBuilder commonQueryPart(
|
||||
MiddleIdData referencedIdData, MiddleIdData indexIdData,
|
||||
String versionsMiddleEntityName, String originalIdPropertyName) {
|
||||
@Override
|
||||
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
// SELECT new list(ee) FROM middleEntity ee
|
||||
final QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||
final QueryBuilder qb = new QueryBuilder( entityName, MIDDLE_ENTITY_ALIAS, sessionFactory );
|
||||
qb.addFrom( referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS, false );
|
||||
qb.addFrom( indexIdData.getAuditEntityName(), INDEX_ENTITY_ALIAS, false );
|
||||
qb.addProjection(
|
||||
|
@ -135,16 +135,18 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
);
|
||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||
|
||||
// ORDER BY
|
||||
// Hibernate applies @OrderBy on map elements, not the key.
|
||||
// So here we apply it to the referenced entity, not the actual index entity that represents the key.
|
||||
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||
}
|
||||
return qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates query restrictions used to retrieve only actual data.
|
||||
*/
|
||||
private void createValidDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||
MiddleIdData referencedIdData, String versionsMiddleEntityName, QueryBuilder qb,
|
||||
Parameters rootParameters, boolean inclusive, MiddleIdData indexIdData, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
|
@ -184,9 +186,19 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(
|
||||
qb, rootParameters, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true,
|
||||
referencingIdData, versionsMiddleEntityName, eeOriginalIdPropertyPath, revisionPropertyPath,
|
||||
originalIdPropertyName, MIDDLE_ENTITY_ALIAS, inclusive, componentData
|
||||
qb,
|
||||
rootParameters,
|
||||
revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(),
|
||||
true,
|
||||
referencingIdData,
|
||||
entityName,
|
||||
eeOriginalIdPropertyPath,
|
||||
revisionPropertyPath,
|
||||
originalIdPropertyName,
|
||||
MIDDLE_ENTITY_ALIAS,
|
||||
inclusive,
|
||||
componentDatas
|
||||
);
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||
|
@ -206,13 +218,8 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||
*/
|
||||
private void createValidAndRemovedDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||
QueryBuilder remQb, MiddleIdData indexIdData, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||
// Restrictions to match all valid rows.
|
||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||
|
@ -221,9 +228,7 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
final String revisionTypePropName = getRevisionTypePath();
|
||||
// Excluding current revision, because we need to match data valid at the previous one.
|
||||
createValidDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, remQb, valid, false, indexIdData, componentData
|
||||
);
|
||||
applyValidPredicates( remQb, valid, false );
|
||||
// ee.revision = :revision
|
||||
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
||||
// e.revision = :revision
|
||||
|
@ -257,14 +262,4 @@ public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenera
|
|||
DEL_REVISION_TYPE_PARAMETER
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryRemovedString() {
|
||||
return queryRemovedString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||
|
@ -23,17 +26,34 @@ import static org.hibernate.envers.internal.entities.mapper.relation.query.Query
|
|||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQueryGenerator {
|
||||
private final String queryString;
|
||||
private final String queryRemovedString;
|
||||
private final MiddleIdData referencedIdData;
|
||||
private final MiddleComponentData[] componentDatas;
|
||||
|
||||
public TwoEntityOneAuditedQueryGenerator(
|
||||
AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName, MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData, boolean revisionTypeInId,
|
||||
GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId,
|
||||
String orderBy,
|
||||
MiddleComponentData... componentData) {
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
super(
|
||||
globalCfg,
|
||||
verEntCfg,
|
||||
auditStrategy,
|
||||
versionsMiddleEntityName,
|
||||
referencingIdData,
|
||||
revisionTypeInId,
|
||||
orderBy
|
||||
);
|
||||
|
||||
this.referencedIdData = referencedIdData;
|
||||
this.componentDatas = componentData;
|
||||
|
||||
/*
|
||||
* The valid query that we need to create:
|
||||
|
@ -57,31 +77,14 @@ public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQue
|
|||
* (only non-deleted entities and associations)
|
||||
* ee.revision_type != DEL
|
||||
*/
|
||||
final QueryBuilder commonPart = commonQueryPart(
|
||||
referencedIdData,
|
||||
versionsMiddleEntityName,
|
||||
verEntCfg.getOriginalIdPropName()
|
||||
);
|
||||
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||
createValidDataRestrictions(
|
||||
auditStrategy, versionsMiddleEntityName, validQuery, validQuery.getRootParameters(), componentData
|
||||
);
|
||||
createValidAndRemovedDataRestrictions( auditStrategy, versionsMiddleEntityName, removedQuery, componentData );
|
||||
|
||||
queryString = queryToString( validQuery );
|
||||
queryRemovedString = queryToString( removedQuery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute common part for both queries.
|
||||
*/
|
||||
private QueryBuilder commonQueryPart(
|
||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||
String originalIdPropertyName) {
|
||||
@Override
|
||||
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
// SELECT new list(ee) FROM middleEntity ee
|
||||
final QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||
final QueryBuilder qb = new QueryBuilder( entityName, MIDDLE_ENTITY_ALIAS, sessionFactory );
|
||||
qb.addFrom( referencedIdData.getEntityName(), REFERENCED_ENTITY_ALIAS, false );
|
||||
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, null, false );
|
||||
// WHERE
|
||||
|
@ -92,54 +95,53 @@ public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQue
|
|||
);
|
||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||
// ORDER BY
|
||||
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||
}
|
||||
return qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates query restrictions used to retrieve only actual data.
|
||||
*/
|
||||
private void createValidDataRestrictions(
|
||||
AuditStrategy auditStrategy, String versionsMiddleEntityName, QueryBuilder qb,
|
||||
Parameters rootParameters, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(
|
||||
qb, rootParameters, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true,
|
||||
referencingIdData, versionsMiddleEntityName, eeOriginalIdPropertyPath, revisionPropertyPath,
|
||||
originalIdPropertyName, MIDDLE_ENTITY_ALIAS, true, componentData
|
||||
qb,
|
||||
rootParameters,
|
||||
revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(),
|
||||
true,
|
||||
referencingIdData,
|
||||
entityName,
|
||||
eeOriginalIdPropertyPath,
|
||||
revisionPropertyPath,
|
||||
originalIdPropertyName,
|
||||
MIDDLE_ENTITY_ALIAS,
|
||||
true,
|
||||
componentDatas
|
||||
);
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||
*/
|
||||
private void createValidAndRemovedDataRestrictions(
|
||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||
QueryBuilder remQb, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||
// Restrictions to match all valid rows.
|
||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||
// Restrictions to match all rows deleted at exactly given revision.
|
||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||
createValidDataRestrictions( auditStrategy, versionsMiddleEntityName, remQb, valid, componentData );
|
||||
applyValidPredicates( remQb, valid, false );
|
||||
// ee.revision = :revision
|
||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
||||
// ee.revision_type = DEL
|
||||
removed.addWhereWithNamedParam( getRevisionTypePath(), "=", DEL_REVISION_TYPE_PARAMETER );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryRemovedString() {
|
||||
return queryRemovedString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||
|
@ -13,6 +15,7 @@ import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
|||
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||
import org.hibernate.envers.strategy.AuditStrategy;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||
|
@ -25,17 +28,34 @@ import static org.hibernate.envers.internal.entities.mapper.relation.query.Query
|
|||
*
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||
private final String queryString;
|
||||
private final String queryRemovedString;
|
||||
private final MiddleIdData referencedIdData;
|
||||
private final MiddleComponentData[] componentDatas;
|
||||
|
||||
public TwoEntityQueryGenerator(
|
||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData, MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId, MiddleComponentData... componentData) {
|
||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||
GlobalConfiguration globalCfg,
|
||||
AuditEntitiesConfiguration verEntCfg,
|
||||
AuditStrategy auditStrategy,
|
||||
String versionsMiddleEntityName,
|
||||
MiddleIdData referencingIdData,
|
||||
MiddleIdData referencedIdData,
|
||||
boolean revisionTypeInId,
|
||||
String orderBy,
|
||||
MiddleComponentData... componentData) {
|
||||
super(
|
||||
globalCfg,
|
||||
verEntCfg,
|
||||
auditStrategy,
|
||||
versionsMiddleEntityName,
|
||||
referencingIdData,
|
||||
revisionTypeInId,
|
||||
orderBy
|
||||
);
|
||||
|
||||
this.referencedIdData = referencedIdData;
|
||||
this.componentDatas = componentData;
|
||||
|
||||
/*
|
||||
* The valid query that we need to create:
|
||||
|
@ -68,34 +88,14 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
* ee.revision_type != DEL AND
|
||||
* e.revision_type != DEL
|
||||
*/
|
||||
final QueryBuilder commonPart = commonQueryPart(
|
||||
referencedIdData,
|
||||
versionsMiddleEntityName,
|
||||
verEntCfg.getOriginalIdPropName()
|
||||
);
|
||||
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||
createValidDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, validQuery,
|
||||
validQuery.getRootParameters(), true, componentData
|
||||
);
|
||||
createValidAndRemovedDataRestrictions(
|
||||
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, removedQuery, componentData
|
||||
);
|
||||
|
||||
queryString = queryToString( validQuery );
|
||||
queryRemovedString = queryToString( removedQuery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute common part for both queries.
|
||||
*/
|
||||
private QueryBuilder commonQueryPart(
|
||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||
String originalIdPropertyName) {
|
||||
@Override
|
||||
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
// SELECT new list(ee) FROM middleEntity ee
|
||||
QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||
QueryBuilder qb = new QueryBuilder( entityName, MIDDLE_ENTITY_ALIAS, sessionFactory );
|
||||
qb.addFrom( referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS, false );
|
||||
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, null, false );
|
||||
// WHERE
|
||||
|
@ -107,16 +107,17 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
);
|
||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||
|
||||
// ORDER BY
|
||||
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||
}
|
||||
|
||||
return qb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates query restrictions used to retrieve only actual data.
|
||||
*/
|
||||
private void createValidDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy, MiddleIdData referencedIdData,
|
||||
String versionsMiddleEntityName, QueryBuilder qb, Parameters rootParameters,
|
||||
boolean inclusive, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||
|
@ -140,10 +141,19 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
// (with ee association at revision :revision)
|
||||
// --> based on auditStrategy (see above)
|
||||
auditStrategy.addAssociationAtRevisionRestriction(
|
||||
qb, rootParameters, revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS,
|
||||
inclusive, componentData
|
||||
qb,
|
||||
rootParameters,
|
||||
revisionPropertyPath,
|
||||
verEntCfg.getRevisionEndFieldName(),
|
||||
true,
|
||||
referencingIdData,
|
||||
entityName,
|
||||
eeOriginalIdPropertyPath,
|
||||
revisionPropertyPath,
|
||||
originalIdPropertyName,
|
||||
MIDDLE_ENTITY_ALIAS,
|
||||
inclusive,
|
||||
componentDatas
|
||||
);
|
||||
// ee.revision_type != DEL
|
||||
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||
|
@ -156,13 +166,8 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||
*/
|
||||
private void createValidAndRemovedDataRestrictions(
|
||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||
QueryBuilder remQb, MiddleComponentData... componentData) {
|
||||
@Override
|
||||
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||
// Restrictions to match all valid rows.
|
||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||
|
@ -171,15 +176,10 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||
final String revisionTypePropName = getRevisionTypePath();
|
||||
// Excluding current revision, because we need to match data valid at the previous one.
|
||||
createValidDataRestrictions(
|
||||
globalCfg,
|
||||
auditStrategy,
|
||||
referencedIdData,
|
||||
versionsMiddleEntityName,
|
||||
applyValidPredicates(
|
||||
remQb,
|
||||
valid,
|
||||
false,
|
||||
componentData
|
||||
false
|
||||
);
|
||||
// ee.revision = :revision
|
||||
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
||||
|
@ -200,14 +200,4 @@ public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerato
|
|||
DEL_REVISION_TYPE_PARAMETER
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getQueryRemovedString() {
|
||||
return queryRemovedString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,19 +8,33 @@ package org.hibernate.envers.internal.tools.query;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.criteria.JoinType;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.internal.entities.RevisionTypeType;
|
||||
import org.hibernate.envers.internal.tools.MutableInteger;
|
||||
import org.hibernate.envers.internal.tools.StringTools;
|
||||
import org.hibernate.envers.internal.tools.Triple;
|
||||
import org.hibernate.envers.tools.Pair;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.sql.Template;
|
||||
import org.hibernate.sql.ordering.antlr.ColumnMapper;
|
||||
import org.hibernate.sql.ordering.antlr.ColumnReference;
|
||||
import org.hibernate.sql.ordering.antlr.FormulaReference;
|
||||
import org.hibernate.sql.ordering.antlr.OrderByAliasResolver;
|
||||
import org.hibernate.sql.ordering.antlr.OrderByTranslation;
|
||||
import org.hibernate.sql.ordering.antlr.SqlValueReference;
|
||||
import org.hibernate.type.CustomType;
|
||||
|
||||
/**
|
||||
|
@ -59,19 +73,30 @@ public class QueryBuilder {
|
|||
*/
|
||||
private final List<String> projections;
|
||||
|
||||
private final List<Pair<String, String>> orderFragments;
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
/**
|
||||
* @param entityName Main entity which should be selected.
|
||||
* @param alias Alias of the entity
|
||||
* @param sessionFactory Session factory
|
||||
*/
|
||||
public QueryBuilder(String entityName, String alias) {
|
||||
this( entityName, alias, new MutableInteger(), new MutableInteger() );
|
||||
public QueryBuilder(String entityName, String alias, SessionFactoryImplementor sessionFactory) {
|
||||
this( entityName, alias, new MutableInteger(), new MutableInteger(), sessionFactory );
|
||||
}
|
||||
|
||||
private QueryBuilder(String entityName, String alias, MutableInteger aliasCounter, MutableInteger paramCounter) {
|
||||
private QueryBuilder(
|
||||
String entityName,
|
||||
String alias,
|
||||
MutableInteger aliasCounter,
|
||||
MutableInteger paramCounter,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.entityName = entityName;
|
||||
this.alias = alias;
|
||||
this.aliasCounter = aliasCounter;
|
||||
this.paramCounter = paramCounter;
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
final Parameters rootParameters = new Parameters( alias, "and", paramCounter );
|
||||
parameters.add( rootParameters );
|
||||
|
@ -79,6 +104,7 @@ public class QueryBuilder {
|
|||
froms = new ArrayList<>();
|
||||
orders = new ArrayList<>();
|
||||
projections = new ArrayList<>();
|
||||
orderFragments = new ArrayList<>();
|
||||
|
||||
addFrom( entityName, alias, true );
|
||||
}
|
||||
|
@ -87,6 +113,7 @@ public class QueryBuilder {
|
|||
private QueryBuilder(QueryBuilder other) {
|
||||
this.entityName = other.entityName;
|
||||
this.alias = other.alias;
|
||||
this.sessionFactory = other.sessionFactory;
|
||||
this.aliasCounter = other.aliasCounter.deepCopy();
|
||||
this.paramCounter = other.paramCounter.deepCopy();
|
||||
for (final Parameters params : other.parameters) {
|
||||
|
@ -96,6 +123,7 @@ public class QueryBuilder {
|
|||
froms = new ArrayList<>( other.froms );
|
||||
orders = new ArrayList<>( other.orders );
|
||||
projections = new ArrayList<>( other.projections );
|
||||
orderFragments = new ArrayList<>( other.orderFragments );
|
||||
}
|
||||
|
||||
public QueryBuilder deepCopy() {
|
||||
|
@ -123,7 +151,13 @@ public class QueryBuilder {
|
|||
|
||||
public Parameters addJoin(JoinType joinType, String entityName, String alias, boolean select) {
|
||||
Parameters joinConditionParameters = new Parameters( alias, Parameters.AND, paramCounter );
|
||||
InnerOuterJoinParameter joinParameter = new InnerOuterJoinParameter( joinType, entityName, alias, select, joinConditionParameters );
|
||||
InnerOuterJoinParameter joinParameter = new InnerOuterJoinParameter(
|
||||
joinType,
|
||||
entityName,
|
||||
alias,
|
||||
select,
|
||||
joinConditionParameters
|
||||
);
|
||||
froms.add( joinParameter );
|
||||
return joinConditionParameters;
|
||||
}
|
||||
|
@ -140,7 +174,7 @@ public class QueryBuilder {
|
|||
* be later used as a value of a parameter.
|
||||
*/
|
||||
public QueryBuilder newSubQueryBuilder(String entityName, String alias) {
|
||||
return new QueryBuilder( entityName, alias, aliasCounter, paramCounter );
|
||||
return new QueryBuilder( entityName, alias, aliasCounter, paramCounter, sessionFactory );
|
||||
}
|
||||
|
||||
public Parameters getRootParameters() {
|
||||
|
@ -157,6 +191,10 @@ public class QueryBuilder {
|
|||
orders.add( Triple.make( alias, propertyName, ascending ) );
|
||||
}
|
||||
|
||||
public void addOrderFragment(String alias, String fragment) {
|
||||
orderFragments.add( Pair.make( alias, fragment ) );
|
||||
}
|
||||
|
||||
public void addProjection(String function, String alias, String propertyName, boolean distinct) {
|
||||
final String effectivePropertyName = propertyName == null ? "" : ".".concat( propertyName );
|
||||
if ( function == null ) {
|
||||
|
@ -209,10 +247,47 @@ public class QueryBuilder {
|
|||
}
|
||||
}
|
||||
// orders
|
||||
if ( orders.size() > 0 ) {
|
||||
if ( !orders.isEmpty() ) {
|
||||
sb.append( " order by " );
|
||||
StringTools.append( sb, getOrderList().iterator(), ", " );
|
||||
}
|
||||
else if ( !orderFragments.isEmpty() ) {
|
||||
sb.append( " order by " );
|
||||
|
||||
final Iterator<Pair<String, String>> fragmentIterator = orderFragments.iterator();
|
||||
while( fragmentIterator.hasNext() ) {
|
||||
final Pair<String, String> fragment = fragmentIterator.next();
|
||||
final OrderByTranslation orderByFragmentTranslation = Template.translateOrderBy(
|
||||
fragment.getSecond(),
|
||||
new ColumnMapper() {
|
||||
@Override
|
||||
public SqlValueReference[] map(String reference) throws HibernateException {
|
||||
return new SqlValueReference[ 0 ];
|
||||
}
|
||||
},
|
||||
sessionFactory,
|
||||
sessionFactory.getJdbcServices().getDialect(),
|
||||
sessionFactory.getSqlFunctionRegistry()
|
||||
);
|
||||
|
||||
sb.append( orderByFragmentTranslation.injectAliases( new QueryOrderByAliasResolver( fragment.getFirst() ) ) );
|
||||
if ( fragmentIterator.hasNext() ) {
|
||||
sb.append( ", " );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class QueryOrderByAliasResolver implements OrderByAliasResolver {
|
||||
private String alias;
|
||||
public QueryOrderByAliasResolver(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveTableAlias(String columnReference) {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getSelectAliasList() {
|
||||
|
@ -294,8 +369,8 @@ public class QueryBuilder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void appendJoin(final boolean firstFromElement, final StringBuilder builder, final Map<String, Object> queryParamValues) {
|
||||
if (!firstFromElement) {
|
||||
public void appendJoin(boolean firstFromElement, StringBuilder builder, Map<String, Object> queryParamValues) {
|
||||
if ( !firstFromElement ) {
|
||||
builder.append( ", " );
|
||||
}
|
||||
builder.append( entityName ).append( ' ' ).append( getAlias() );
|
||||
|
@ -309,7 +384,12 @@ public class QueryBuilder {
|
|||
private final String entityName;
|
||||
private final Parameters joinConditionParameters;
|
||||
|
||||
public InnerOuterJoinParameter(JoinType joinType, String entityName, String alias, boolean select, Parameters joinConditionParameters) {
|
||||
public InnerOuterJoinParameter(
|
||||
JoinType joinType,
|
||||
String entityName,
|
||||
String alias,
|
||||
boolean select,
|
||||
Parameters joinConditionParameters) {
|
||||
super(alias, select);
|
||||
this.joinType = joinType;
|
||||
this.entityName = entityName;
|
||||
|
|
|
@ -86,7 +86,7 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
|||
}
|
||||
aliasToEntityNameMap.put( REFERENCED_ENTITY_ALIAS, entityName );
|
||||
|
||||
qb = new QueryBuilder( versionsEntityName, REFERENCED_ENTITY_ALIAS );
|
||||
qb = new QueryBuilder( versionsEntityName, REFERENCED_ENTITY_ALIAS, versionsReader.getSessionImplementor().getFactory() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,7 +95,7 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
|||
}
|
||||
|
||||
protected Query buildQuery() {
|
||||
Query query = qb.toQuery( versionsReader.getSession() );
|
||||
Query query = qb.toQuery( versionsReader.getSessionImplementor() );
|
||||
setQueryProperties( query );
|
||||
return query;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ import java.util.Map;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||
|
@ -241,7 +241,11 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
|||
String propertyName,
|
||||
AuditEntitiesConfiguration auditEntitiesConfiguration,
|
||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
||||
final QueryBuilder qb = new QueryBuilder( persistentCollectionChangeData.getEntityName(), MIDDLE_ENTITY_ALIAS );
|
||||
final QueryBuilder qb = new QueryBuilder(
|
||||
persistentCollectionChangeData.getEntityName(),
|
||||
MIDDLE_ENTITY_ALIAS,
|
||||
( (SharedSessionContractImplementor) session ).getFactory()
|
||||
);
|
||||
|
||||
final String originalIdPropName = auditEntitiesConfiguration.getOriginalIdPropName();
|
||||
final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
|
||||
|
|
Loading…
Reference in New Issue