mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-22 11:06:08 +00:00
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.ReflectionTools;
|
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||||
import org.hibernate.envers.internal.tools.StringTools;
|
import org.hibernate.envers.internal.tools.StringTools;
|
||||||
import org.hibernate.envers.internal.tools.Tools;
|
import org.hibernate.envers.internal.tools.Tools;
|
||||||
|
import org.hibernate.mapping.Bag;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.IndexedCollection;
|
import org.hibernate.mapping.IndexedCollection;
|
||||||
@ -237,7 +238,8 @@ private void addOneToManyAttached(boolean fakeOneToManyBidirectional) {
|
|||||||
referencedIdData,
|
referencedIdData,
|
||||||
isEmbeddableElementType(),
|
isEmbeddableElementType(),
|
||||||
mappedBy,
|
mappedBy,
|
||||||
isMappedByKey( propertyValue, mappedBy )
|
isMappedByKey( propertyValue, mappedBy ),
|
||||||
|
propertyValue.getOrderBy()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Creating common mapper data.
|
// Creating common mapper data.
|
||||||
@ -290,7 +292,15 @@ else if ( indexed ) {
|
|||||||
|
|
||||||
// Checking if there's an index defined. If so, adding a mapper for it.
|
// Checking if there's an index defined. If so, adding a mapper for it.
|
||||||
if ( positionMappedBy != null ) {
|
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(
|
fakeBidirectionalRelationIndexMapper = new SinglePropertyMapper(
|
||||||
PropertyData.forProperty( positionMappedBy, indexType )
|
PropertyData.forProperty( positionMappedBy, indexType )
|
||||||
);
|
);
|
||||||
@ -451,7 +461,10 @@ private void addWithMiddleTable() {
|
|||||||
mainGenerator.getAuditStrategy(),
|
mainGenerator.getAuditStrategy(),
|
||||||
referencingIdData,
|
referencingIdData,
|
||||||
auditMiddleEntityName,
|
auditMiddleEntityName,
|
||||||
isRevisionTypeInId()
|
isRevisionTypeInId(),
|
||||||
|
propertyValue.getOrderBy() == null
|
||||||
|
? propertyValue.getManyToManyOrdering()
|
||||||
|
: propertyValue.getOrderBy()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
|
// 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 String auditMiddleEntityName;
|
||||||
private final List<MiddleIdData> idDatas;
|
private final List<MiddleIdData> idDatas;
|
||||||
private final boolean revisionTypeInId;
|
private final boolean revisionTypeInId;
|
||||||
|
private final String orderBy;
|
||||||
|
|
||||||
QueryGeneratorBuilder(
|
QueryGeneratorBuilder(
|
||||||
GlobalConfiguration globalCfg,
|
GlobalConfiguration globalCfg,
|
||||||
@ -43,12 +44,14 @@ public final class QueryGeneratorBuilder {
|
|||||||
AuditStrategy auditStrategy,
|
AuditStrategy auditStrategy,
|
||||||
MiddleIdData referencingIdData,
|
MiddleIdData referencingIdData,
|
||||||
String auditMiddleEntityName,
|
String auditMiddleEntityName,
|
||||||
boolean revisionTypeInId) {
|
boolean revisionTypeInId,
|
||||||
|
String orderBy) {
|
||||||
this.globalCfg = globalCfg;
|
this.globalCfg = globalCfg;
|
||||||
this.verEntCfg = verEntCfg;
|
this.verEntCfg = verEntCfg;
|
||||||
this.auditStrategy = auditStrategy;
|
this.auditStrategy = auditStrategy;
|
||||||
this.referencingIdData = referencingIdData;
|
this.referencingIdData = referencingIdData;
|
||||||
this.auditMiddleEntityName = auditMiddleEntityName;
|
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||||
|
this.orderBy = orderBy;
|
||||||
this.revisionTypeInId = revisionTypeInId;
|
this.revisionTypeInId = revisionTypeInId;
|
||||||
|
|
||||||
idDatas = new ArrayList<>();
|
idDatas = new ArrayList<>();
|
||||||
@ -61,7 +64,7 @@ void addRelation(MiddleIdData idData) {
|
|||||||
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
|
||||||
if ( idDatas.size() == 0 ) {
|
if ( idDatas.size() == 0 ) {
|
||||||
return new OneEntityQueryGenerator(
|
return new OneEntityQueryGenerator(
|
||||||
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
revisionTypeInId, componentDatas
|
revisionTypeInId, componentDatas
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -69,13 +72,13 @@ else if ( idDatas.size() == 1 ) {
|
|||||||
if ( idDatas.get( 0 ).isAudited() ) {
|
if ( idDatas.get( 0 ).isAudited() ) {
|
||||||
return new TwoEntityQueryGenerator(
|
return new TwoEntityQueryGenerator(
|
||||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
idDatas.get( 0 ), revisionTypeInId, orderBy, componentDatas
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new TwoEntityOneAuditedQueryGenerator(
|
return new TwoEntityOneAuditedQueryGenerator(
|
||||||
verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
idDatas.get( 0 ), revisionTypeInId, componentDatas
|
idDatas.get( 0 ), revisionTypeInId, orderBy, componentDatas
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,10 +89,9 @@ else if ( idDatas.size() == 2 ) {
|
|||||||
"Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported."
|
"Ternary relations using @Audited(targetAuditMode = NOT_AUDITED) are not supported."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ThreeEntityQueryGenerator(
|
return new ThreeEntityQueryGenerator(
|
||||||
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
globalCfg, verEntCfg, auditStrategy, auditMiddleEntityName, referencingIdData,
|
||||||
idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, componentDatas
|
idDatas.get( 0 ), idDatas.get( 1 ), revisionTypeInId, orderBy, componentDatas
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
||||||
@ -46,7 +47,8 @@ public AbstractCollectionInitializor(
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T initialize() {
|
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() );
|
final T collection = initializeCollection( collectionContent.size() );
|
||||||
|
|
||||||
|
@ -9,12 +9,17 @@
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
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.RevisionType;
|
||||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
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.id.QueryParameterData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
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.internal.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
|
||||||
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.DEL_REVISION_TYPE_PARAMETER;
|
||||||
@ -27,57 +32,127 @@
|
|||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractRelationQueryGenerator implements RelationQueryGenerator {
|
public abstract class AbstractRelationQueryGenerator implements RelationQueryGenerator {
|
||||||
|
protected final GlobalConfiguration globalCfg;
|
||||||
protected final AuditEntitiesConfiguration verEntCfg;
|
protected final AuditEntitiesConfiguration verEntCfg;
|
||||||
|
protected final AuditStrategy auditStrategy;
|
||||||
protected final MiddleIdData referencingIdData;
|
protected final MiddleIdData referencingIdData;
|
||||||
protected final boolean revisionTypeInId;
|
protected final boolean revisionTypeInId;
|
||||||
|
protected final String entityName;
|
||||||
|
protected final String orderBy;
|
||||||
|
|
||||||
|
private String queryString;
|
||||||
|
private String queryRemovedString;
|
||||||
|
|
||||||
protected AbstractRelationQueryGenerator(
|
protected AbstractRelationQueryGenerator(
|
||||||
|
GlobalConfiguration globalCfg,
|
||||||
AuditEntitiesConfiguration verEntCfg,
|
AuditEntitiesConfiguration verEntCfg,
|
||||||
|
AuditStrategy auditStrategy,
|
||||||
|
String entityName,
|
||||||
MiddleIdData referencingIdData,
|
MiddleIdData referencingIdData,
|
||||||
boolean revisionTypeInId) {
|
boolean revisionTypeInId,
|
||||||
|
String orderBy) {
|
||||||
|
this.globalCfg = globalCfg;
|
||||||
this.verEntCfg = verEntCfg;
|
this.verEntCfg = verEntCfg;
|
||||||
|
this.entityName = entityName;
|
||||||
|
this.auditStrategy = auditStrategy;
|
||||||
this.referencingIdData = referencingIdData;
|
this.referencingIdData = referencingIdData;
|
||||||
this.revisionTypeInId = revisionTypeInId;
|
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
|
@Override
|
||||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision, boolean removed) {
|
public Query getQuery(SharedSessionContractImplementor session, Object primaryKey, Number revision, boolean removed) {
|
||||||
final Query query = versionsReader.getSession().createQuery( removed ? getQueryRemovedString() : getQueryString() );
|
final String queryString = getQueryString( session.getFactory(), removed );
|
||||||
|
|
||||||
|
final Query query = session.createQuery( queryString );
|
||||||
query.setParameter( DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL );
|
query.setParameter( DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL );
|
||||||
query.setParameter( REVISION_PARAMETER, revision );
|
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 );
|
paramData.setParameterValue( query );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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() );
|
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();
|
final StringBuilder sb = new StringBuilder();
|
||||||
query.build( sb, queryParamValues );
|
query.build( sb, queryParamValues );
|
||||||
return sb.toString();
|
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;
|
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.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||||
import org.hibernate.envers.internal.entities.mapper.id.AbstractCompositeIdMapper;
|
import org.hibernate.envers.internal.entities.mapper.id.AbstractCompositeIdMapper;
|
||||||
@ -14,6 +15,7 @@
|
|||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
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.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.REFERENCED_ENTITY_ALIAS;
|
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.REFERENCED_ENTITY_ALIAS;
|
||||||
@ -28,10 +30,9 @@
|
|||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
|
||||||
private final String queryRemovedString;
|
|
||||||
private final String mappedBy;
|
private final String mappedBy;
|
||||||
private final boolean multipleIdMapperKey;
|
private final boolean multipleIdMapperKey;
|
||||||
|
private final MiddleIdData referencedIdData;
|
||||||
|
|
||||||
public OneAuditEntityQueryGenerator(
|
public OneAuditEntityQueryGenerator(
|
||||||
GlobalConfiguration globalCfg,
|
GlobalConfiguration globalCfg,
|
||||||
@ -42,10 +43,20 @@ public OneAuditEntityQueryGenerator(
|
|||||||
MiddleIdData referencedIdData,
|
MiddleIdData referencedIdData,
|
||||||
boolean revisionTypeInId,
|
boolean revisionTypeInId,
|
||||||
String mappedBy,
|
String mappedBy,
|
||||||
boolean mappedByKey) {
|
boolean mappedByKey,
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
String orderBy) {
|
||||||
|
super(
|
||||||
|
globalCfg,
|
||||||
|
verEntCfg,
|
||||||
|
auditStrategy,
|
||||||
|
verEntCfg.getAuditEntityName( referencedEntityName ),
|
||||||
|
referencingIdData,
|
||||||
|
revisionTypeInId,
|
||||||
|
orderBy
|
||||||
|
);
|
||||||
|
|
||||||
this.mappedBy = mappedBy;
|
this.mappedBy = mappedBy;
|
||||||
|
this.referencedIdData = referencedIdData;
|
||||||
|
|
||||||
// HHH-11770 We use AbstractCompositeIdMapper here to handle EmbeddedIdMapper and MultipleIdMappper support
|
// HHH-11770 We use AbstractCompositeIdMapper here to handle EmbeddedIdMapper and MultipleIdMappper support
|
||||||
// so that OneAuditEntityQueryGenerator supports mappings to both @IdClass and @EmbeddedId components.
|
// so that OneAuditEntityQueryGenerator supports mappings to both @IdClass and @EmbeddedId components.
|
||||||
@ -74,24 +85,12 @@ public OneAuditEntityQueryGenerator(
|
|||||||
* (only non-deleted entities)
|
* (only non-deleted entities)
|
||||||
* e.revision_type != DEL
|
* 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Compute common part for both queries.
|
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||||
*/
|
|
||||||
private QueryBuilder commonQueryPart(String versionsReferencedEntityName) {
|
|
||||||
// SELECT e FROM versionsEntity e
|
// 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 );
|
qb.addProjection( null, REFERENCED_ENTITY_ALIAS, null, false );
|
||||||
// WHERE
|
// WHERE
|
||||||
if ( multipleIdMapperKey ) {
|
if ( multipleIdMapperKey ) {
|
||||||
@ -105,57 +104,53 @@ private QueryBuilder commonQueryPart(String versionsReferencedEntityName) {
|
|||||||
// e.id_ref_ed = :id_ref_ed
|
// e.id_ref_ed = :id_ref_ed
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( qb.getRootParameters(), null, true );
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( qb.getRootParameters(), null, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ORDER BY
|
||||||
|
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||||
|
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||||
|
}
|
||||||
|
|
||||||
return qb;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Creates query restrictions used to retrieve only actual data.
|
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||||
*/
|
|
||||||
private void createValidDataRestrictions(
|
|
||||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
|
||||||
MiddleIdData referencedIdData, QueryBuilder qb, Parameters rootParameters) {
|
|
||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
// (selecting e entities at revision :revision)
|
// (selecting e entities at revision :revision)
|
||||||
// --> based on auditStrategy (see above)
|
// --> based on auditStrategy (see above)
|
||||||
auditStrategy.addEntityAtRevisionRestriction(
|
auditStrategy.addEntityAtRevisionRestriction(
|
||||||
globalCfg, qb, rootParameters, revisionPropertyPath,
|
globalCfg,
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData, revisionPropertyPath,
|
qb,
|
||||||
verEntCfg.getOriginalIdPropName(), REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
rootParameters,
|
||||||
|
revisionPropertyPath,
|
||||||
|
verEntCfg.getRevisionEndFieldName(),
|
||||||
|
true,
|
||||||
|
referencedIdData,
|
||||||
|
revisionPropertyPath,
|
||||||
|
verEntCfg.getOriginalIdPropName(),
|
||||||
|
REFERENCED_ENTITY_ALIAS,
|
||||||
|
REFERENCED_ENTITY_ALIAS_DEF_AUD_STR,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
// e.revision_type != DEL
|
// e.revision_type != DEL
|
||||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||||
*/
|
|
||||||
private void createValidAndRemovedDataRestrictions(
|
|
||||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
|
||||||
MiddleIdData referencedIdData, QueryBuilder remQb) {
|
|
||||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
// Restrictions to match all valid rows.
|
// Restrictions to match all valid rows.
|
||||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||||
// Restrictions to match all rows deleted at exactly given revision.
|
// Restrictions to match all rows deleted at exactly given revision.
|
||||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||||
// Excluding current revision, because we need to match data valid at the previous one.
|
// 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
|
// e.revision = :revision
|
||||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), false, "=", REVISION_PARAMETER );
|
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), false, "=", REVISION_PARAMETER );
|
||||||
// e.revision_type = DEL
|
// e.revision_type = DEL
|
||||||
removed.addWhereWithNamedParam( getRevisionTypePath(), false, "=", DEL_REVISION_TYPE_PARAMETER );
|
removed.addWhereWithNamedParam( getRevisionTypePath(), false, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getQueryString() {
|
|
||||||
return queryString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getQueryRemovedString() {
|
|
||||||
return queryRemovedString;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IdMapper getMultipleIdPrefixedMapper() {
|
private IdMapper getMultipleIdPrefixedMapper() {
|
||||||
final String prefix = verEntCfg.getOriginalIdPropName() + "." + mappedBy + ".";
|
final String prefix = verEntCfg.getOriginalIdPropName() + "." + mappedBy + ".";
|
||||||
return referencingIdData.getOriginalMapper().prefixMappedProperties( prefix );
|
return referencingIdData.getOriginalMapper().prefixMappedProperties( prefix );
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation.query;
|
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.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.MiddleComponentData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
@ -22,16 +24,30 @@
|
|||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final MiddleComponentData[] componentDatas;
|
||||||
private final String queryRemovedString;
|
|
||||||
|
|
||||||
public OneEntityQueryGenerator(
|
public OneEntityQueryGenerator(
|
||||||
AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
GlobalConfiguration globalCfg,
|
||||||
String versionsMiddleEntityName, MiddleIdData referencingIdData,
|
AuditEntitiesConfiguration verEntCfg,
|
||||||
boolean revisionTypeInId, MiddleComponentData... componentData) {
|
AuditStrategy auditStrategy,
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
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:
|
* The valid query that we need to create:
|
||||||
@ -52,24 +68,12 @@ public OneEntityQueryGenerator(
|
|||||||
* (only non-deleted entities and associations)
|
* (only non-deleted entities and associations)
|
||||||
* ee.revision_type != DEL
|
* 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Compute common part for both queries.
|
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||||
*/
|
|
||||||
private QueryBuilder commonQueryPart(String versionsMiddleEntityName) {
|
|
||||||
// SELECT ee FROM middleEntity ee
|
// 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 );
|
qb.addProjection( null, MIDDLE_ENTITY_ALIAS, null, false );
|
||||||
// WHERE
|
// WHERE
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
@ -78,56 +82,55 @@ private QueryBuilder commonQueryPart(String versionsMiddleEntityName) {
|
|||||||
verEntCfg.getOriginalIdPropName(),
|
verEntCfg.getOriginalIdPropName(),
|
||||||
true
|
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;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Creates query restrictions used to retrieve only actual data.
|
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||||
*/
|
|
||||||
private void createValidDataRestrictions(
|
|
||||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
|
||||||
QueryBuilder qb, Parameters rootParameters, boolean inclusive,
|
|
||||||
MiddleComponentData... componentData) {
|
|
||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// (with ee association at revision :revision)
|
// (with ee association at revision :revision)
|
||||||
// --> based on auditStrategy (see above)
|
// --> based on auditStrategy (see above)
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(
|
auditStrategy.addAssociationAtRevisionRestriction(
|
||||||
qb, rootParameters, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true,
|
qb,
|
||||||
referencingIdData, versionsMiddleEntityName, eeOriginalIdPropertyPath, revisionPropertyPath,
|
rootParameters,
|
||||||
originalIdPropertyName, MIDDLE_ENTITY_ALIAS, inclusive, componentData
|
revisionPropertyPath,
|
||||||
|
verEntCfg.getRevisionEndFieldName(),
|
||||||
|
true,
|
||||||
|
referencingIdData,
|
||||||
|
entityName,
|
||||||
|
eeOriginalIdPropertyPath,
|
||||||
|
revisionPropertyPath,
|
||||||
|
originalIdPropertyName,
|
||||||
|
MIDDLE_ENTITY_ALIAS,
|
||||||
|
inclusive,
|
||||||
|
componentDatas
|
||||||
);
|
);
|
||||||
// ee.revision_type != DEL
|
// ee.revision_type != DEL
|
||||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||||
*/
|
|
||||||
private void createValidAndRemovedDataRestrictions(
|
|
||||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
|
||||||
QueryBuilder remQb, MiddleComponentData... componentData) {
|
|
||||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
// Restrictions to match all valid rows.
|
// Restrictions to match all valid rows.
|
||||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||||
// Restrictions to match all rows deleted at exactly given revision.
|
// Restrictions to match all rows deleted at exactly given revision.
|
||||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||||
// Excluding current revision, because we need to match data valid at the previous one.
|
// 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
|
// ee.revision = :revision
|
||||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
||||||
// ee.revision_type = DEL
|
// ee.revision_type = DEL
|
||||||
removed.addWhereWithNamedParam( getRevisionTypePath(), "=", DEL_REVISION_TYPE_PARAMETER );
|
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;
|
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;
|
import org.hibernate.query.Query;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: cleanup implementations and extract common code
|
* Implementations of this interface provide a method to generate queries on a
|
||||||
* <p/>
|
* relation table (a table used for mapping relations). The query can select,
|
||||||
* Implementations of this interface provide a method to generate queries on a relation table (a table used
|
* apart from selecting the content of the relation table, also data of other
|
||||||
* for mapping relations). The query can select, apart from selecting the content of the relation table, also data of
|
* "related" entities.
|
||||||
* other "related" entities.
|
|
||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public interface RelationQueryGenerator {
|
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;
|
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.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||||
@ -13,6 +14,7 @@
|
|||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
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.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.INDEX_ENTITY_ALIAS;
|
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.INDEX_ENTITY_ALIAS;
|
||||||
@ -27,18 +29,37 @@
|
|||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final MiddleIdData referencedIdData;
|
||||||
private final String queryRemovedString;
|
private final MiddleIdData indexIdData;
|
||||||
|
private final MiddleComponentData[] componentDatas;
|
||||||
|
|
||||||
public ThreeEntityQueryGenerator(
|
public ThreeEntityQueryGenerator(
|
||||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
GlobalConfiguration globalCfg,
|
||||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
AuditEntitiesConfiguration verEntCfg,
|
||||||
MiddleIdData referencingIdData, MiddleIdData referencedIdData,
|
AuditStrategy auditStrategy,
|
||||||
MiddleIdData indexIdData, boolean revisionTypeInId,
|
String versionsMiddleEntityName,
|
||||||
|
MiddleIdData referencingIdData,
|
||||||
|
MiddleIdData referencedIdData,
|
||||||
|
MiddleIdData indexIdData,
|
||||||
|
boolean revisionTypeInId,
|
||||||
|
String orderBy,
|
||||||
MiddleComponentData... componentData) {
|
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:
|
* The valid query that we need to create:
|
||||||
@ -86,35 +107,14 @@ public ThreeEntityQueryGenerator(
|
|||||||
* e.revision_type != DEL AND
|
* e.revision_type != DEL AND
|
||||||
* f.revision_type != DEL
|
* 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Compute common part for both queries.
|
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||||
*/
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
private QueryBuilder commonQueryPart(
|
|
||||||
MiddleIdData referencedIdData, MiddleIdData indexIdData,
|
|
||||||
String versionsMiddleEntityName, String originalIdPropertyName) {
|
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// SELECT new list(ee) FROM middleEntity ee
|
// 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( referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS, false );
|
||||||
qb.addFrom( indexIdData.getAuditEntityName(), INDEX_ENTITY_ALIAS, false );
|
qb.addFrom( indexIdData.getAuditEntityName(), INDEX_ENTITY_ALIAS, false );
|
||||||
qb.addProjection(
|
qb.addProjection(
|
||||||
@ -135,16 +135,18 @@ private QueryBuilder commonQueryPart(
|
|||||||
);
|
);
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
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;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Creates query restrictions used to retrieve only actual data.
|
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||||
*/
|
|
||||||
private void createValidDataRestrictions(
|
|
||||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
|
||||||
MiddleIdData referencedIdData, String versionsMiddleEntityName, QueryBuilder qb,
|
|
||||||
Parameters rootParameters, boolean inclusive, MiddleIdData indexIdData, MiddleComponentData... componentData) {
|
|
||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
@ -184,9 +186,19 @@ private void createValidDataRestrictions(
|
|||||||
// (with ee association at revision :revision)
|
// (with ee association at revision :revision)
|
||||||
// --> based on auditStrategy (see above)
|
// --> based on auditStrategy (see above)
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(
|
auditStrategy.addAssociationAtRevisionRestriction(
|
||||||
qb, rootParameters, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true,
|
qb,
|
||||||
referencingIdData, versionsMiddleEntityName, eeOriginalIdPropertyPath, revisionPropertyPath,
|
rootParameters,
|
||||||
originalIdPropertyName, MIDDLE_ENTITY_ALIAS, inclusive, componentData
|
revisionPropertyPath,
|
||||||
|
verEntCfg.getRevisionEndFieldName(),
|
||||||
|
true,
|
||||||
|
referencingIdData,
|
||||||
|
entityName,
|
||||||
|
eeOriginalIdPropertyPath,
|
||||||
|
revisionPropertyPath,
|
||||||
|
originalIdPropertyName,
|
||||||
|
MIDDLE_ENTITY_ALIAS,
|
||||||
|
inclusive,
|
||||||
|
componentDatas
|
||||||
);
|
);
|
||||||
// ee.revision_type != DEL
|
// ee.revision_type != DEL
|
||||||
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
@ -206,13 +218,8 @@ private void createValidDataRestrictions(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||||
*/
|
|
||||||
private void createValidAndRemovedDataRestrictions(
|
|
||||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
|
||||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
|
||||||
QueryBuilder remQb, MiddleIdData indexIdData, MiddleComponentData... componentData) {
|
|
||||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
// Restrictions to match all valid rows.
|
// Restrictions to match all valid rows.
|
||||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||||
@ -221,9 +228,7 @@ private void createValidAndRemovedDataRestrictions(
|
|||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
final String revisionTypePropName = getRevisionTypePath();
|
final String revisionTypePropName = getRevisionTypePath();
|
||||||
// Excluding current revision, because we need to match data valid at the previous one.
|
// Excluding current revision, because we need to match data valid at the previous one.
|
||||||
createValidDataRestrictions(
|
applyValidPredicates( remQb, valid, false );
|
||||||
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, remQb, valid, false, indexIdData, componentData
|
|
||||||
);
|
|
||||||
// ee.revision = :revision
|
// ee.revision = :revision
|
||||||
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
||||||
// e.revision = :revision
|
// e.revision = :revision
|
||||||
@ -257,14 +262,4 @@ private void createValidAndRemovedDataRestrictions(
|
|||||||
DEL_REVISION_TYPE_PARAMETER
|
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;
|
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.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.MiddleComponentData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
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.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||||
@ -23,17 +26,34 @@
|
|||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final MiddleIdData referencedIdData;
|
||||||
private final String queryRemovedString;
|
private final MiddleComponentData[] componentDatas;
|
||||||
|
|
||||||
public TwoEntityOneAuditedQueryGenerator(
|
public TwoEntityOneAuditedQueryGenerator(
|
||||||
AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
GlobalConfiguration globalCfg,
|
||||||
String versionsMiddleEntityName, MiddleIdData referencingIdData,
|
AuditEntitiesConfiguration verEntCfg,
|
||||||
MiddleIdData referencedIdData, boolean revisionTypeInId,
|
AuditStrategy auditStrategy,
|
||||||
|
String versionsMiddleEntityName,
|
||||||
|
MiddleIdData referencingIdData,
|
||||||
|
MiddleIdData referencedIdData,
|
||||||
|
boolean revisionTypeInId,
|
||||||
|
String orderBy,
|
||||||
MiddleComponentData... componentData) {
|
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:
|
* The valid query that we need to create:
|
||||||
@ -57,31 +77,14 @@ public TwoEntityOneAuditedQueryGenerator(
|
|||||||
* (only non-deleted entities and associations)
|
* (only non-deleted entities and associations)
|
||||||
* ee.revision_type != DEL
|
* 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Compute common part for both queries.
|
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||||
*/
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
private QueryBuilder commonQueryPart(
|
|
||||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
|
||||||
String originalIdPropertyName) {
|
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// SELECT new list(ee) FROM middleEntity ee
|
// 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.addFrom( referencedIdData.getEntityName(), REFERENCED_ENTITY_ALIAS, false );
|
||||||
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, null, false );
|
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, null, false );
|
||||||
// WHERE
|
// WHERE
|
||||||
@ -92,54 +95,53 @@ private QueryBuilder commonQueryPart(
|
|||||||
);
|
);
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||||
|
// ORDER BY
|
||||||
|
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||||
|
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||||
|
}
|
||||||
return qb;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates query restrictions used to retrieve only actual data.
|
* Creates query restrictions used to retrieve only actual data.
|
||||||
*/
|
*/
|
||||||
private void createValidDataRestrictions(
|
@Override
|
||||||
AuditStrategy auditStrategy, String versionsMiddleEntityName, QueryBuilder qb,
|
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||||
Parameters rootParameters, MiddleComponentData... componentData) {
|
|
||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// (with ee association at revision :revision)
|
// (with ee association at revision :revision)
|
||||||
// --> based on auditStrategy (see above)
|
// --> based on auditStrategy (see above)
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(
|
auditStrategy.addAssociationAtRevisionRestriction(
|
||||||
qb, rootParameters, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true,
|
qb,
|
||||||
referencingIdData, versionsMiddleEntityName, eeOriginalIdPropertyPath, revisionPropertyPath,
|
rootParameters,
|
||||||
originalIdPropertyName, MIDDLE_ENTITY_ALIAS, true, componentData
|
revisionPropertyPath,
|
||||||
|
verEntCfg.getRevisionEndFieldName(),
|
||||||
|
true,
|
||||||
|
referencingIdData,
|
||||||
|
entityName,
|
||||||
|
eeOriginalIdPropertyPath,
|
||||||
|
revisionPropertyPath,
|
||||||
|
originalIdPropertyName,
|
||||||
|
MIDDLE_ENTITY_ALIAS,
|
||||||
|
true,
|
||||||
|
componentDatas
|
||||||
);
|
);
|
||||||
// ee.revision_type != DEL
|
// ee.revision_type != DEL
|
||||||
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||||
*/
|
|
||||||
private void createValidAndRemovedDataRestrictions(
|
|
||||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
|
||||||
QueryBuilder remQb, MiddleComponentData... componentData) {
|
|
||||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
// Restrictions to match all valid rows.
|
// Restrictions to match all valid rows.
|
||||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||||
// Restrictions to match all rows deleted at exactly given revision.
|
// Restrictions to match all rows deleted at exactly given revision.
|
||||||
final Parameters removed = disjoint.addSubParameters( "and" );
|
final Parameters removed = disjoint.addSubParameters( "and" );
|
||||||
createValidDataRestrictions( auditStrategy, versionsMiddleEntityName, remQb, valid, componentData );
|
applyValidPredicates( remQb, valid, false );
|
||||||
// ee.revision = :revision
|
// ee.revision = :revision
|
||||||
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
||||||
// ee.revision_type = DEL
|
// ee.revision_type = DEL
|
||||||
removed.addWhereWithNamedParam( getRevisionTypePath(), "=", DEL_REVISION_TYPE_PARAMETER );
|
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;
|
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.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||||
@ -13,6 +15,7 @@
|
|||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
import org.hibernate.envers.internal.tools.query.QueryBuilder;
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
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.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
import static org.hibernate.envers.internal.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||||
@ -25,17 +28,34 @@
|
|||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final MiddleIdData referencedIdData;
|
||||||
private final String queryRemovedString;
|
private final MiddleComponentData[] componentDatas;
|
||||||
|
|
||||||
public TwoEntityQueryGenerator(
|
public TwoEntityQueryGenerator(
|
||||||
GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
GlobalConfiguration globalCfg,
|
||||||
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
AuditEntitiesConfiguration verEntCfg,
|
||||||
MiddleIdData referencingIdData, MiddleIdData referencedIdData,
|
AuditStrategy auditStrategy,
|
||||||
boolean revisionTypeInId, MiddleComponentData... componentData) {
|
String versionsMiddleEntityName,
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
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:
|
* The valid query that we need to create:
|
||||||
@ -68,34 +88,14 @@ public TwoEntityQueryGenerator(
|
|||||||
* ee.revision_type != DEL AND
|
* ee.revision_type != DEL AND
|
||||||
* e.revision_type != DEL
|
* 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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Compute common part for both queries.
|
protected QueryBuilder buildQueryBuilderCommon(SessionFactoryImplementor sessionFactory) {
|
||||||
*/
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
private QueryBuilder commonQueryPart(
|
|
||||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
|
||||||
String originalIdPropertyName) {
|
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// SELECT new list(ee) FROM middleEntity ee
|
// 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.addFrom( referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS, false );
|
||||||
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, null, false );
|
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, null, false );
|
||||||
// WHERE
|
// WHERE
|
||||||
@ -107,16 +107,17 @@ private QueryBuilder commonQueryPart(
|
|||||||
);
|
);
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||||
|
|
||||||
|
// ORDER BY
|
||||||
|
if ( !StringHelper.isEmpty( orderBy ) ) {
|
||||||
|
qb.addOrderFragment( REFERENCED_ENTITY_ALIAS, orderBy );
|
||||||
|
}
|
||||||
|
|
||||||
return qb;
|
return qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Creates query restrictions used to retrieve only actual data.
|
protected void applyValidPredicates(QueryBuilder qb, Parameters rootParameters, boolean inclusive) {
|
||||||
*/
|
|
||||||
private void createValidDataRestrictions(
|
|
||||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy, MiddleIdData referencedIdData,
|
|
||||||
String versionsMiddleEntityName, QueryBuilder qb, Parameters rootParameters,
|
|
||||||
boolean inclusive, MiddleComponentData... componentData) {
|
|
||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
@ -140,10 +141,19 @@ private void createValidDataRestrictions(
|
|||||||
// (with ee association at revision :revision)
|
// (with ee association at revision :revision)
|
||||||
// --> based on auditStrategy (see above)
|
// --> based on auditStrategy (see above)
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(
|
auditStrategy.addAssociationAtRevisionRestriction(
|
||||||
qb, rootParameters, revisionPropertyPath,
|
qb,
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
rootParameters,
|
||||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS,
|
revisionPropertyPath,
|
||||||
inclusive, componentData
|
verEntCfg.getRevisionEndFieldName(),
|
||||||
|
true,
|
||||||
|
referencingIdData,
|
||||||
|
entityName,
|
||||||
|
eeOriginalIdPropertyPath,
|
||||||
|
revisionPropertyPath,
|
||||||
|
originalIdPropertyName,
|
||||||
|
MIDDLE_ENTITY_ALIAS,
|
||||||
|
inclusive,
|
||||||
|
componentDatas
|
||||||
);
|
);
|
||||||
// ee.revision_type != DEL
|
// ee.revision_type != DEL
|
||||||
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
@ -156,13 +166,8 @@ private void createValidDataRestrictions(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
protected void applyValidAndRemovePredicates(QueryBuilder remQb) {
|
||||||
*/
|
|
||||||
private void createValidAndRemovedDataRestrictions(
|
|
||||||
GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
|
||||||
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
|
||||||
QueryBuilder remQb, MiddleComponentData... componentData) {
|
|
||||||
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
// Restrictions to match all valid rows.
|
// Restrictions to match all valid rows.
|
||||||
final Parameters valid = disjoint.addSubParameters( "and" );
|
final Parameters valid = disjoint.addSubParameters( "and" );
|
||||||
@ -171,15 +176,10 @@ private void createValidAndRemovedDataRestrictions(
|
|||||||
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
final String revisionTypePropName = getRevisionTypePath();
|
final String revisionTypePropName = getRevisionTypePath();
|
||||||
// Excluding current revision, because we need to match data valid at the previous one.
|
// Excluding current revision, because we need to match data valid at the previous one.
|
||||||
createValidDataRestrictions(
|
applyValidPredicates(
|
||||||
globalCfg,
|
|
||||||
auditStrategy,
|
|
||||||
referencedIdData,
|
|
||||||
versionsMiddleEntityName,
|
|
||||||
remQb,
|
remQb,
|
||||||
valid,
|
valid,
|
||||||
false,
|
false
|
||||||
componentData
|
|
||||||
);
|
);
|
||||||
// ee.revision = :revision
|
// ee.revision = :revision
|
||||||
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
||||||
@ -200,14 +200,4 @@ private void createValidAndRemovedDataRestrictions(
|
|||||||
DEL_REVISION_TYPE_PARAMETER
|
DEL_REVISION_TYPE_PARAMETER
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getQueryString() {
|
|
||||||
return queryString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getQueryRemovedString() {
|
|
||||||
return queryRemovedString;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,33 @@
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.persistence.criteria.JoinType;
|
import javax.persistence.criteria.JoinType;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Session;
|
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.RevisionType;
|
||||||
import org.hibernate.envers.internal.entities.RevisionTypeType;
|
import org.hibernate.envers.internal.entities.RevisionTypeType;
|
||||||
import org.hibernate.envers.internal.tools.MutableInteger;
|
import org.hibernate.envers.internal.tools.MutableInteger;
|
||||||
import org.hibernate.envers.internal.tools.StringTools;
|
import org.hibernate.envers.internal.tools.StringTools;
|
||||||
import org.hibernate.envers.internal.tools.Triple;
|
import org.hibernate.envers.internal.tools.Triple;
|
||||||
|
import org.hibernate.envers.tools.Pair;
|
||||||
import org.hibernate.query.Query;
|
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;
|
import org.hibernate.type.CustomType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,19 +73,30 @@ public class QueryBuilder {
|
|||||||
*/
|
*/
|
||||||
private final List<String> projections;
|
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 entityName Main entity which should be selected.
|
||||||
* @param alias Alias of the entity
|
* @param alias Alias of the entity
|
||||||
|
* @param sessionFactory Session factory
|
||||||
*/
|
*/
|
||||||
public QueryBuilder(String entityName, String alias) {
|
public QueryBuilder(String entityName, String alias, SessionFactoryImplementor sessionFactory) {
|
||||||
this( entityName, alias, new MutableInteger(), new MutableInteger() );
|
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.entityName = entityName;
|
||||||
this.alias = alias;
|
this.alias = alias;
|
||||||
this.aliasCounter = aliasCounter;
|
this.aliasCounter = aliasCounter;
|
||||||
this.paramCounter = paramCounter;
|
this.paramCounter = paramCounter;
|
||||||
|
this.sessionFactory = sessionFactory;
|
||||||
|
|
||||||
final Parameters rootParameters = new Parameters( alias, "and", paramCounter );
|
final Parameters rootParameters = new Parameters( alias, "and", paramCounter );
|
||||||
parameters.add( rootParameters );
|
parameters.add( rootParameters );
|
||||||
@ -79,6 +104,7 @@ private QueryBuilder(String entityName, String alias, MutableInteger aliasCounte
|
|||||||
froms = new ArrayList<>();
|
froms = new ArrayList<>();
|
||||||
orders = new ArrayList<>();
|
orders = new ArrayList<>();
|
||||||
projections = new ArrayList<>();
|
projections = new ArrayList<>();
|
||||||
|
orderFragments = new ArrayList<>();
|
||||||
|
|
||||||
addFrom( entityName, alias, true );
|
addFrom( entityName, alias, true );
|
||||||
}
|
}
|
||||||
@ -87,6 +113,7 @@ private QueryBuilder(String entityName, String alias, MutableInteger aliasCounte
|
|||||||
private QueryBuilder(QueryBuilder other) {
|
private QueryBuilder(QueryBuilder other) {
|
||||||
this.entityName = other.entityName;
|
this.entityName = other.entityName;
|
||||||
this.alias = other.alias;
|
this.alias = other.alias;
|
||||||
|
this.sessionFactory = other.sessionFactory;
|
||||||
this.aliasCounter = other.aliasCounter.deepCopy();
|
this.aliasCounter = other.aliasCounter.deepCopy();
|
||||||
this.paramCounter = other.paramCounter.deepCopy();
|
this.paramCounter = other.paramCounter.deepCopy();
|
||||||
for (final Parameters params : other.parameters) {
|
for (final Parameters params : other.parameters) {
|
||||||
@ -96,6 +123,7 @@ private QueryBuilder(QueryBuilder other) {
|
|||||||
froms = new ArrayList<>( other.froms );
|
froms = new ArrayList<>( other.froms );
|
||||||
orders = new ArrayList<>( other.orders );
|
orders = new ArrayList<>( other.orders );
|
||||||
projections = new ArrayList<>( other.projections );
|
projections = new ArrayList<>( other.projections );
|
||||||
|
orderFragments = new ArrayList<>( other.orderFragments );
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryBuilder deepCopy() {
|
public QueryBuilder deepCopy() {
|
||||||
@ -123,7 +151,13 @@ public void addFrom(String entityName, String alias, boolean select) {
|
|||||||
|
|
||||||
public Parameters addJoin(JoinType joinType, String entityName, String alias, boolean select) {
|
public Parameters addJoin(JoinType joinType, String entityName, String alias, boolean select) {
|
||||||
Parameters joinConditionParameters = new Parameters( alias, Parameters.AND, paramCounter );
|
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 );
|
froms.add( joinParameter );
|
||||||
return joinConditionParameters;
|
return joinConditionParameters;
|
||||||
}
|
}
|
||||||
@ -140,7 +174,7 @@ public String generateAlias() {
|
|||||||
* be later used as a value of a parameter.
|
* be later used as a value of a parameter.
|
||||||
*/
|
*/
|
||||||
public QueryBuilder newSubQueryBuilder(String entityName, String alias) {
|
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() {
|
public Parameters getRootParameters() {
|
||||||
@ -157,6 +191,10 @@ public void addOrder(String alias, String propertyName, boolean ascending) {
|
|||||||
orders.add( Triple.make( alias, propertyName, ascending ) );
|
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) {
|
public void addProjection(String function, String alias, String propertyName, boolean distinct) {
|
||||||
final String effectivePropertyName = propertyName == null ? "" : ".".concat( propertyName );
|
final String effectivePropertyName = propertyName == null ? "" : ".".concat( propertyName );
|
||||||
if ( function == null ) {
|
if ( function == null ) {
|
||||||
@ -209,10 +247,47 @@ public void build(StringBuilder sb, Map<String, Object> queryParamValues) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// orders
|
// orders
|
||||||
if ( orders.size() > 0 ) {
|
if ( !orders.isEmpty() ) {
|
||||||
sb.append( " order by " );
|
sb.append( " order by " );
|
||||||
StringTools.append( sb, getOrderList().iterator(), ", " );
|
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() {
|
private List<String> getSelectAliasList() {
|
||||||
@ -294,8 +369,8 @@ public CrossJoinParameter(String entityName, String alias, boolean select) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendJoin(final boolean firstFromElement, final StringBuilder builder, final Map<String, Object> queryParamValues) {
|
public void appendJoin(boolean firstFromElement, StringBuilder builder, Map<String, Object> queryParamValues) {
|
||||||
if (!firstFromElement) {
|
if ( !firstFromElement ) {
|
||||||
builder.append( ", " );
|
builder.append( ", " );
|
||||||
}
|
}
|
||||||
builder.append( entityName ).append( ' ' ).append( getAlias() );
|
builder.append( entityName ).append( ' ' ).append( getAlias() );
|
||||||
@ -309,7 +384,12 @@ private static class InnerOuterJoinParameter extends JoinParameter {
|
|||||||
private final String entityName;
|
private final String entityName;
|
||||||
private final Parameters joinConditionParameters;
|
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);
|
super(alias, select);
|
||||||
this.joinType = joinType;
|
this.joinType = joinType;
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
|
@ -86,7 +86,7 @@ protected AbstractAuditQuery(
|
|||||||
}
|
}
|
||||||
aliasToEntityNameMap.put( REFERENCED_ENTITY_ALIAS, entityName );
|
aliasToEntityNameMap.put( REFERENCED_ENTITY_ALIAS, entityName );
|
||||||
|
|
||||||
qb = new QueryBuilder( versionsEntityName, REFERENCED_ENTITY_ALIAS );
|
qb = new QueryBuilder( versionsEntityName, REFERENCED_ENTITY_ALIAS, versionsReader.getSessionImplementor().getFactory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -95,7 +95,7 @@ public String getAlias() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Query buildQuery() {
|
protected Query buildQuery() {
|
||||||
Query query = qb.toQuery( versionsReader.getSession() );
|
Query query = qb.toQuery( versionsReader.getSessionImplementor() );
|
||||||
setQueryProperties( query );
|
setQueryProperties( query );
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
|
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
import org.hibernate.envers.configuration.internal.GlobalConfiguration;
|
||||||
@ -241,7 +241,11 @@ public void performCollectionChange(
|
|||||||
String propertyName,
|
String propertyName,
|
||||||
AuditEntitiesConfiguration auditEntitiesConfiguration,
|
AuditEntitiesConfiguration auditEntitiesConfiguration,
|
||||||
PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
|
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 String originalIdPropName = auditEntitiesConfiguration.getOriginalIdPropName();
|
||||||
final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
|
final Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user