HHH-5845 - Lazy loading of audited entites with revision type DEL
This commit is contained in:
parent
2daa528cd1
commit
76fe91cf4a
|
@ -200,14 +200,22 @@ public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
|
||||||
|
|
||||||
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
|
protected abstract Initializor<T> getInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader, Object primaryKey,
|
AuditReaderImplementor versionsReader, Object primaryKey,
|
||||||
Number revision);
|
Number revision, boolean removed);
|
||||||
|
|
||||||
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
public void mapToEntityFromMap(AuditConfiguration verCfg, Object obj, Map data, Object primaryKey,
|
||||||
AuditReaderImplementor versionsReader, Number revision) {
|
AuditReaderImplementor versionsReader, Number revision) {
|
||||||
Setter setter = ReflectionTools.getSetter(obj.getClass(),
|
Setter setter = ReflectionTools.getSetter(obj.getClass(), commonCollectionMapperData.getCollectionReferencingPropertyData());
|
||||||
commonCollectionMapperData.getCollectionReferencingPropertyData());
|
|
||||||
try {
|
try {
|
||||||
setter.set(obj, proxyConstructor.newInstance(getInitializor(verCfg, versionsReader, primaryKey, revision)), null);
|
setter.set(
|
||||||
|
obj,
|
||||||
|
proxyConstructor.newInstance(
|
||||||
|
getInitializor(
|
||||||
|
verCfg, versionsReader, primaryKey, revision,
|
||||||
|
RevisionType.DEL.equals( data.get( verCfg.getAuditEntCfg().getRevisionTypePropName() ) )
|
||||||
|
)
|
||||||
|
),
|
||||||
|
null
|
||||||
|
);
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
throw new AuditException(e);
|
throw new AuditException(e);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
|
|
|
@ -49,9 +49,9 @@ public class BasicCollectionMapper<T extends Collection> extends AbstractCollect
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
Object primaryKey, Number revision) {
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
return new BasicCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
return new BasicCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||||
primaryKey, revision, collectionClass, elementComponentData);
|
primaryKey, revision, removed, collectionClass, elementComponentData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
||||||
|
|
|
@ -54,9 +54,9 @@ public final class ListCollectionMapper extends AbstractCollectionMapper<List> i
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Initializor<List> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
protected Initializor<List> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
Object primaryKey, Number revision) {
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
return new ListCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
return new ListCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||||
primaryKey, revision, elementComponentData, indexComponentData);
|
primaryKey, revision, removed, elementComponentData, indexComponentData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
|
|
|
@ -52,9 +52,9 @@ public class MapCollectionMapper<T extends Map> extends AbstractCollectionMapper
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
protected Initializor<T> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
Object primaryKey, Number revision) {
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
return new MapCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
return new MapCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||||
primaryKey, revision, collectionClass, elementComponentData, indexComponentData);
|
primaryKey, revision, removed, collectionClass, elementComponentData, indexComponentData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
|
||||||
|
|
|
@ -46,9 +46,9 @@ public final class SortedMapCollectionMapper extends MapCollectionMapper<SortedM
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Initializor<SortedMap> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
protected Initializor<SortedMap> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
Object primaryKey, Number revision) {
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
return new SortedMapCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
return new SortedMapCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||||
primaryKey, revision, collectionClass, elementComponentData, indexComponentData, comparator);
|
primaryKey, revision, removed, collectionClass, elementComponentData, indexComponentData, comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -46,9 +46,8 @@ public final class SortedSetCollectionMapper extends BasicCollectionMapper<Sorte
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Initializor<SortedSet> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
protected Initializor<SortedSet> getInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
Object primaryKey, Number revision) {
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
return new SortedSetCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
return new SortedSetCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
|
||||||
primaryKey, revision, collectionClass, elementComponentData, comparator);
|
primaryKey, revision, removed, collectionClass, elementComponentData, comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,18 +37,19 @@ public abstract class AbstractCollectionInitializor<T> implements Initializor<T>
|
||||||
private final AuditReaderImplementor versionsReader;
|
private final AuditReaderImplementor versionsReader;
|
||||||
private final RelationQueryGenerator queryGenerator;
|
private final RelationQueryGenerator queryGenerator;
|
||||||
private final Object primaryKey;
|
private final Object primaryKey;
|
||||||
|
|
||||||
protected final Number revision;
|
protected final Number revision;
|
||||||
|
protected final boolean removed;
|
||||||
protected final EntityInstantiator entityInstantiator;
|
protected final EntityInstantiator entityInstantiator;
|
||||||
|
|
||||||
public AbstractCollectionInitializor(AuditConfiguration verCfg,
|
public AbstractCollectionInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
RelationQueryGenerator queryGenerator,
|
RelationQueryGenerator queryGenerator,
|
||||||
Object primaryKey, Number revision) {
|
Object primaryKey, Number revision, boolean removed) {
|
||||||
this.versionsReader = versionsReader;
|
this.versionsReader = versionsReader;
|
||||||
this.queryGenerator = queryGenerator;
|
this.queryGenerator = queryGenerator;
|
||||||
this.primaryKey = primaryKey;
|
this.primaryKey = primaryKey;
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
|
this.removed = removed;
|
||||||
|
|
||||||
entityInstantiator = new EntityInstantiator(verCfg, versionsReader);
|
entityInstantiator = new EntityInstantiator(verCfg, versionsReader);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +59,7 @@ public abstract class AbstractCollectionInitializor<T> implements Initializor<T>
|
||||||
protected abstract void addToCollection(T collection, Object collectionRow);
|
protected abstract void addToCollection(T collection, Object collectionRow);
|
||||||
|
|
||||||
public T initialize() {
|
public T initialize() {
|
||||||
List<?> collectionContent = queryGenerator.getQuery(versionsReader, primaryKey, revision).list();
|
List<?> collectionContent = queryGenerator.getQuery(versionsReader, primaryKey, revision, removed).list();
|
||||||
|
|
||||||
T collection = initializeCollection(collectionContent.size());
|
T collection = initializeCollection(collectionContent.size());
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,10 @@ public class ArrayCollectionInitializor extends AbstractCollectionInitializor<Ob
|
||||||
public ArrayCollectionInitializor(AuditConfiguration verCfg,
|
public ArrayCollectionInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
RelationQueryGenerator queryGenerator,
|
RelationQueryGenerator queryGenerator,
|
||||||
Object primaryKey, Number revision,
|
Object primaryKey, Number revision, boolean removed,
|
||||||
MiddleComponentData elementComponentData,
|
MiddleComponentData elementComponentData,
|
||||||
MiddleComponentData indexComponentData) {
|
MiddleComponentData indexComponentData) {
|
||||||
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
|
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, removed);
|
||||||
|
|
||||||
this.elementComponentData = elementComponentData;
|
this.elementComponentData = elementComponentData;
|
||||||
this.indexComponentData = indexComponentData;
|
this.indexComponentData = indexComponentData;
|
||||||
|
|
|
@ -46,10 +46,10 @@ public class BasicCollectionInitializor<T extends Collection> extends AbstractCo
|
||||||
public BasicCollectionInitializor(AuditConfiguration verCfg,
|
public BasicCollectionInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
RelationQueryGenerator queryGenerator,
|
RelationQueryGenerator queryGenerator,
|
||||||
Object primaryKey, Number revision,
|
Object primaryKey, Number revision, boolean removed,
|
||||||
Class<? extends T> collectionClass,
|
Class<? extends T> collectionClass,
|
||||||
MiddleComponentData elementComponentData) {
|
MiddleComponentData elementComponentData) {
|
||||||
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
|
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, removed);
|
||||||
|
|
||||||
this.collectionClass = collectionClass;
|
this.collectionClass = collectionClass;
|
||||||
this.elementComponentData = elementComponentData;
|
this.elementComponentData = elementComponentData;
|
||||||
|
|
|
@ -42,10 +42,10 @@ public class ListCollectionInitializor extends AbstractCollectionInitializor<Lis
|
||||||
public ListCollectionInitializor(AuditConfiguration verCfg,
|
public ListCollectionInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
RelationQueryGenerator queryGenerator,
|
RelationQueryGenerator queryGenerator,
|
||||||
Object primaryKey, Number revision,
|
Object primaryKey, Number revision, boolean removed,
|
||||||
MiddleComponentData elementComponentData,
|
MiddleComponentData elementComponentData,
|
||||||
MiddleComponentData indexComponentData) {
|
MiddleComponentData indexComponentData) {
|
||||||
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
|
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, removed);
|
||||||
|
|
||||||
this.elementComponentData = elementComponentData;
|
this.elementComponentData = elementComponentData;
|
||||||
this.indexComponentData = indexComponentData;
|
this.indexComponentData = indexComponentData;
|
||||||
|
|
|
@ -46,11 +46,11 @@ public class MapCollectionInitializor<T extends Map> extends AbstractCollectionI
|
||||||
public MapCollectionInitializor(AuditConfiguration verCfg,
|
public MapCollectionInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
RelationQueryGenerator queryGenerator,
|
RelationQueryGenerator queryGenerator,
|
||||||
Object primaryKey, Number revision,
|
Object primaryKey, Number revision, boolean removed,
|
||||||
Class<? extends T> collectionClass,
|
Class<? extends T> collectionClass,
|
||||||
MiddleComponentData elementComponentData,
|
MiddleComponentData elementComponentData,
|
||||||
MiddleComponentData indexComponentData) {
|
MiddleComponentData indexComponentData) {
|
||||||
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
|
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, removed);
|
||||||
|
|
||||||
this.collectionClass = collectionClass;
|
this.collectionClass = collectionClass;
|
||||||
this.elementComponentData = elementComponentData;
|
this.elementComponentData = elementComponentData;
|
||||||
|
|
|
@ -44,11 +44,11 @@ public class SortedMapCollectionInitializor extends MapCollectionInitializor<Sor
|
||||||
public SortedMapCollectionInitializor(AuditConfiguration verCfg,
|
public SortedMapCollectionInitializor(AuditConfiguration verCfg,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
RelationQueryGenerator queryGenerator,
|
RelationQueryGenerator queryGenerator,
|
||||||
Object primaryKey, Number revision,
|
Object primaryKey, Number revision, boolean removed,
|
||||||
Class<? extends SortedMap> collectionClass,
|
Class<? extends SortedMap> collectionClass,
|
||||||
MiddleComponentData elementComponentData,
|
MiddleComponentData elementComponentData,
|
||||||
MiddleComponentData indexComponentData, Comparator comparator) {
|
MiddleComponentData indexComponentData, Comparator comparator) {
|
||||||
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, collectionClass, elementComponentData, indexComponentData);
|
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, removed, collectionClass, elementComponentData, indexComponentData);
|
||||||
this.comparator = comparator;
|
this.comparator = comparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,11 @@ import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||||
public class SortedSetCollectionInitializor extends BasicCollectionInitializor<SortedSet> {
|
public class SortedSetCollectionInitializor extends BasicCollectionInitializor<SortedSet> {
|
||||||
private final Comparator comparator;
|
private final Comparator comparator;
|
||||||
|
|
||||||
public SortedSetCollectionInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader, RelationQueryGenerator queryGenerator, Object primaryKey, Number revision, Class<? extends SortedSet> collectionClass, MiddleComponentData elementComponentData, Comparator comparator) {
|
public SortedSetCollectionInitializor(AuditConfiguration verCfg, AuditReaderImplementor versionsReader,
|
||||||
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, collectionClass, elementComponentData);
|
RelationQueryGenerator queryGenerator, Object primaryKey, Number revision, boolean removed,
|
||||||
|
Class<? extends SortedSet> collectionClass, MiddleComponentData elementComponentData,
|
||||||
|
Comparator comparator) {
|
||||||
|
super(verCfg, versionsReader, queryGenerator, primaryKey, revision, removed, collectionClass, elementComponentData);
|
||||||
this.comparator = comparator;
|
this.comparator = comparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,16 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.entities.mapper.relation.query;
|
package org.hibernate.envers.entities.mapper.relation.query;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.Query;
|
import org.hibernate.Query;
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REVISION_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REVISION_PARAMETER;
|
||||||
|
@ -50,12 +54,22 @@ public abstract class AbstractRelationQueryGenerator implements RelationQueryGen
|
||||||
this.revisionTypeInId = revisionTypeInId;
|
this.revisionTypeInId = revisionTypeInId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Query used to retrieve state of audited entity valid at a given revision.
|
||||||
|
*/
|
||||||
protected abstract String getQueryString();
|
protected abstract String getQueryString();
|
||||||
|
|
||||||
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision) {
|
/**
|
||||||
Query query = versionsReader.getSession().createQuery( getQueryString() );
|
* @return Query executed to retrieve state of audited entity valid at previous revision
|
||||||
query.setParameter( REVISION_PARAMETER, revision );
|
* or removed during exactly specified revision number. Used only when traversing deleted
|
||||||
|
* entities graph.
|
||||||
|
*/
|
||||||
|
protected abstract String getQueryRemovedString();
|
||||||
|
|
||||||
|
public Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision, boolean removed) {
|
||||||
|
Query query = versionsReader.getSession().createQuery( removed ? getQueryRemovedString() : getQueryString() );
|
||||||
query.setParameter( DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL );
|
query.setParameter( DEL_REVISION_TYPE_PARAMETER, RevisionType.DEL );
|
||||||
|
query.setParameter( REVISION_PARAMETER, revision );
|
||||||
for ( QueryParameterData paramData : referencingIdData.getPrefixedMapper().mapToQueryParametersFromId( primaryKey ) ) {
|
for ( QueryParameterData paramData : referencingIdData.getPrefixedMapper().mapToQueryParametersFromId( primaryKey ) ) {
|
||||||
paramData.setParameterValue( query );
|
paramData.setParameterValue( query );
|
||||||
}
|
}
|
||||||
|
@ -67,4 +81,14 @@ public abstract class AbstractRelationQueryGenerator implements RelationQueryGen
|
||||||
? verEntCfg.getOriginalIdPropName() + "." + verEntCfg.getRevisionTypePropName()
|
? verEntCfg.getOriginalIdPropName() + "." + verEntCfg.getRevisionTypePropName()
|
||||||
: verEntCfg.getRevisionTypePropName();
|
: verEntCfg.getRevisionTypePropName();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
protected String queryToString(QueryBuilder query) {
|
||||||
|
return queryToString( query, Collections.<String, Object>emptyMap() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String queryToString(QueryBuilder query, Map<String, Object> queryParamValues) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
query.build( sb, queryParamValues );
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,18 +23,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.entities.mapper.relation.query;
|
package org.hibernate.envers.entities.mapper.relation.query;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.hibernate.Query;
|
|
||||||
import org.hibernate.envers.RevisionType;
|
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
|
||||||
import org.hibernate.envers.tools.query.Parameters;
|
import org.hibernate.envers.tools.query.Parameters;
|
||||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
|
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REFERENCED_ENTITY_ALIAS;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.REFERENCED_ENTITY_ALIAS;
|
||||||
|
@ -43,65 +37,104 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects data from an audit entity.
|
* Selects data from an audit entity.
|
||||||
|
*
|
||||||
* @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)
|
||||||
*/
|
*/
|
||||||
public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class OneAuditEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
private final String queryRemovedString;
|
||||||
|
|
||||||
public OneAuditEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
public OneAuditEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||||
AuditStrategy auditStrategy,
|
AuditStrategy auditStrategy, MiddleIdData referencingIdData,
|
||||||
MiddleIdData referencingIdData,
|
String referencedEntityName, MiddleIdData referencedIdData, boolean revisionTypeInId) {
|
||||||
String referencedEntityName, MiddleIdData referencedIdData,
|
|
||||||
boolean revisionTypeInId) {
|
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query that we need to create:
|
* The valid query that we need to create:
|
||||||
* SELECT e FROM versionsReferencedEntity e
|
* SELECT e FROM versionsReferencedEntity e
|
||||||
* WHERE
|
* WHERE
|
||||||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||||
* e.id_ref_ing = :id_ref_ing AND
|
* e.id_ref_ing = :id_ref_ing AND
|
||||||
* (selecting e entities at revision :revision)
|
* (selecting e entities at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||||
*
|
*
|
||||||
* AND
|
* AND
|
||||||
* (only non-deleted entities)
|
* (only non-deleted entities)
|
||||||
* e.revision_type != DEL
|
* e.revision_type != DEL
|
||||||
*/
|
*/
|
||||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final QueryBuilder commonPart = commonQueryPart( verEntCfg.getAuditEntityName( referencedEntityName ) );
|
||||||
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||||
|
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||||
|
createValidDataRestrictions(
|
||||||
|
globalCfg, auditStrategy, referencedIdData, validQuery, validQuery.getRootParameters(), true
|
||||||
|
);
|
||||||
|
createValidAndRemovedDataRestrictions( globalCfg, auditStrategy, referencedIdData, removedQuery );
|
||||||
|
|
||||||
String versionsReferencedEntityName = verEntCfg.getAuditEntityName(referencedEntityName);
|
queryString = queryToString( validQuery );
|
||||||
|
queryRemovedString = queryToString( removedQuery );
|
||||||
|
}
|
||||||
|
|
||||||
// SELECT e FROM versionsEntity e
|
/**
|
||||||
QueryBuilder qb = new QueryBuilder(versionsReferencedEntityName, REFERENCED_ENTITY_ALIAS);
|
* Compute common part for both queries.
|
||||||
qb.addProjection(null, REFERENCED_ENTITY_ALIAS, false, false);
|
*/
|
||||||
// WHERE
|
private QueryBuilder commonQueryPart(String versionsReferencedEntityName) {
|
||||||
Parameters rootParameters = qb.getRootParameters();
|
// SELECT e FROM versionsEntity e
|
||||||
// e.id_ref_ed = :id_ref_ed
|
final QueryBuilder qb = new QueryBuilder( versionsReferencedEntityName, REFERENCED_ENTITY_ALIAS );
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, null, true);
|
qb.addProjection( null, REFERENCED_ENTITY_ALIAS, false, false );
|
||||||
|
// WHERE
|
||||||
|
// e.id_ref_ed = :id_ref_ed
|
||||||
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( qb.getRootParameters(), null, true );
|
||||||
|
return qb;
|
||||||
|
}
|
||||||
|
|
||||||
// (selecting e entities at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Creates query restrictions used to retrieve only actual data.
|
||||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, revisionPropertyPath,
|
*/
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData,
|
private void createValidDataRestrictions(GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||||
revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR);
|
MiddleIdData referencedIdData, 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,
|
||||||
|
inclusive
|
||||||
|
);
|
||||||
|
// e.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
*/
|
||||||
StringBuilder sb = new StringBuilder();
|
private void createValidAndRemovedDataRestrictions(GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
MiddleIdData referencedIdData, QueryBuilder remQb) {
|
||||||
queryString = sb.toString();
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
}
|
final Parameters valid = disjoint.addSubParameters( "and" ); // Restrictions to match all valid rows.
|
||||||
|
final Parameters removed = disjoint.addSubParameters( "and" ); // Restrictions to match all rows deleted at exactly given revision.
|
||||||
|
// Excluding current revision, because we need to match data valid at the previous one.
|
||||||
|
createValidDataRestrictions( globalCfg, auditStrategy, referencedIdData, 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
|
@Override
|
||||||
protected String getQueryString() {
|
protected String getQueryString() {
|
||||||
return queryString;
|
return queryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getQueryRemovedString() {
|
||||||
|
return queryRemovedString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,18 +23,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.entities.mapper.relation.query;
|
package org.hibernate.envers.entities.mapper.relation.query;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.hibernate.Query;
|
|
||||||
import org.hibernate.envers.RevisionType;
|
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
|
||||||
import org.hibernate.envers.tools.query.Parameters;
|
import org.hibernate.envers.tools.query.Parameters;
|
||||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
|
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||||
|
@ -42,67 +36,106 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects data from a relation middle-table only.
|
* Selects data from a relation middle-table only.
|
||||||
|
*
|
||||||
* @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)
|
||||||
*/
|
*/
|
||||||
public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class OneEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
private final String queryRemovedString;
|
||||||
|
|
||||||
public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg,
|
public OneEntityQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
||||||
AuditStrategy auditStrategy,
|
String versionsMiddleEntityName, MiddleIdData referencingIdData,
|
||||||
String versionsMiddleEntityName,
|
boolean revisionTypeInId, MiddleComponentData... componentData) {
|
||||||
MiddleIdData referencingIdData,
|
|
||||||
boolean revisionTypeInId,
|
|
||||||
MiddleComponentData... componentDatas) {
|
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query that we need to create:
|
* The valid query that we need to create:
|
||||||
* SELECT ee FROM middleEntity ee WHERE
|
* SELECT ee FROM middleEntity ee WHERE
|
||||||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||||
* ee.originalId.id_ref_ing = :id_ref_ing AND
|
* ee.originalId.id_ref_ing = :id_ref_ing AND
|
||||||
*
|
*
|
||||||
* (the association at revision :revision)
|
* (the association at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||||
*
|
*
|
||||||
* AND
|
* AND
|
||||||
*
|
*
|
||||||
* (only non-deleted entities and associations)
|
* (only non-deleted entities and associations)
|
||||||
* ee.revision_type != DEL
|
* ee.revision_type != DEL
|
||||||
*/
|
*/
|
||||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final QueryBuilder commonPart = commonQueryPart( versionsMiddleEntityName );
|
||||||
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||||
|
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||||
|
createValidDataRestrictions(
|
||||||
|
auditStrategy, versionsMiddleEntityName, validQuery, validQuery.getRootParameters(), true, componentData
|
||||||
|
);
|
||||||
|
createValidAndRemovedDataRestrictions( auditStrategy, versionsMiddleEntityName, removedQuery, componentData );
|
||||||
|
|
||||||
// SELECT ee FROM middleEntity ee
|
queryString = queryToString( validQuery );
|
||||||
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS);
|
queryRemovedString = queryToString( removedQuery );
|
||||||
qb.addProjection(null, MIDDLE_ENTITY_ALIAS, false, false);
|
}
|
||||||
// WHERE
|
|
||||||
Parameters rootParameters = qb.getRootParameters();
|
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
|
||||||
|
|
||||||
String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
|
||||||
|
|
||||||
// (with ee association at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Compute common part for both queries.
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
*/
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
private QueryBuilder commonQueryPart(String versionsMiddleEntityName) {
|
||||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
// SELECT ee FROM middleEntity ee
|
||||||
|
final QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||||
// ee.revision_type != DEL
|
qb.addProjection( null, MIDDLE_ENTITY_ALIAS, false, false );
|
||||||
rootParameters.addWhereWithNamedParam(getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER);
|
// WHERE
|
||||||
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( qb.getRootParameters(), verEntCfg.getOriginalIdPropName(), true );
|
||||||
|
return qb;
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
/**
|
||||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
* Creates query restrictions used to retrieve only actual data.
|
||||||
queryString = sb.toString();
|
*/
|
||||||
}
|
private void createValidDataRestrictions(AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||||
|
QueryBuilder qb, Parameters rootParameters, boolean inclusive,
|
||||||
|
MiddleComponentData... componentData) {
|
||||||
|
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
|
||||||
|
);
|
||||||
|
// 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) {
|
||||||
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
|
final Parameters valid = disjoint.addSubParameters( "and" ); // Restrictions to match all valid rows.
|
||||||
|
final Parameters removed = disjoint.addSubParameters( "and" ); // Restrictions to match all rows deleted at exactly given revision.
|
||||||
|
// Excluding current revision, because we need to match data valid at the previous one.
|
||||||
|
createValidDataRestrictions( auditStrategy, versionsMiddleEntityName, remQb, valid, false, componentData );
|
||||||
|
// ee.revision = :revision
|
||||||
|
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
||||||
|
// ee.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( getRevisionTypePath(), "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getQueryString() {
|
protected String getQueryString() {
|
||||||
return queryString;
|
return queryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getQueryRemovedString() {
|
||||||
|
return queryRemovedString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,5 +34,5 @@ import org.hibernate.envers.reader.AuditReaderImplementor;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public interface RelationQueryGenerator {
|
public interface RelationQueryGenerator {
|
||||||
Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision);
|
Query getQuery(AuditReaderImplementor versionsReader, Object primaryKey, Number revision, boolean removed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.entities.mapper.relation.query;
|
package org.hibernate.envers.entities.mapper.relation.query;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.hibernate.Query;
|
|
||||||
import org.hibernate.envers.RevisionType;
|
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
|
||||||
import org.hibernate.envers.tools.query.Parameters;
|
import org.hibernate.envers.tools.query.Parameters;
|
||||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
|
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.INDEX_ENTITY_ALIAS;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.INDEX_ENTITY_ALIAS;
|
||||||
|
@ -47,133 +41,188 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects data from a relation middle-table and a two related versions entity.
|
* Selects data from a relation middle-table and a two related versions entity.
|
||||||
|
*
|
||||||
* @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)
|
||||||
*/
|
*/
|
||||||
public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class ThreeEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
private final String queryRemovedString;
|
||||||
|
|
||||||
public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
|
public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||||
AuditEntitiesConfiguration verEntCfg,
|
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||||
AuditStrategy auditStrategy,
|
MiddleIdData referencingIdData, MiddleIdData referencedIdData,
|
||||||
String versionsMiddleEntityName,
|
MiddleIdData indexIdData, boolean revisionTypeInId,
|
||||||
MiddleIdData referencingIdData,
|
MiddleComponentData... componentData) {
|
||||||
MiddleIdData referencedIdData,
|
|
||||||
MiddleIdData indexIdData,
|
|
||||||
boolean revisionTypeInId,
|
|
||||||
MiddleComponentData... componentDatas) {
|
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query that we need to create:
|
* The valid query that we need to create:
|
||||||
* SELECT new list(ee, e, f) FROM versionsReferencedEntity e, versionsIndexEntity f, middleEntity ee
|
* SELECT new list(ee, e, f) FROM versionsReferencedEntity e, versionsIndexEntity f, middleEntity ee
|
||||||
* WHERE
|
* WHERE
|
||||||
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
|
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
|
||||||
* ee.id_ref_ed = e.id_ref_ed AND
|
* ee.id_ref_ed = e.id_ref_ed AND
|
||||||
* (entities referenced by the middle table; id_ref_ind = id of the index entity)
|
* (entities referenced by the middle table; id_ref_ind = id of the index entity)
|
||||||
* ee.id_ref_ind = f.id_ref_ind AND
|
* ee.id_ref_ind = f.id_ref_ind AND
|
||||||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||||
* ee.id_ref_ing = :id_ref_ing AND
|
* ee.id_ref_ing = :id_ref_ing AND
|
||||||
* (selecting e entities at revision :revision)
|
* (selecting e entities at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||||
*
|
*
|
||||||
* AND
|
* AND
|
||||||
*
|
*
|
||||||
* (selecting f entities at revision :revision)
|
* (selecting f entities at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* f.revision = (SELECT max(f2.revision) FROM versionsIndexEntity f2
|
* f.revision = (SELECT max(f2.revision) FROM versionsIndexEntity f2
|
||||||
* WHERE f2.revision <= :revision AND f2.id_ref_ed = f.id_ref_ed)
|
* WHERE f2.revision <= :revision AND f2.id_ref_ed = f.id_ref_ed)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* f.revision <= :revision and (f.endRevision > :revision or f.endRevision is null)
|
* f.revision <= :revision and (f.endRevision > :revision or f.endRevision is null)
|
||||||
*
|
*
|
||||||
* AND
|
* AND
|
||||||
*
|
*
|
||||||
* (the association at revision :revision)
|
* (the association at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||||
*
|
* and ( strtestent1_.REVEND>? or strtestent1_.REVEND is null )
|
||||||
and (
|
* and ( strtestent1_.REVEND>? or strtestent1_.REVEND is null )
|
||||||
strtestent1_.REVEND>?
|
* and ( ternarymap0_.REVEND>? or ternarymap0_.REVEND is null )
|
||||||
or strtestent1_.REVEND is null
|
*
|
||||||
)
|
* (only non-deleted entities and associations)
|
||||||
and (
|
* ee.revision_type != DEL AND
|
||||||
strtestent1_.REVEND>?
|
* e.revision_type != DEL AND
|
||||||
or strtestent1_.REVEND is null
|
* f.revision_type != DEL
|
||||||
)
|
*/
|
||||||
and (
|
final QueryBuilder commonPart = commonQueryPart( referencedIdData, indexIdData, versionsMiddleEntityName, verEntCfg.getOriginalIdPropName() );
|
||||||
ternarymap0_.REVEND>?
|
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||||
or ternarymap0_.REVEND is null
|
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||||
)
|
createValidDataRestrictions(
|
||||||
*
|
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, validQuery,
|
||||||
*
|
validQuery.getRootParameters(), true, componentData
|
||||||
*
|
);
|
||||||
* (only non-deleted entities and associations)
|
createValidAndRemovedDataRestrictions(
|
||||||
* ee.revision_type != DEL AND
|
globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, removedQuery, componentData
|
||||||
* e.revision_type != DEL AND
|
);
|
||||||
* f.revision_type != DEL
|
|
||||||
*/
|
|
||||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
|
||||||
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
|
||||||
String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
|
||||||
|
|
||||||
// SELECT new list(ee) FROM middleEntity ee
|
queryString = queryToString( validQuery );
|
||||||
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS);
|
queryRemovedString = queryToString( removedQuery );
|
||||||
qb.addFrom(referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS);
|
}
|
||||||
qb.addFrom(indexIdData.getAuditEntityName(), INDEX_ENTITY_ALIAS);
|
|
||||||
qb.addProjection("new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS + ", " + INDEX_ENTITY_ALIAS, false, false);
|
|
||||||
// WHERE
|
|
||||||
Parameters rootParameters = qb.getRootParameters();
|
|
||||||
// ee.id_ref_ed = e.id_ref_ed
|
|
||||||
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
|
|
||||||
referencedIdData.getOriginalMapper(), REFERENCED_ENTITY_ALIAS + "." + originalIdPropertyName);
|
|
||||||
// ee.id_ref_ind = f.id_ref_ind
|
|
||||||
indexIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
|
|
||||||
indexIdData.getOriginalMapper(), INDEX_ENTITY_ALIAS + "." + originalIdPropertyName);
|
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
|
||||||
|
|
||||||
// (selecting e entities at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Compute common part for both queries.
|
||||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
*/
|
||||||
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(), false,
|
private QueryBuilder commonQueryPart(MiddleIdData referencedIdData, MiddleIdData indexIdData,
|
||||||
referencedIdData, revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR);
|
String versionsMiddleEntityName, String originalIdPropertyName) {
|
||||||
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// (selecting f entities at revision :revision)
|
// SELECT new list(ee) FROM middleEntity ee
|
||||||
// --> based on auditStrategy (see above)
|
final QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
qb.addFrom( referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS );
|
||||||
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(), false,
|
qb.addFrom( indexIdData.getAuditEntityName(), INDEX_ENTITY_ALIAS );
|
||||||
referencedIdData, revisionPropertyPath, originalIdPropertyName, INDEX_ENTITY_ALIAS, INDEX_ENTITY_ALIAS_DEF_AUD_STR);
|
qb.addProjection(
|
||||||
|
"new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS + ", " + INDEX_ENTITY_ALIAS,
|
||||||
|
false, false
|
||||||
|
);
|
||||||
|
// WHERE
|
||||||
|
final Parameters rootParameters = qb.getRootParameters();
|
||||||
|
// ee.id_ref_ed = e.id_ref_ed
|
||||||
|
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(
|
||||||
|
rootParameters, eeOriginalIdPropertyPath, referencedIdData.getOriginalMapper(),
|
||||||
|
REFERENCED_ENTITY_ALIAS + "." + originalIdPropertyName
|
||||||
|
);
|
||||||
|
// ee.id_ref_ind = f.id_ref_ind
|
||||||
|
indexIdData.getPrefixedMapper().addIdsEqualToQuery(
|
||||||
|
rootParameters, eeOriginalIdPropertyPath, indexIdData.getOriginalMapper(),
|
||||||
|
INDEX_ENTITY_ALIAS + "." + originalIdPropertyName
|
||||||
|
);
|
||||||
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||||
|
return qb;
|
||||||
|
}
|
||||||
|
|
||||||
// (with ee association at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Creates query restrictions used to retrieve only actual data.
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
*/
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
private void createValidDataRestrictions(GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
MiddleIdData referencedIdData, String versionsMiddleEntityName, QueryBuilder qb,
|
||||||
|
Parameters rootParameters, boolean inclusive, MiddleComponentData... componentData) {
|
||||||
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
|
final String revisionTypePropName = getRevisionTypePath();
|
||||||
|
// (selecting e entities at revision :revision)
|
||||||
|
// --> based on auditStrategy (see above)
|
||||||
|
auditStrategy.addEntityAtRevisionRestriction(
|
||||||
|
globalCfg, qb, rootParameters, REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
||||||
|
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(), false, referencedIdData, revisionPropertyPath,
|
||||||
|
originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR, inclusive
|
||||||
|
);
|
||||||
|
// (selecting f entities at revision :revision)
|
||||||
|
// --> based on auditStrategy (see above)
|
||||||
|
auditStrategy.addEntityAtRevisionRestriction(
|
||||||
|
globalCfg, qb, rootParameters, REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
||||||
|
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(), false, referencedIdData, revisionPropertyPath,
|
||||||
|
originalIdPropertyName, INDEX_ENTITY_ALIAS, INDEX_ENTITY_ALIAS_DEF_AUD_STR, inclusive
|
||||||
|
);
|
||||||
|
// (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
|
||||||
|
);
|
||||||
|
// ee.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
// e.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
// f.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( INDEX_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
// ee.revision_type != DEL
|
/**
|
||||||
String revisionTypePropName = getRevisionTypePath();
|
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||||
rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER);
|
*/
|
||||||
// e.revision_type != DEL
|
private void createValidAndRemovedDataRestrictions(GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||||
rootParameters.addWhereWithNamedParam(REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER);
|
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||||
// f.revision_type != DEL
|
QueryBuilder remQb, MiddleComponentData... componentData) {
|
||||||
rootParameters.addWhereWithNamedParam(INDEX_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER);
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
|
final Parameters valid = disjoint.addSubParameters( "and" ); // Restrictions to match all valid rows.
|
||||||
StringBuilder sb = new StringBuilder();
|
final Parameters removed = disjoint.addSubParameters( "and" ); // Restrictions to match all rows deleted at exactly given revision.
|
||||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
queryString = sb.toString();
|
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, componentData
|
||||||
|
);
|
||||||
|
// ee.revision = :revision
|
||||||
|
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
||||||
|
// e.revision = :revision
|
||||||
|
removed.addWhereWithNamedParam( REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath, false, "=", REVISION_PARAMETER );
|
||||||
|
// f.revision = :revision
|
||||||
|
removed.addWhereWithNamedParam( INDEX_ENTITY_ALIAS + "." + revisionPropertyPath, false, "=", REVISION_PARAMETER );
|
||||||
|
// ee.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( revisionTypePropName, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
// e.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
// f.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( INDEX_ENTITY_ALIAS + "." + revisionTypePropName, false, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getQueryString() {
|
protected String getQueryString() {
|
||||||
return queryString;
|
return queryString;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
protected String getQueryRemovedString() {
|
||||||
|
return queryRemovedString;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,18 +23,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.entities.mapper.relation.query;
|
package org.hibernate.envers.entities.mapper.relation.query;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.hibernate.Query;
|
|
||||||
import org.hibernate.envers.RevisionType;
|
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
|
||||||
import org.hibernate.envers.tools.query.Parameters;
|
import org.hibernate.envers.tools.query.Parameters;
|
||||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
|
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||||
|
@ -43,74 +37,116 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects data from a relation middle-table and a related non-audited entity.
|
* Selects data from a relation middle-table and a related non-audited entity.
|
||||||
|
*
|
||||||
* @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)
|
||||||
*/
|
*/
|
||||||
public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class TwoEntityOneAuditedQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
private final String queryRemovedString;
|
||||||
|
|
||||||
public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
public TwoEntityOneAuditedQueryGenerator(AuditEntitiesConfiguration verEntCfg, AuditStrategy auditStrategy,
|
||||||
String versionsMiddleEntityName,
|
String versionsMiddleEntityName, MiddleIdData referencingIdData,
|
||||||
MiddleIdData referencingIdData,
|
MiddleIdData referencedIdData, boolean revisionTypeInId,
|
||||||
MiddleIdData referencedIdData,
|
MiddleComponentData... componentData) {
|
||||||
boolean revisionTypeInId,
|
|
||||||
MiddleComponentData... componentDatas) {
|
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query that we need to create:
|
* The valid query that we need to create:
|
||||||
* SELECT new list(ee, e) FROM referencedEntity e, middleEntity ee
|
* SELECT new list(ee, e) FROM referencedEntity e, middleEntity ee
|
||||||
* WHERE
|
* WHERE
|
||||||
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
|
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
|
||||||
* ee.id_ref_ed = e.id_ref_ed AND
|
* ee.id_ref_ed = e.id_ref_ed AND
|
||||||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||||
* ee.id_ref_ing = :id_ref_ing AND
|
* ee.id_ref_ing = :id_ref_ing AND
|
||||||
*
|
*
|
||||||
* (the association at revision :revision)
|
* (the association at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||||
*
|
*
|
||||||
* AND
|
* AND
|
||||||
*
|
*
|
||||||
* (only non-deleted entities and associations)
|
* (only non-deleted entities and associations)
|
||||||
* ee.revision_type != DEL
|
* ee.revision_type != DEL
|
||||||
*/
|
*/
|
||||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final QueryBuilder commonPart = commonQueryPart( referencedIdData, versionsMiddleEntityName, verEntCfg.getOriginalIdPropName() );
|
||||||
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
final QueryBuilder validQuery = commonPart.deepCopy();
|
||||||
|
final QueryBuilder removedQuery = commonPart.deepCopy();
|
||||||
|
createValidDataRestrictions(
|
||||||
|
auditStrategy, versionsMiddleEntityName, validQuery, validQuery.getRootParameters(), componentData
|
||||||
|
);
|
||||||
|
createValidAndRemovedDataRestrictions( auditStrategy, versionsMiddleEntityName, removedQuery, componentData );
|
||||||
|
|
||||||
String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
queryString = queryToString( validQuery );
|
||||||
|
queryRemovedString = queryToString( removedQuery );
|
||||||
|
}
|
||||||
|
|
||||||
// SELECT new list(ee) FROM middleEntity ee
|
/**
|
||||||
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS);
|
* Compute common part for both queries.
|
||||||
qb.addFrom(referencedIdData.getEntityName(), REFERENCED_ENTITY_ALIAS);
|
*/
|
||||||
qb.addProjection("new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, false, false);
|
private QueryBuilder commonQueryPart(MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||||
// WHERE
|
String originalIdPropertyName) {
|
||||||
Parameters rootParameters = qb.getRootParameters();
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// ee.id_ref_ed = e.id_ref_ed
|
// SELECT new list(ee) FROM middleEntity ee
|
||||||
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
|
final QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||||
referencedIdData.getOriginalMapper(), REFERENCED_ENTITY_ALIAS);
|
qb.addFrom( referencedIdData.getEntityName(), REFERENCED_ENTITY_ALIAS );
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, false, false );
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
// WHERE
|
||||||
|
final Parameters rootParameters = qb.getRootParameters();
|
||||||
|
// ee.id_ref_ed = e.id_ref_ed
|
||||||
|
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(
|
||||||
|
rootParameters, eeOriginalIdPropertyPath, referencedIdData.getOriginalMapper(), REFERENCED_ENTITY_ALIAS
|
||||||
|
);
|
||||||
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||||
|
return qb;
|
||||||
|
}
|
||||||
|
|
||||||
// (with ee association at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Creates query restrictions used to retrieve only actual data.
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
*/
|
||||||
verEntCfg.getRevisionEndFieldName(), true,referencingIdData, versionsMiddleEntityName,
|
private void createValidDataRestrictions(AuditStrategy auditStrategy, String versionsMiddleEntityName, QueryBuilder qb,
|
||||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
Parameters rootParameters, MiddleComponentData... componentData) {
|
||||||
|
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
|
||||||
|
);
|
||||||
|
// ee.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( getRevisionTypePath(), "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
*/
|
||||||
StringBuilder sb = new StringBuilder();
|
private void createValidAndRemovedDataRestrictions(AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
QueryBuilder remQb, MiddleComponentData... componentData) {
|
||||||
queryString = sb.toString();
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
}
|
final Parameters valid = disjoint.addSubParameters( "and" ); // Restrictions to match all valid rows.
|
||||||
|
final Parameters removed = disjoint.addSubParameters( "and" ); // Restrictions to match all rows deleted at exactly given revision.
|
||||||
|
createValidDataRestrictions( auditStrategy, versionsMiddleEntityName, remQb, valid, componentData );
|
||||||
|
// ee.revision = :revision
|
||||||
|
removed.addWhereWithNamedParam( verEntCfg.getRevisionNumberPath(), "=", REVISION_PARAMETER );
|
||||||
|
// ee.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( getRevisionTypePath(), "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getQueryString() {
|
protected String getQueryString() {
|
||||||
return queryString;
|
return queryString;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
protected String getQueryRemovedString() {
|
||||||
|
return queryRemovedString;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,19 +23,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.entities.mapper.relation.query;
|
package org.hibernate.envers.entities.mapper.relation.query;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.hibernate.Query;
|
|
||||||
import org.hibernate.envers.RevisionType;
|
|
||||||
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
|
||||||
import org.hibernate.envers.configuration.GlobalConfiguration;
|
import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.id.QueryParameterData;
|
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
import org.hibernate.envers.reader.AuditReaderImplementor;
|
|
||||||
import org.hibernate.envers.strategy.AuditStrategy;
|
|
||||||
import org.hibernate.envers.tools.query.Parameters;
|
import org.hibernate.envers.tools.query.Parameters;
|
||||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
import org.hibernate.envers.strategy.AuditStrategy;
|
||||||
|
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.DEL_REVISION_TYPE_PARAMETER;
|
||||||
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants.MIDDLE_ENTITY_ALIAS;
|
||||||
|
@ -45,94 +39,148 @@ import static org.hibernate.envers.entities.mapper.relation.query.QueryConstants
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects data from a relation middle-table and a related versions entity.
|
* Selects data from a relation middle-table and a related versions entity.
|
||||||
|
*
|
||||||
* @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)
|
||||||
*/
|
*/
|
||||||
public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
public final class TwoEntityQueryGenerator extends AbstractRelationQueryGenerator {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
private final String queryRemovedString;
|
||||||
|
|
||||||
public TwoEntityQueryGenerator(GlobalConfiguration globalCfg,
|
public TwoEntityQueryGenerator(GlobalConfiguration globalCfg, AuditEntitiesConfiguration verEntCfg,
|
||||||
AuditEntitiesConfiguration verEntCfg,
|
AuditStrategy auditStrategy, String versionsMiddleEntityName,
|
||||||
AuditStrategy auditStrategy,
|
MiddleIdData referencingIdData, MiddleIdData referencedIdData,
|
||||||
String versionsMiddleEntityName,
|
boolean revisionTypeInId, MiddleComponentData... componentData) {
|
||||||
MiddleIdData referencingIdData,
|
|
||||||
MiddleIdData referencedIdData,
|
|
||||||
boolean revisionTypeInId,
|
|
||||||
MiddleComponentData... componentDatas) {
|
|
||||||
super( verEntCfg, referencingIdData, revisionTypeInId );
|
super( verEntCfg, referencingIdData, revisionTypeInId );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The query that we need to create:
|
* The valid query that we need to create:
|
||||||
* SELECT new list(ee, e) FROM versionsReferencedEntity e, middleEntity ee
|
* SELECT new list(ee, e) FROM versionsReferencedEntity e, middleEntity ee
|
||||||
* WHERE
|
* WHERE
|
||||||
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
|
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
|
||||||
* ee.id_ref_ed = e.id_ref_ed AND
|
* ee.id_ref_ed = e.id_ref_ed AND
|
||||||
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
|
||||||
* ee.id_ref_ing = :id_ref_ing AND
|
* ee.id_ref_ing = :id_ref_ing AND
|
||||||
*
|
*
|
||||||
* (selecting e entities at revision :revision)
|
* (selecting e entities at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
|
||||||
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
* WHERE e2.revision <= :revision AND e2.id = e.id)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
|
||||||
*
|
*
|
||||||
* AND
|
* AND
|
||||||
*
|
*
|
||||||
* (the association at revision :revision)
|
* (the association at revision :revision)
|
||||||
* --> for DefaultAuditStrategy:
|
* --> for DefaultAuditStrategy:
|
||||||
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
|
||||||
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*)
|
||||||
*
|
*
|
||||||
* --> for ValidityAuditStrategy:
|
* --> for ValidityAuditStrategy:
|
||||||
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
* ee.revision <= :revision and (ee.endRevision > :revision or ee.endRevision is null)
|
||||||
*
|
*
|
||||||
* (only non-deleted entities and associations)
|
* (only non-deleted entities and associations)
|
||||||
* ee.revision_type != DEL AND
|
* ee.revision_type != DEL AND
|
||||||
* e.revision_type != DEL
|
* e.revision_type != DEL
|
||||||
*/
|
*/
|
||||||
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
final QueryBuilder commonPart = commonQueryPart( referencedIdData, versionsMiddleEntityName, verEntCfg.getOriginalIdPropName() );
|
||||||
String originalIdPropertyName = 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
|
||||||
|
);
|
||||||
|
|
||||||
String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
queryString = queryToString( validQuery );
|
||||||
|
queryRemovedString = queryToString( removedQuery );
|
||||||
|
}
|
||||||
|
|
||||||
// SELECT new list(ee) FROM middleEntity ee
|
/**
|
||||||
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS);
|
* Compute common part for both queries.
|
||||||
qb.addFrom(referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS);
|
*/
|
||||||
qb.addProjection("new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, false, false);
|
private QueryBuilder commonQueryPart(MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||||
// WHERE
|
String originalIdPropertyName) {
|
||||||
Parameters rootParameters = qb.getRootParameters();
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
// ee.id_ref_ed = e.id_ref_ed
|
// SELECT new list(ee) FROM middleEntity ee
|
||||||
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
|
QueryBuilder qb = new QueryBuilder( versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS );
|
||||||
referencedIdData.getOriginalMapper(), REFERENCED_ENTITY_ALIAS + "." + originalIdPropertyName);
|
qb.addFrom( referencedIdData.getAuditEntityName(), REFERENCED_ENTITY_ALIAS );
|
||||||
// ee.originalId.id_ref_ing = :id_ref_ing
|
qb.addProjection( "new list", MIDDLE_ENTITY_ALIAS + ", " + REFERENCED_ENTITY_ALIAS, false, false );
|
||||||
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
|
// WHERE
|
||||||
|
final Parameters rootParameters = qb.getRootParameters();
|
||||||
|
// ee.id_ref_ed = e.id_ref_ed
|
||||||
|
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(
|
||||||
|
rootParameters, eeOriginalIdPropertyPath, referencedIdData.getOriginalMapper(),
|
||||||
|
REFERENCED_ENTITY_ALIAS + "." + originalIdPropertyName
|
||||||
|
);
|
||||||
|
// ee.originalId.id_ref_ing = :id_ref_ing
|
||||||
|
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery( rootParameters, originalIdPropertyName, true );
|
||||||
|
return qb;
|
||||||
|
}
|
||||||
|
|
||||||
// (selecting e entities at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Creates query restrictions used to retrieve only actual data.
|
||||||
auditStrategy.addEntityAtRevisionRestriction(globalCfg, qb, REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
*/
|
||||||
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(), false,
|
private void createValidDataRestrictions(GlobalConfiguration globalCfg, AuditStrategy auditStrategy, MiddleIdData referencedIdData,
|
||||||
referencedIdData, revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR);
|
String versionsMiddleEntityName, QueryBuilder qb, Parameters rootParameters,
|
||||||
|
boolean inclusive, MiddleComponentData... componentData) {
|
||||||
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
|
final String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
|
||||||
|
final String eeOriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS + "." + originalIdPropertyName;
|
||||||
|
final String revisionTypePropName = getRevisionTypePath();
|
||||||
|
// (selecting e entities at revision :revision)
|
||||||
|
// --> based on auditStrategy (see above)
|
||||||
|
auditStrategy.addEntityAtRevisionRestriction(
|
||||||
|
globalCfg, qb, rootParameters, REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath,
|
||||||
|
REFERENCED_ENTITY_ALIAS + "." + verEntCfg.getRevisionEndFieldName(), false, referencedIdData, revisionPropertyPath,
|
||||||
|
originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR, inclusive
|
||||||
|
);
|
||||||
|
// (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
|
||||||
|
);
|
||||||
|
// ee.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
// e.revision_type != DEL
|
||||||
|
rootParameters.addWhereWithNamedParam( REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
// (with ee association at revision :revision)
|
/**
|
||||||
// --> based on auditStrategy (see above)
|
* Create query restrictions used to retrieve actual data and deletions that took place at exactly given revision.
|
||||||
auditStrategy.addAssociationAtRevisionRestriction(qb, revisionPropertyPath,
|
*/
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencingIdData, versionsMiddleEntityName,
|
private void createValidAndRemovedDataRestrictions(GlobalConfiguration globalCfg, AuditStrategy auditStrategy,
|
||||||
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, MIDDLE_ENTITY_ALIAS, componentDatas);
|
MiddleIdData referencedIdData, String versionsMiddleEntityName,
|
||||||
|
QueryBuilder remQb, MiddleComponentData... componentData) {
|
||||||
// ee.revision_type != DEL
|
final Parameters disjoint = remQb.getRootParameters().addSubParameters( "or" );
|
||||||
String revisionTypePropName = getRevisionTypePath();
|
final Parameters valid = disjoint.addSubParameters( "and" ); // Restrictions to match all valid rows.
|
||||||
rootParameters.addWhereWithNamedParam(revisionTypePropName, "!=", DEL_REVISION_TYPE_PARAMETER);
|
final Parameters removed = disjoint.addSubParameters( "and" ); // Restrictions to match all rows deleted at exactly given revision.
|
||||||
// e.revision_type != DEL
|
final String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
|
||||||
rootParameters.addWhereWithNamedParam(REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "!=", DEL_REVISION_TYPE_PARAMETER);
|
final String revisionTypePropName = getRevisionTypePath();
|
||||||
|
// Excluding current revision, because we need to match data valid at the previous one.
|
||||||
StringBuilder sb = new StringBuilder();
|
createValidDataRestrictions( globalCfg, auditStrategy, referencedIdData, versionsMiddleEntityName, remQb, valid, false, componentData );
|
||||||
qb.build(sb, Collections.<String, Object>emptyMap());
|
// ee.revision = :revision
|
||||||
queryString = sb.toString();
|
removed.addWhereWithNamedParam( revisionPropertyPath, "=", REVISION_PARAMETER );
|
||||||
}
|
// e.revision = :revision
|
||||||
|
removed.addWhereWithNamedParam( REFERENCED_ENTITY_ALIAS + "." + revisionPropertyPath, false, "=", REVISION_PARAMETER );
|
||||||
|
// ee.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( revisionTypePropName, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
// e.revision_type = DEL
|
||||||
|
removed.addWhereWithNamedParam( REFERENCED_ENTITY_ALIAS + "." + revisionTypePropName, false, "=", DEL_REVISION_TYPE_PARAMETER );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getQueryString() {
|
protected String getQueryString() {
|
||||||
return queryString;
|
return queryString;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
protected String getQueryRemovedString() {
|
||||||
|
return queryRemovedString;
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,9 +91,9 @@ public class EntitiesAtRevisionQuery extends AbstractAuditQuery {
|
||||||
|
|
||||||
// (selecting e entities at revision :revision)
|
// (selecting e entities at revision :revision)
|
||||||
// --> based on auditStrategy (see above)
|
// --> based on auditStrategy (see above)
|
||||||
verCfg.getAuditStrategy().addEntityAtRevisionRestriction(verCfg.getGlobalCfg(), qb, revisionPropertyPath,
|
verCfg.getAuditStrategy().addEntityAtRevisionRestriction(verCfg.getGlobalCfg(), qb, qb.getRootParameters(),
|
||||||
verEntCfg.getRevisionEndFieldName(), true, referencedIdData,
|
revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true, referencedIdData,
|
||||||
revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR);
|
revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR, true);
|
||||||
|
|
||||||
if (!includeDeletions) {
|
if (!includeDeletions) {
|
||||||
// e.revision_type != DEL
|
// e.revision_type != DEL
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.hibernate.envers.configuration.GlobalConfiguration;
|
||||||
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
import org.hibernate.envers.entities.mapper.relation.MiddleIdData;
|
||||||
|
import org.hibernate.envers.tools.query.Parameters;
|
||||||
import org.hibernate.envers.tools.query.QueryBuilder;
|
import org.hibernate.envers.tools.query.QueryBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,6 +60,7 @@ public interface AuditStrategy {
|
||||||
*
|
*
|
||||||
* @param globalCfg the {@link GlobalConfiguration}
|
* @param globalCfg the {@link GlobalConfiguration}
|
||||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||||
|
* @param parameters root parameters to which restrictions shall be added
|
||||||
* @param revisionProperty property of the revision column
|
* @param revisionProperty property of the revision column
|
||||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||||
|
@ -67,10 +69,11 @@ public interface AuditStrategy {
|
||||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||||
* @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
* @param alias1 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||||
* @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
* @param alias2 an alias used for subquery (only used for {@link ValidityAuditStrategy})
|
||||||
|
* @param inclusive indicates whether revision number shall be treated as inclusive or exclusive
|
||||||
*/
|
*/
|
||||||
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, Parameters parameters,
|
||||||
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
|
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData,
|
||||||
String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2);
|
String revisionPropertyPath, String originalIdPropertyName, String alias1, String alias2, boolean inclusive);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity
|
* Update the rootQueryBuilder with an extra WHERE clause to restrict the revision for a middle-entity
|
||||||
|
@ -85,6 +88,7 @@ public interface AuditStrategy {
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
* @param rootQueryBuilder the {@link QueryBuilder} that will be updated
|
||||||
|
* @param parameters root parameters to which restrictions shall be added
|
||||||
* @param revisionProperty property of the revision column
|
* @param revisionProperty property of the revision column
|
||||||
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
* @param revisionEndProperty property of the revisionEnd column (only used for {@link ValidityAuditStrategy})
|
||||||
* @param addAlias {@code boolean} indicator if a left alias is needed
|
* @param addAlias {@code boolean} indicator if a left alias is needed
|
||||||
|
@ -94,11 +98,11 @@ public interface AuditStrategy {
|
||||||
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
|
* @param revisionPropertyPath path of the revision property (only used for {@link ValidityAuditStrategy})
|
||||||
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
* @param originalIdPropertyName name of the id property (only used for {@link ValidityAuditStrategy})
|
||||||
* @param alias1 an alias used for subqueries (only used for {@link DefaultAuditStrategy})
|
* @param alias1 an alias used for subqueries (only used for {@link DefaultAuditStrategy})
|
||||||
|
* @param inclusive indicates whether revision number shall be treated as inclusive or exclusive
|
||||||
* @param componentDatas information about the middle-entity relation
|
* @param componentDatas information about the middle-entity relation
|
||||||
*/
|
*/
|
||||||
void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, Parameters parameters, String revisionProperty,
|
||||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||||
String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas);
|
String originalIdPropertyName, String alias1, boolean inclusive, MiddleComponentData... componentDatas);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,9 @@ public class DefaultAuditStrategy implements AuditStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, String revisionProperty,
|
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder, Parameters parameters,
|
||||||
String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath,
|
String revisionProperty, String revisionEndProperty, boolean addAlias, MiddleIdData idData, String revisionPropertyPath,
|
||||||
String originalIdPropertyName, String alias1, String alias2) {
|
String originalIdPropertyName, String alias1, String alias2, boolean inclusive) {
|
||||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
|
||||||
|
|
||||||
// create a subquery builder
|
// create a subquery builder
|
||||||
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
// SELECT max(e.revision) FROM versionsReferencedEntity e2
|
||||||
QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
|
QueryBuilder maxERevQb = rootQueryBuilder.newSubQueryBuilder(idData.getAuditEntityName(), alias2);
|
||||||
|
@ -53,29 +51,27 @@ public class DefaultAuditStrategy implements AuditStrategy {
|
||||||
// WHERE
|
// WHERE
|
||||||
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
|
||||||
// e2.revision <= :revision
|
// e2.revision <= :revision
|
||||||
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
|
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, inclusive ? "<=" : "<", REVISION_PARAMETER);
|
||||||
// e2.id_ref_ed = e.id_ref_ed
|
// e2.id_ref_ed = e.id_ref_ed
|
||||||
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
|
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
|
||||||
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
|
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
|
||||||
|
|
||||||
// add subquery to rootParameters
|
// add subquery to rootParameters
|
||||||
String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator();
|
String subqueryOperator = globalCfg.getCorrelatedSubqueryOperator();
|
||||||
rootParameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb);
|
parameters.addWhere(revisionProperty, addAlias, subqueryOperator, maxERevQb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, Parameters parameters, String revisionProperty,
|
||||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
|
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData, String versionsMiddleEntityName,
|
||||||
String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
String eeOriginalIdPropertyPath, String revisionPropertyPath, String originalIdPropertyName, String alias1,
|
||||||
String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
|
boolean inclusive, MiddleComponentData... componentDatas) {
|
||||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
// SELECT max(ee2.revision) FROM middleEntity ee2
|
||||||
|
|
||||||
// SELECT max(ee2.revision) FROM middleEntity ee2
|
|
||||||
QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
|
QueryBuilder maxEeRevQb = rootQueryBuilder.newSubQueryBuilder(versionsMiddleEntityName, MIDDLE_ENTITY_ALIAS_DEF_AUD_STR);
|
||||||
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
|
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
|
||||||
// WHERE
|
// WHERE
|
||||||
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
|
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
|
||||||
// ee2.revision <= :revision
|
// ee2.revision <= :revision
|
||||||
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", REVISION_PARAMETER);
|
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, inclusive ? "<=" : "<", REVISION_PARAMETER);
|
||||||
// ee2.originalId.* = ee.originalId.*
|
// ee2.originalId.* = ee.originalId.*
|
||||||
String ee2OriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS_DEF_AUD_STR + "." + originalIdPropertyName;
|
String ee2OriginalIdPropertyPath = MIDDLE_ENTITY_ALIAS_DEF_AUD_STR + "." + originalIdPropertyName;
|
||||||
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
|
||||||
|
@ -84,7 +80,7 @@ public class DefaultAuditStrategy implements AuditStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add subquery to rootParameters
|
// add subquery to rootParameters
|
||||||
rootParameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb);
|
parameters.addWhere(revisionProperty, addAlias, "=", maxEeRevQb);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,6 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
||||||
final Serializable id,
|
final Serializable id,
|
||||||
Object data,
|
Object data,
|
||||||
final Object revision) {
|
final Object revision) {
|
||||||
|
|
||||||
final AuditEntitiesConfiguration audEntitiesCfg = auditCfg.getAuditEntCfg();
|
final AuditEntitiesConfiguration audEntitiesCfg = auditCfg.getAuditEntCfg();
|
||||||
final String auditedEntityName = audEntitiesCfg.getAuditEntityName( entityName );
|
final String auditedEntityName = audEntitiesCfg.getAuditEntityName( entityName );
|
||||||
final String revisionInfoEntityName = auditCfg.getAuditEntCfg().getRevisionInfoEntityName();
|
final String revisionInfoEntityName = auditCfg.getAuditEntCfg().getRevisionInfoEntityName();
|
||||||
|
@ -290,32 +289,29 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
public void addEntityAtRevisionRestriction(GlobalConfiguration globalCfg, QueryBuilder rootQueryBuilder,
|
||||||
String revisionProperty,String revisionEndProperty, boolean addAlias,
|
Parameters parameters, String revisionProperty,String revisionEndProperty, boolean addAlias,
|
||||||
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
|
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
|
||||||
String alias1, String alias2) {
|
String alias1, String alias2, boolean inclusive) {
|
||||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
addRevisionRestriction(parameters, revisionProperty, revisionEndProperty, addAlias, inclusive);
|
||||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, String revisionProperty,
|
public void addAssociationAtRevisionRestriction(QueryBuilder rootQueryBuilder, Parameters parameters, String revisionProperty,
|
||||||
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
String revisionEndProperty, boolean addAlias, MiddleIdData referencingIdData,
|
||||||
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
String versionsMiddleEntityName, String eeOriginalIdPropertyPath, String revisionPropertyPath,
|
||||||
String originalIdPropertyName, String alias1, MiddleComponentData... componentDatas) {
|
String originalIdPropertyName, String alias1, boolean inclusive, MiddleComponentData... componentDatas) {
|
||||||
Parameters rootParameters = rootQueryBuilder.getRootParameters();
|
addRevisionRestriction(parameters, revisionProperty, revisionEndProperty, addAlias, inclusive);
|
||||||
addRevisionRestriction(rootParameters, revisionProperty, revisionEndProperty, addAlias);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRevisionTimestampGetter(Getter revisionTimestampGetter) {
|
public void setRevisionTimestampGetter(Getter revisionTimestampGetter) {
|
||||||
this.revisionTimestampGetter = revisionTimestampGetter;
|
this.revisionTimestampGetter = revisionTimestampGetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRevisionRestriction(Parameters rootParameters,
|
private void addRevisionRestriction(Parameters rootParameters, String revisionProperty, String revisionEndProperty,
|
||||||
String revisionProperty, String revisionEndProperty, boolean addAlias) {
|
boolean addAlias, boolean inclusive) {
|
||||||
|
|
||||||
// e.revision <= _revision and (e.endRevision > _revision or e.endRevision is null)
|
// e.revision <= _revision and (e.endRevision > _revision or e.endRevision is null)
|
||||||
Parameters subParm = rootParameters.addSubParameters("or");
|
Parameters subParm = rootParameters.addSubParameters("or");
|
||||||
rootParameters.addWhereWithNamedParam(revisionProperty, addAlias, "<=", REVISION_PARAMETER);
|
rootParameters.addWhereWithNamedParam(revisionProperty, addAlias, inclusive ? "<=" : "<", REVISION_PARAMETER);
|
||||||
subParm.addWhereWithNamedParam(revisionEndProperty + ".id", addAlias, ">", REVISION_PARAMETER);
|
subParm.addWhereWithNamedParam(revisionEndProperty + ".id", addAlias, inclusive ? ">" : ">=", REVISION_PARAMETER);
|
||||||
subParm.addWhere(revisionEndProperty, addAlias, "is", "null", false);
|
subParm.addWhere(revisionEndProperty, addAlias, "is", "null", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +323,6 @@ public class ValidityAuditStrategy implements AuditStrategy {
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
private void updateLastRevision(Session session, AuditConfiguration auditCfg, List<Object> l,
|
private void updateLastRevision(Session session, AuditConfiguration auditCfg, List<Object> l,
|
||||||
Object id, String auditedEntityName, Object revision) {
|
Object id, String auditedEntityName, Object revision) {
|
||||||
|
|
||||||
// There should be one entry
|
// There should be one entry
|
||||||
if (l.size() == 1) {
|
if (l.size() == 1) {
|
||||||
// Setting the end revision to be the current rev
|
// Setting the end revision to be the current rev
|
||||||
|
|
|
@ -36,6 +36,10 @@ public class MutableInteger {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MutableInteger deepCopy() {
|
||||||
|
return new MutableInteger( value );
|
||||||
|
}
|
||||||
|
|
||||||
public int getAndIncrease() {
|
public int getAndIncrease() {
|
||||||
return value++;
|
return value++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,8 @@ package org.hibernate.envers.tools;
|
||||||
* @author Adam Warski (adamw@aster.pl)
|
* @author Adam Warski (adamw@aster.pl)
|
||||||
*/
|
*/
|
||||||
public class Pair<T1, T2> {
|
public class Pair<T1, T2> {
|
||||||
private T1 obj1;
|
private final T1 obj1;
|
||||||
private T2 obj2;
|
private final T2 obj2;
|
||||||
|
|
||||||
public Pair(T1 obj1, T2 obj2) {
|
public Pair(T1 obj1, T2 obj2) {
|
||||||
this.obj1 = obj1;
|
this.obj1 = obj1;
|
||||||
|
|
|
@ -79,6 +79,28 @@ public class Parameters {
|
||||||
localQueryParamValues = new HashMap<String, Object>();
|
localQueryParamValues = new HashMap<String, Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for deep copy purpose.
|
||||||
|
private Parameters(Parameters other) {
|
||||||
|
this.alias = other.alias;
|
||||||
|
this.connective = other.connective;
|
||||||
|
this.queryParamCounter = other.queryParamCounter.deepCopy();
|
||||||
|
|
||||||
|
subParameters = new ArrayList<Parameters>( other.subParameters.size() );
|
||||||
|
for ( Parameters p : other.subParameters ) {
|
||||||
|
subParameters.add( p.deepCopy() );
|
||||||
|
}
|
||||||
|
negatedParameters = new ArrayList<Parameters>( other.negatedParameters.size() );
|
||||||
|
for ( Parameters p : other.negatedParameters ) {
|
||||||
|
negatedParameters.add( p.deepCopy() );
|
||||||
|
}
|
||||||
|
expressions = new ArrayList<String>( other.expressions );
|
||||||
|
localQueryParamValues = new HashMap<String, Object>( other.localQueryParamValues );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Parameters deepCopy() {
|
||||||
|
return new Parameters( this );
|
||||||
|
}
|
||||||
|
|
||||||
private String generateQueryParam() {
|
private String generateQueryParam() {
|
||||||
return "_p" + queryParamCounter.getAndIncrease();
|
return "_p" + queryParamCounter.getAndIncrease();
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,23 @@ public class QueryBuilder {
|
||||||
addFrom(entityName, alias);
|
addFrom(entityName, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for deep copy purpose.
|
||||||
|
private QueryBuilder(QueryBuilder other) {
|
||||||
|
this.entityName = other.entityName;
|
||||||
|
this.alias = other.alias;
|
||||||
|
this.aliasCounter = other.aliasCounter.deepCopy();
|
||||||
|
this.paramCounter = other.paramCounter.deepCopy();
|
||||||
|
this.rootParameters = other.rootParameters.deepCopy();
|
||||||
|
|
||||||
|
froms = new ArrayList<Pair<String, String>>( other.froms );
|
||||||
|
orders = new ArrayList<Pair<String, Boolean>>( other.orders );
|
||||||
|
projections = new ArrayList<String>( other.projections );
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryBuilder deepCopy() {
|
||||||
|
return new QueryBuilder( this );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an entity from which to select.
|
* Add an entity from which to select.
|
||||||
* @param entityName Name of the entity from which to select.
|
* @param entityName Name of the entity from which to select.
|
||||||
|
|
|
@ -1,83 +1,444 @@
|
||||||
package org.hibernate.envers.test.integration.proxy;
|
package org.hibernate.envers.test.integration.proxy;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import java.util.HashSet;
|
||||||
import org.hibernate.envers.RevisionType;
|
import java.util.List;
|
||||||
import org.hibernate.envers.query.AuditEntity;
|
import java.util.Map;
|
||||||
import org.hibernate.envers.query.AuditQuery;
|
import java.util.Set;
|
||||||
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
import javax.persistence.EntityManager;
|
||||||
import org.hibernate.envers.test.Priority;
|
|
||||||
import org.hibernate.envers.test.entities.onetomany.SetRefEdEntity;
|
|
||||||
import org.hibernate.envers.test.entities.onetomany.SetRefIngEntity;
|
|
||||||
import org.hibernate.envers.test.tools.TestTools;
|
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import org.hibernate.Hibernate;
|
||||||
import java.util.Map;
|
import org.hibernate.envers.RevisionType;
|
||||||
|
import org.hibernate.envers.enhanced.SequenceIdRevisionEntity;
|
||||||
import javax.persistence.EntityManager;
|
import org.hibernate.envers.query.AuditEntity;
|
||||||
|
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
||||||
|
import org.hibernate.envers.test.Priority;
|
||||||
|
import org.hibernate.envers.test.entities.IntTestPrivSeqEntity;
|
||||||
|
import org.hibernate.envers.test.entities.StrTestPrivSeqEntity;
|
||||||
|
import org.hibernate.envers.test.entities.UnversionedStrTestEntity;
|
||||||
|
import org.hibernate.envers.test.entities.collection.StringSetEntity;
|
||||||
|
import org.hibernate.envers.test.entities.manytomany.SetOwnedEntity;
|
||||||
|
import org.hibernate.envers.test.entities.manytomany.SetOwningEntity;
|
||||||
|
import org.hibernate.envers.test.entities.manytomany.unidirectional.M2MIndexedListTargetNotAuditedEntity;
|
||||||
|
import org.hibernate.envers.test.entities.onetomany.SetRefEdEntity;
|
||||||
|
import org.hibernate.envers.test.entities.onetomany.SetRefIngEntity;
|
||||||
|
import org.hibernate.envers.test.integration.manytomany.ternary.TernaryMapEntity;
|
||||||
|
import org.hibernate.envers.test.tools.TestTools;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
@TestForIssue(jiraKey = "HHH-5845")
|
@TestForIssue(jiraKey = "HHH-5845")
|
||||||
public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
public class RemovedObjectQueryTest extends BaseEnversJPAFunctionalTestCase {
|
||||||
@Override
|
private Integer stringSetId = null;
|
||||||
@SuppressWarnings("unchecked")
|
private Integer ternaryMapId = null;
|
||||||
protected void addConfigOptions(Map options) {
|
private UnversionedStrTestEntity unversionedEntity1 = null;
|
||||||
options.put("org.hibernate.envers.store_data_at_delete", "true");
|
private UnversionedStrTestEntity unversionedEntity2 = null;
|
||||||
}
|
private StrTestPrivSeqEntity stringEntity1 = null;
|
||||||
|
private StrTestPrivSeqEntity stringEntity2 = null;
|
||||||
|
private IntTestPrivSeqEntity intEntity1 = null;
|
||||||
|
private IntTestPrivSeqEntity intEntity2 = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
protected void addConfigOptions(Map options) {
|
||||||
return new Class<?>[] { SetRefEdEntity.class, SetRefIngEntity.class };
|
super.addConfigOptions( options );
|
||||||
}
|
options.put( "org.hibernate.envers.store_data_at_delete", "true" );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Override
|
||||||
@Priority(10)
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
public void initData() {
|
return new Class<?>[] {
|
||||||
EntityManager em = getEntityManager();
|
SetRefEdEntity.class, SetRefIngEntity.class, SetOwnedEntity.class, SetOwningEntity.class,
|
||||||
|
StringSetEntity.class, UnversionedStrTestEntity.class, M2MIndexedListTargetNotAuditedEntity.class,
|
||||||
|
TernaryMapEntity.class, StrTestPrivSeqEntity.class, IntTestPrivSeqEntity.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
SetRefEdEntity refEdEntity = new SetRefEdEntity(1, "Demo Data");
|
@Test
|
||||||
SetRefIngEntity refIngEntity = new SetRefIngEntity(2, "Example Data", refEdEntity);
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
|
||||||
em.getTransaction().begin();
|
SetRefEdEntity refEdEntity1 = new SetRefEdEntity( 1, "Demo Data 1" );
|
||||||
em.persist(refEdEntity);
|
SetRefIngEntity refIngEntity1 = new SetRefIngEntity( 2, "Example Data 1", refEdEntity1 );
|
||||||
em.persist(refIngEntity);
|
|
||||||
em.getTransaction().commit();
|
|
||||||
|
|
||||||
em.getTransaction().begin();
|
// Revision 1
|
||||||
refIngEntity = em.find(SetRefIngEntity.class, 2);
|
em.getTransaction().begin();
|
||||||
em.remove(refIngEntity);
|
em.persist( refEdEntity1 );
|
||||||
em.remove(refEdEntity);
|
em.persist( refIngEntity1 );
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
// Revision 2 - removing both object in the same revision
|
||||||
public void testFindDeletedReference() {
|
em.getTransaction().begin();
|
||||||
AuditQuery query = getAuditReader().createQuery().forRevisionsOfEntity(SetRefIngEntity.class, false, true)
|
refEdEntity1 = em.find( SetRefEdEntity.class, 1 );
|
||||||
.add(AuditEntity.revisionType().eq(RevisionType.DEL));
|
refIngEntity1 = em.find( SetRefIngEntity.class, 2 );
|
||||||
List queryResult = (List) query.getResultList();
|
em.remove( refIngEntity1 );
|
||||||
|
em.remove( refEdEntity1 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
Object[] objArray = (Object[]) queryResult.get(0);
|
SetRefEdEntity refEdEntity2 = new SetRefEdEntity( 3, "Demo Data 2" );
|
||||||
SetRefIngEntity refIngEntity = (SetRefIngEntity) objArray[0];
|
SetRefIngEntity refIngEntity2 = new SetRefIngEntity( 4, "Example Data 2", refEdEntity2 );
|
||||||
Assert.assertEquals("Example Data", refIngEntity.getData());
|
|
||||||
|
|
||||||
Hibernate.initialize(refIngEntity.getReference());
|
// Revision 3
|
||||||
Assert.assertEquals("Demo Data", refIngEntity.getReference().getData());
|
em.getTransaction().begin();
|
||||||
}
|
em.persist( refEdEntity2 );
|
||||||
|
em.persist( refIngEntity2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
@FailureExpected(jiraKey = "HHH-5845") // TODO: doesn't work until collection queries are fixed
|
// Revision 4 - removing child object
|
||||||
@Test
|
em.getTransaction().begin();
|
||||||
public void testFindDeletedReferring() {
|
refIngEntity2 = em.find( SetRefIngEntity.class, 4 );
|
||||||
AuditQuery query = getAuditReader().createQuery().forRevisionsOfEntity(SetRefEdEntity.class, false, true)
|
em.remove( refIngEntity2 );
|
||||||
.add(AuditEntity.revisionType().eq(RevisionType.DEL));
|
em.getTransaction().commit();
|
||||||
List queryResult = (List) query.getResultList();
|
|
||||||
|
|
||||||
Object[] objArray = (Object[]) queryResult.get(0);
|
// Revision 5 - removing parent object
|
||||||
SetRefEdEntity refEdEntity = (SetRefEdEntity) objArray[0];
|
em.getTransaction().begin();
|
||||||
Assert.assertEquals("Demo Data", refEdEntity.getData());
|
refEdEntity2 = em.find( SetRefEdEntity.class, 3 );
|
||||||
|
em.remove( refEdEntity2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
Hibernate.initialize(refEdEntity.getReffering());
|
SetOwningEntity setOwningEntity1 = new SetOwningEntity( 5, "Demo Data 1" );
|
||||||
Assert.assertEquals(TestTools.makeSet(new SetRefIngEntity(2, "Example Data")), refEdEntity.getReffering());
|
SetOwnedEntity setOwnedEntity1 = new SetOwnedEntity( 6, "Example Data 1" );
|
||||||
}
|
Set<SetOwningEntity> owning = new HashSet<SetOwningEntity>();
|
||||||
}
|
Set<SetOwnedEntity> owned = new HashSet<SetOwnedEntity>();
|
||||||
|
owning.add( setOwningEntity1 );
|
||||||
|
owned.add( setOwnedEntity1 );
|
||||||
|
setOwningEntity1.setReferences( owned );
|
||||||
|
setOwnedEntity1.setReferencing( owning );
|
||||||
|
|
||||||
|
// Revision 6
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( setOwnedEntity1 );
|
||||||
|
em.persist( setOwningEntity1 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 7 - removing both object in the same revision
|
||||||
|
em.getTransaction().begin();
|
||||||
|
setOwnedEntity1 = em.find( SetOwnedEntity.class, 6 );
|
||||||
|
setOwningEntity1 = em.find( SetOwningEntity.class, 5 );
|
||||||
|
em.remove( setOwningEntity1 );
|
||||||
|
em.remove( setOwnedEntity1 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
SetOwningEntity setOwningEntity2 = new SetOwningEntity( 7, "Demo Data 2" );
|
||||||
|
SetOwnedEntity setOwnedEntity2 = new SetOwnedEntity( 8, "Example Data 2" );
|
||||||
|
owning = new HashSet<SetOwningEntity>();
|
||||||
|
owned = new HashSet<SetOwnedEntity>();
|
||||||
|
owning.add( setOwningEntity2 );
|
||||||
|
owned.add( setOwnedEntity2 );
|
||||||
|
setOwningEntity2.setReferences( owned );
|
||||||
|
setOwnedEntity2.setReferencing( owning );
|
||||||
|
|
||||||
|
// Revision 8
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( setOwnedEntity2 );
|
||||||
|
em.persist( setOwningEntity2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 9 - removing first object
|
||||||
|
em.getTransaction().begin();
|
||||||
|
setOwningEntity2 = em.find( SetOwningEntity.class, 7 );
|
||||||
|
em.remove( setOwningEntity2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 10 - removing second object
|
||||||
|
em.getTransaction().begin();
|
||||||
|
setOwnedEntity2 = em.find( SetOwnedEntity.class, 8 );
|
||||||
|
em.remove( setOwnedEntity2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
StringSetEntity stringSetEntity = new StringSetEntity();
|
||||||
|
stringSetEntity.getStrings().add( "string 1" );
|
||||||
|
stringSetEntity.getStrings().add( "string 2" );
|
||||||
|
|
||||||
|
// Revision 11
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( stringSetEntity );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
stringSetId = stringSetEntity.getId();
|
||||||
|
|
||||||
|
// Revision 12 - removing element collection
|
||||||
|
em.getTransaction().begin();
|
||||||
|
stringSetEntity = em.find( StringSetEntity.class, stringSetEntity.getId() );
|
||||||
|
em.remove( stringSetEntity );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 13
|
||||||
|
em.getTransaction().begin();
|
||||||
|
unversionedEntity1 = new UnversionedStrTestEntity( "string 1" );
|
||||||
|
unversionedEntity2 = new UnversionedStrTestEntity( "string 2" );
|
||||||
|
M2MIndexedListTargetNotAuditedEntity relationNotAuditedEntity = new M2MIndexedListTargetNotAuditedEntity( 1, "Parent" );
|
||||||
|
relationNotAuditedEntity.getReferences().add( unversionedEntity1 );
|
||||||
|
relationNotAuditedEntity.getReferences().add( unversionedEntity2 );
|
||||||
|
em.persist( unversionedEntity1 );
|
||||||
|
em.persist( unversionedEntity2 );
|
||||||
|
em.persist( relationNotAuditedEntity );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Revision 14 - removing entity with unversioned relation
|
||||||
|
em.getTransaction().begin();
|
||||||
|
relationNotAuditedEntity = em.find( M2MIndexedListTargetNotAuditedEntity.class, relationNotAuditedEntity.getId() );
|
||||||
|
em.remove( relationNotAuditedEntity );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
stringEntity1 = new StrTestPrivSeqEntity( "Value 1" );
|
||||||
|
stringEntity2 = new StrTestPrivSeqEntity( "Value 2" );
|
||||||
|
intEntity1 = new IntTestPrivSeqEntity( 1 );
|
||||||
|
intEntity2 = new IntTestPrivSeqEntity( 2 );
|
||||||
|
TernaryMapEntity mapEntity = new TernaryMapEntity();
|
||||||
|
mapEntity.getMap().put( intEntity1, stringEntity1 );
|
||||||
|
mapEntity.getMap().put( intEntity2, stringEntity2 );
|
||||||
|
|
||||||
|
// Revision 15
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( stringEntity1 );
|
||||||
|
em.persist( stringEntity2 );
|
||||||
|
em.persist( intEntity1 );
|
||||||
|
em.persist( intEntity2 );
|
||||||
|
em.persist( mapEntity );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
ternaryMapId = mapEntity.getId();
|
||||||
|
|
||||||
|
// Revision 16 - removing ternary map
|
||||||
|
em.getTransaction().begin();
|
||||||
|
mapEntity = em.find( TernaryMapEntity.class, mapEntity.getId() );
|
||||||
|
em.remove( mapEntity );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTernaryMap() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( TernaryMapEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( ternaryMapId ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 16, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
TernaryMapEntity mapEntity = (TernaryMapEntity) objArray[0];
|
||||||
|
Assert.assertEquals( TestTools.makeMap( intEntity1, stringEntity1, intEntity2, stringEntity2 ), mapEntity.getMap() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnversionedRelation() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( M2MIndexedListTargetNotAuditedEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 1 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 14, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
M2MIndexedListTargetNotAuditedEntity relationNotAuditedEntity = (M2MIndexedListTargetNotAuditedEntity) objArray[0];
|
||||||
|
Assert.assertTrue(
|
||||||
|
TestTools.checkList(
|
||||||
|
relationNotAuditedEntity.getReferences(),
|
||||||
|
unversionedEntity1, unversionedEntity2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testElementCollection() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( StringSetEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( stringSetId ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 12, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
StringSetEntity stringSetEntity = (StringSetEntity) objArray[0];
|
||||||
|
Assert.assertEquals( TestTools.makeSet( "string 1", "string 2" ), stringSetEntity.getStrings() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// One to many tests.
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferencedOneToManySameRevision() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetRefIngEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 2 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 2, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetRefIngEntity refIngEntity = (SetRefIngEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Example Data 1", refIngEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( refIngEntity.getReference() );
|
||||||
|
Assert.assertEquals( "Demo Data 1", refIngEntity.getReference().getData() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferringOneToManySameRevision() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetRefEdEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 1 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 2, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetRefEdEntity refEdEntity = (SetRefEdEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Demo Data 1", refEdEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( refEdEntity.getReffering() );
|
||||||
|
Assert.assertEquals(
|
||||||
|
TestTools.makeSet( new SetRefIngEntity( 2, "Example Data 1" ) ),
|
||||||
|
refEdEntity.getReffering()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferencedOneToManyDifferentRevisions() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetRefIngEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 4 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 4, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetRefIngEntity refIngEntity = (SetRefIngEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Example Data 2", refIngEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( refIngEntity.getReference() );
|
||||||
|
Assert.assertEquals( "Demo Data 2", refIngEntity.getReference().getData() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReferringOneToManyDifferentRevisions() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetRefEdEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 3 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 5, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetRefEdEntity refEdEntity = (SetRefEdEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Demo Data 2", refEdEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( refEdEntity.getReffering() );
|
||||||
|
Assert.assertTrue( refEdEntity.getReffering().isEmpty() );
|
||||||
|
|
||||||
|
// After commit in revision four, child entity has been removed.
|
||||||
|
queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetRefEdEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 3 ) )
|
||||||
|
.add( AuditEntity.revisionNumber().eq( 4 ) )
|
||||||
|
.getResultList();
|
||||||
|
objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
refEdEntity = (SetRefEdEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Demo Data 2", refEdEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( refEdEntity.getReffering() );
|
||||||
|
Assert.assertTrue( refEdEntity.getReffering().isEmpty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Many to many tests.
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwnedManyToManySameRevision() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetOwningEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 5 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 7, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetOwningEntity setOwningEntity = (SetOwningEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Demo Data 1", setOwningEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( setOwningEntity.getReferences() );
|
||||||
|
Assert.assertEquals(
|
||||||
|
TestTools.makeSet( new SetOwnedEntity( 6, "Example Data 1" ) ),
|
||||||
|
setOwningEntity.getReferences()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwningManyToManySameRevision() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetOwnedEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 6 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 7, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetOwnedEntity setOwnedEntity = (SetOwnedEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Example Data 1", setOwnedEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( setOwnedEntity.getReferencing() );
|
||||||
|
Assert.assertEquals(
|
||||||
|
TestTools.makeSet( new SetOwningEntity( 5, "Demo Data 1" ) ),
|
||||||
|
setOwnedEntity.getReferencing()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwnedManyToManyDifferentRevisions() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetOwningEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 7 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 9, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetOwningEntity setOwningEntity = (SetOwningEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Demo Data 2", setOwningEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( setOwningEntity.getReferences() );
|
||||||
|
Assert.assertEquals(
|
||||||
|
TestTools.makeSet( new SetOwnedEntity( 8, "Example Data 2" ) ),
|
||||||
|
setOwningEntity.getReferences()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwningManyToManyDifferentRevisions() {
|
||||||
|
List queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetOwnedEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 8 ) )
|
||||||
|
.add( AuditEntity.revisionType().eq( RevisionType.DEL ) )
|
||||||
|
.getResultList();
|
||||||
|
Object[] objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
Assert.assertEquals( 10, getRevisionNumber( objArray[1] ) );
|
||||||
|
|
||||||
|
SetOwnedEntity setOwnedEntity = (SetOwnedEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Example Data 2", setOwnedEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( setOwnedEntity.getReferencing() );
|
||||||
|
Assert.assertTrue( setOwnedEntity.getReferencing().isEmpty() );
|
||||||
|
|
||||||
|
// After commit in revision nine, related entity has been removed.
|
||||||
|
queryResult = getAuditReader().createQuery().forRevisionsOfEntity( SetOwnedEntity.class, false, true )
|
||||||
|
.add( AuditEntity.id().eq( 8 ) )
|
||||||
|
.add( AuditEntity.revisionNumber().eq( 9 ) )
|
||||||
|
.getResultList();
|
||||||
|
objArray = (Object[]) queryResult.get( 0 );
|
||||||
|
|
||||||
|
setOwnedEntity = (SetOwnedEntity) objArray[0];
|
||||||
|
Assert.assertEquals( "Example Data 2", setOwnedEntity.getData() );
|
||||||
|
|
||||||
|
Hibernate.initialize( setOwnedEntity.getReferencing() );
|
||||||
|
Assert.assertTrue( setOwnedEntity.getReferencing().isEmpty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Number getRevisionNumber(Object revisionEntity) {
|
||||||
|
return ( (SequenceIdRevisionEntity) revisionEntity ).getId();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue