HHH-11895 Support traversal of components in audit query API
This commit is contained in:
parent
25421733d6
commit
d9f3e82291
|
@ -14,6 +14,7 @@ import org.hibernate.envers.boot.registry.classloading.ClassLoaderAccessHelper;
|
||||||
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
import org.hibernate.envers.boot.spi.EnversMetadataBuildingContext;
|
||||||
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
|
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
|
||||||
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
|
import org.hibernate.envers.configuration.internal.metadata.reader.PropertyAuditingData;
|
||||||
|
import org.hibernate.envers.internal.entities.EntityConfiguration;
|
||||||
import org.hibernate.envers.internal.entities.mapper.CompositeMapperBuilder;
|
import org.hibernate.envers.internal.entities.mapper.CompositeMapperBuilder;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
@ -80,6 +81,11 @@ public final class ComponentMetadataGenerator extends AbstractMetadataGenerator
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !firstPass ) {
|
||||||
|
final EntityConfiguration owningEntityConfiguration = getAuditedEntityConfigurations().get( entityName );
|
||||||
|
owningEntityConfiguration.addToOneComponent( propertyAuditingData.getName(), componentAuditingData );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getClassNameForComponent(Component component) {
|
private String getClassNameForComponent(Component component) {
|
||||||
|
|
|
@ -237,7 +237,7 @@ public class MiddleTableCollectionMetadataGenerator extends AbstractCollectionMe
|
||||||
MiddleIdData referencingIdData,
|
MiddleIdData referencingIdData,
|
||||||
String referencedPrefix,
|
String referencedPrefix,
|
||||||
String auditMiddleEntityName) {
|
String auditMiddleEntityName) {
|
||||||
// Only if this is a relation (when there is a referenced entity).
|
// Only if this is a relation (when there is a referenced entity or a component).
|
||||||
if ( context.getReferencedEntityName() != null ) {
|
if ( context.getReferencedEntityName() != null ) {
|
||||||
final IdMappingData referencedIdMapping = getReferencedIdMappingData(
|
final IdMappingData referencedIdMapping = getReferencedIdMappingData(
|
||||||
context.getReferencingEntityName(),
|
context.getReferencingEntityName(),
|
||||||
|
@ -270,5 +270,12 @@ public class MiddleTableCollectionMetadataGenerator extends AbstractCollectionMe
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
context.getReferencingEntityConfiguration().addToManyComponent(
|
||||||
|
context.getPropertyName(),
|
||||||
|
auditMiddleEntityName,
|
||||||
|
referencingIdData
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.envers.internal.entities;
|
||||||
|
|
||||||
|
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
|
||||||
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class ComponentDescription {
|
||||||
|
|
||||||
|
private final ComponentType type;
|
||||||
|
private final String propertyName;
|
||||||
|
private final String auditMiddleEntityName;
|
||||||
|
private final MiddleIdData middleIdData;
|
||||||
|
private final ComponentAuditingData auditingData;
|
||||||
|
|
||||||
|
private ComponentDescription(ComponentType type,
|
||||||
|
String propertyName,
|
||||||
|
String auditMiddleEntityName,
|
||||||
|
MiddleIdData middleIdData,
|
||||||
|
ComponentAuditingData componentAuditingData) {
|
||||||
|
this.type = type;
|
||||||
|
this.propertyName = propertyName;
|
||||||
|
this.auditMiddleEntityName = auditMiddleEntityName;
|
||||||
|
this.middleIdData = middleIdData;
|
||||||
|
this.auditingData = componentAuditingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComponentDescription many(String propertyName, String auditMiddleEntityName, MiddleIdData middleIdData) {
|
||||||
|
return new ComponentDescription( ComponentType.MANY, propertyName, auditMiddleEntityName, middleIdData, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComponentDescription one(String propertyName, ComponentAuditingData componentAuditingData) {
|
||||||
|
return new ComponentDescription( ComponentType.ONE, propertyName, null, null, componentAuditingData );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPropertyName() {
|
||||||
|
return propertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuditMiddleEntityName() {
|
||||||
|
return auditMiddleEntityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MiddleIdData getMiddleIdData() {
|
||||||
|
return middleIdData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentAuditingData getAuditingData() {
|
||||||
|
return auditingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ComponentType {
|
||||||
|
ONE, MANY
|
||||||
|
}
|
||||||
|
}
|
|
@ -124,6 +124,27 @@ public class EntitiesConfigurations {
|
||||||
return descriptions;
|
return descriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComponentDescription getComponentDescription(final String entityName, final String propertyName) {
|
||||||
|
final EntityConfiguration entCfg;
|
||||||
|
if ( isVersioned( entityName ) ) {
|
||||||
|
entCfg = get( entityName );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entCfg = getNotVersionEntityConfiguration( entityName );
|
||||||
|
}
|
||||||
|
final ComponentDescription relDesc = entCfg.getComponentDescription( propertyName );
|
||||||
|
if ( relDesc != null ) {
|
||||||
|
return relDesc;
|
||||||
|
}
|
||||||
|
else if ( entCfg.getParentEntityName() != null ) {
|
||||||
|
// The field may be declared in a superclass ...
|
||||||
|
return getComponentDescription( entCfg.getParentEntityName(), propertyName );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
|
private void addWithParentEntityNames(String entityName, Set<String> entityNames) {
|
||||||
entityNames.add( entityName );
|
entityNames.add( entityName );
|
||||||
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
final EntityConfiguration entCfg = entitiesConfigurations.get( entityName );
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.envers.internal.entities;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.envers.configuration.internal.metadata.reader.ComponentAuditingData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.ExtendedPropertyMapper;
|
import org.hibernate.envers.internal.entities.mapper.ExtendedPropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||||
|
@ -31,6 +32,7 @@ public class EntityConfiguration {
|
||||||
private final ExtendedPropertyMapper propertyMapper;
|
private final ExtendedPropertyMapper propertyMapper;
|
||||||
// Maps from property name
|
// Maps from property name
|
||||||
private final Map<String, RelationDescription> relations;
|
private final Map<String, RelationDescription> relations;
|
||||||
|
private final Map<String, ComponentDescription> components;
|
||||||
private final String parentEntityName;
|
private final String parentEntityName;
|
||||||
|
|
||||||
public EntityConfiguration(
|
public EntityConfiguration(
|
||||||
|
@ -46,6 +48,7 @@ public class EntityConfiguration {
|
||||||
this.parentEntityName = parentEntityName;
|
this.parentEntityName = parentEntityName;
|
||||||
|
|
||||||
this.relations = new HashMap<>();
|
this.relations = new HashMap<>();
|
||||||
|
this.components = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToOneRelation(
|
public void addToOneRelation(
|
||||||
|
@ -170,6 +173,14 @@ public class EntityConfiguration {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addToManyComponent(String propertyName, String auditMiddleEntityName, MiddleIdData middleIdData) {
|
||||||
|
components.put( propertyName, ComponentDescription.many( propertyName, auditMiddleEntityName, middleIdData ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToOneComponent(String propertyName, ComponentAuditingData auditingData) {
|
||||||
|
components.put( propertyName, ComponentDescription.one( propertyName, auditingData ) );
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRelation(String propertyName) {
|
public boolean isRelation(String propertyName) {
|
||||||
return relations.get( propertyName ) != null;
|
return relations.get( propertyName ) != null;
|
||||||
}
|
}
|
||||||
|
@ -178,6 +189,10 @@ public class EntityConfiguration {
|
||||||
return relations.get( propertyName );
|
return relations.get( propertyName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComponentDescription getComponentDescription(String propertyName) {
|
||||||
|
return components.get( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
public IdMappingData getIdMappingData() {
|
public IdMappingData getIdMappingData() {
|
||||||
return idMappingData;
|
return idMappingData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,6 +318,7 @@ public class Parameters {
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
|
* @param aliasToComponentPropertyNameMap alias to component property name map, never {@literal null}
|
||||||
* @param function the function.
|
* @param function the function.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param value the scalar value.
|
* @param value the scalar value.
|
||||||
|
@ -325,6 +326,7 @@ public class Parameters {
|
||||||
public void addWhereWithFunction(
|
public void addWhereWithFunction(
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
AuditFunction function,
|
AuditFunction function,
|
||||||
String op,
|
String op,
|
||||||
Object value) {
|
Object value) {
|
||||||
|
@ -333,6 +335,7 @@ public class Parameters {
|
||||||
QueryBuilder.appendFunctionArgument(
|
QueryBuilder.appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
queryParamCounter,
|
queryParamCounter,
|
||||||
localQueryParamValues,
|
localQueryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
@ -354,6 +357,7 @@ public class Parameters {
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
|
* @param aliasToComponentPropertyNameMap alias to component property name map, never {@literal null}
|
||||||
* @param function the function.
|
* @param function the function.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param aliasRight the optional alias of the right property, may be {@literal null}
|
* @param aliasRight the optional alias of the right property, may be {@literal null}
|
||||||
|
@ -362,6 +366,7 @@ public class Parameters {
|
||||||
public void addWhereWithFunction(
|
public void addWhereWithFunction(
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
AuditFunction function,
|
AuditFunction function,
|
||||||
String op,
|
String op,
|
||||||
String aliasRight,
|
String aliasRight,
|
||||||
|
@ -371,6 +376,7 @@ public class Parameters {
|
||||||
QueryBuilder.appendFunctionArgument(
|
QueryBuilder.appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
queryParamCounter,
|
queryParamCounter,
|
||||||
localQueryParamValues,
|
localQueryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
@ -393,6 +399,7 @@ public class Parameters {
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
|
* @param aliasToComponentPropertyNameMap alias to component property name map, never {@literal null}
|
||||||
* @param aliasLeft the optional alias of the left property, may be {@literal null}
|
* @param aliasLeft the optional alias of the left property, may be {@literal null}
|
||||||
* @param left the property.
|
* @param left the property.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
|
@ -401,6 +408,7 @@ public class Parameters {
|
||||||
public void addWhereWithFunction(
|
public void addWhereWithFunction(
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String aliasLeft,
|
String aliasLeft,
|
||||||
String left,
|
String left,
|
||||||
String op,
|
String op,
|
||||||
|
@ -417,6 +425,7 @@ public class Parameters {
|
||||||
QueryBuilder.appendFunctionArgument(
|
QueryBuilder.appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
queryParamCounter,
|
queryParamCounter,
|
||||||
localQueryParamValues,
|
localQueryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
@ -432,6 +441,7 @@ public class Parameters {
|
||||||
*
|
*
|
||||||
* @param configuration the configuration.
|
* @param configuration the configuration.
|
||||||
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
* @param aliasToEntityNameMap alias to entity name map, never {@literal null}
|
||||||
|
* @param aliasToComponentPropertyNameMap alias to component property name map, never {@literal null}
|
||||||
* @param left the left-side function.
|
* @param left the left-side function.
|
||||||
* @param op the operator.
|
* @param op the operator.
|
||||||
* @param right the right-side function.
|
* @param right the right-side function.
|
||||||
|
@ -439,6 +449,7 @@ public class Parameters {
|
||||||
public void addWhereWithFunction(
|
public void addWhereWithFunction(
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
AuditFunction left,
|
AuditFunction left,
|
||||||
String op,
|
String op,
|
||||||
AuditFunction right) {
|
AuditFunction right) {
|
||||||
|
@ -447,6 +458,7 @@ public class Parameters {
|
||||||
QueryBuilder.appendFunctionArgument(
|
QueryBuilder.appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
queryParamCounter,
|
queryParamCounter,
|
||||||
localQueryParamValues,
|
localQueryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
@ -459,6 +471,7 @@ public class Parameters {
|
||||||
QueryBuilder.appendFunctionArgument(
|
QueryBuilder.appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
queryParamCounter,
|
queryParamCounter,
|
||||||
localQueryParamValues,
|
localQueryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
|
|
@ -26,10 +26,10 @@ import org.hibernate.envers.internal.entities.RevisionTypeType;
|
||||||
import org.hibernate.envers.internal.entities.mapper.id.QueryParameterData;
|
import org.hibernate.envers.internal.entities.mapper.id.QueryParameterData;
|
||||||
import org.hibernate.envers.internal.tools.MutableInteger;
|
import org.hibernate.envers.internal.tools.MutableInteger;
|
||||||
import org.hibernate.envers.internal.tools.StringTools;
|
import org.hibernate.envers.internal.tools.StringTools;
|
||||||
import org.hibernate.envers.internal.tools.Triple;
|
|
||||||
import org.hibernate.envers.query.criteria.AuditFunction;
|
import org.hibernate.envers.query.criteria.AuditFunction;
|
||||||
import org.hibernate.envers.query.criteria.AuditId;
|
import org.hibernate.envers.query.criteria.AuditId;
|
||||||
import org.hibernate.envers.query.criteria.AuditProperty;
|
import org.hibernate.envers.query.criteria.AuditProperty;
|
||||||
|
import org.hibernate.envers.query.criteria.internal.CriteriaTools;
|
||||||
import org.hibernate.envers.query.order.NullPrecedence;
|
import org.hibernate.envers.query.order.NullPrecedence;
|
||||||
import org.hibernate.envers.tools.Pair;
|
import org.hibernate.envers.tools.Pair;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
@ -220,11 +220,16 @@ public class QueryBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addProjection(Configuration configuration, Map<String, String> aliasToEntityNameMap, AuditFunction function) {
|
public void addProjection(
|
||||||
|
Configuration configuration,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
|
AuditFunction function) {
|
||||||
final StringBuilder expression = new StringBuilder();
|
final StringBuilder expression = new StringBuilder();
|
||||||
appendFunctionArgument(
|
appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
paramCounter,
|
paramCounter,
|
||||||
projectionQueryParamValues,
|
projectionQueryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
@ -237,6 +242,7 @@ public class QueryBuilder {
|
||||||
protected static void appendFunctionArgument(
|
protected static void appendFunctionArgument(
|
||||||
Configuration configuration,
|
Configuration configuration,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
MutableInteger paramCounter,
|
MutableInteger paramCounter,
|
||||||
Map<String, Object> queryParamValues,
|
Map<String, Object> queryParamValues,
|
||||||
String alias,
|
String alias,
|
||||||
|
@ -253,6 +259,7 @@ public class QueryBuilder {
|
||||||
appendFunctionArgument(
|
appendFunctionArgument(
|
||||||
configuration,
|
configuration,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
paramCounter,
|
paramCounter,
|
||||||
queryParamValues,
|
queryParamValues,
|
||||||
alias,
|
alias,
|
||||||
|
@ -292,8 +299,14 @@ public class QueryBuilder {
|
||||||
if ( propertyAlias != null ) {
|
if ( propertyAlias != null ) {
|
||||||
expression.append( propertyAlias ).append( '.' );
|
expression.append( propertyAlias ).append( '.' );
|
||||||
}
|
}
|
||||||
|
String propertyPrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
configuration.getEnversService(),
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
propertyAlias
|
||||||
|
);
|
||||||
String propertyName = property.getPropertyNameGetter().get( configuration );
|
String propertyName = property.getPropertyNameGetter().get( configuration );
|
||||||
expression.append( propertyName );
|
expression.append( propertyPrefix.concat( propertyName ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String queryParam = "_p" + paramCounter.getAndIncrease();
|
String queryParam = "_p" + paramCounter.getAndIncrease();
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class AggregatedAuditExpression implements AuditCriterion, ExtendableCrit
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
|
@ -64,8 +65,15 @@ public class AggregatedAuditExpression implements AuditCriterion, ExtendableCrit
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
|
String componentPrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
effectiveAlias
|
||||||
|
);
|
||||||
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, prefixedPropertyName );
|
||||||
|
|
||||||
// Make sure our conditions are ANDed together even if the parent Parameters have a different connective
|
// Make sure our conditions are ANDed together even if the parent Parameters have a different connective
|
||||||
Parameters subParams = parameters.addSubParameters( Parameters.AND );
|
Parameters subParams = parameters.addSubParameters( Parameters.AND );
|
||||||
|
@ -78,17 +86,34 @@ public class AggregatedAuditExpression implements AuditCriterion, ExtendableCrit
|
||||||
// Adding all specified conditions both to the main query, as well as to the
|
// Adding all specified conditions both to the main query, as well as to the
|
||||||
// aggregated one.
|
// aggregated one.
|
||||||
for ( AuditCriterion versionsCriteria : criterions ) {
|
for ( AuditCriterion versionsCriteria : criterions ) {
|
||||||
versionsCriteria.addToQuery( enversService, versionsReader, aliasToEntityNameMap, effectiveAlias, qb, subParams );
|
versionsCriteria.addToQuery(
|
||||||
versionsCriteria.addToQuery( enversService, versionsReader, aliasToEntityNameMap, subQueryAlias, subQb, subQb.getRootParameters() );
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
effectiveAlias,
|
||||||
|
qb,
|
||||||
|
subParams
|
||||||
|
);
|
||||||
|
|
||||||
|
versionsCriteria.addToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
subQueryAlias,
|
||||||
|
subQb,
|
||||||
|
subQb.getRootParameters()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the desired projection of the aggregated query
|
// Setting the desired projection of the aggregated query
|
||||||
switch ( mode ) {
|
switch ( mode ) {
|
||||||
case MIN:
|
case MIN:
|
||||||
subQb.addProjection( "min", subQb.getAlias(), propertyName, false );
|
subQb.addProjection( "min", subQb.getAlias(), prefixedPropertyName, false );
|
||||||
break;
|
break;
|
||||||
case MAX:
|
case MAX:
|
||||||
subQb.addProjection( "max", subQb.getAlias(), propertyName, false );
|
subQb.addProjection( "max", subQb.getAlias(), prefixedPropertyName, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Correlating subquery with the outer query by entity id. See JIRA HHH-7827.
|
// Correlating subquery with the outer query by entity id. See JIRA HHH-7827.
|
||||||
|
@ -102,7 +127,7 @@ public class AggregatedAuditExpression implements AuditCriterion, ExtendableCrit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding the constrain on the result of the aggregated criteria
|
// Adding the constrain on the result of the aggregated criteria
|
||||||
subParams.addWhere( effectiveAlias, propertyName, "=", subQb );
|
subParams.addWhere( effectiveAlias, prefixedPropertyName, "=", subQb );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class AuditConjunction implements AuditCriterion, ExtendableCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String alias,
|
String alias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
|
@ -46,7 +47,15 @@ public class AuditConjunction implements AuditCriterion, ExtendableCriterion {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for ( AuditCriterion criterion : criterions ) {
|
for ( AuditCriterion criterion : criterions ) {
|
||||||
criterion.addToQuery( enversService, versionsReader, aliasToEntityNameMap, alias, qb, andParameters );
|
criterion.addToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
qb,
|
||||||
|
andParameters
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ public interface AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters);
|
Parameters parameters);
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class AuditDisjunction implements AuditCriterion, ExtendableCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String alias,
|
String alias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
|
@ -46,7 +47,15 @@ public class AuditDisjunction implements AuditCriterion, ExtendableCriterion {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for ( AuditCriterion criterion : criterions ) {
|
for ( AuditCriterion criterion : criterions ) {
|
||||||
criterion.addToQuery( enversService, versionsReader, aliasToEntityNameMap, alias, qb, orParameters );
|
criterion.addToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
qb,
|
||||||
|
orParameters
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,9 +240,15 @@ public class AuditFunction implements AuditProjection {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor auditReader,
|
AuditReaderImplementor auditReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder) {
|
QueryBuilder queryBuilder) {
|
||||||
queryBuilder.addProjection( enversService.getConfig(), aliasToEntityNameMap, this );
|
queryBuilder.addProjection(
|
||||||
|
enversService.getConfig(),
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
this
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -405,20 +405,33 @@ public class AuditProperty<T> implements AuditProjection {
|
||||||
// Projection on this property
|
// Projection on this property
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
public void addProjectionToQuery(
|
||||||
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder) {
|
||||||
String projectionEntityAlias = getAlias( baseAlias );
|
String projectionEntityAlias = getAlias( baseAlias );
|
||||||
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
enversService,
|
enversService,
|
||||||
auditReader,
|
auditReader,
|
||||||
projectionEntityName,
|
projectionEntityName,
|
||||||
propertyNameGetter );
|
propertyNameGetter
|
||||||
|
);
|
||||||
|
String propertyNamePrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
projectionEntityAlias
|
||||||
|
);
|
||||||
queryBuilder.addProjection(
|
queryBuilder.addProjection(
|
||||||
null,
|
null,
|
||||||
projectionEntityAlias,
|
projectionEntityAlias,
|
||||||
propertyName,
|
propertyNamePrefix.concat( propertyName ),
|
||||||
false );
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order
|
// Order
|
||||||
|
@ -438,7 +451,12 @@ public class AuditProperty<T> implements AuditProjection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convertQueryResult(EnversService enversService, EntityInstantiator entityInstantiator, String entityName, Number revision, Object value) {
|
public Object convertQueryResult(
|
||||||
|
EnversService enversService,
|
||||||
|
EntityInstantiator entityInstantiator,
|
||||||
|
String entityName,
|
||||||
|
Number revision,
|
||||||
|
Object value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ import org.hibernate.envers.query.criteria.AuditCriterion;
|
||||||
* the corresponding entity name. The effect alias is either the alias that has been
|
* the corresponding entity name. The effect alias is either the alias that has been
|
||||||
* specified at creation time of this expression or if that alias is null, the base
|
* specified at creation time of this expression or if that alias is null, the base
|
||||||
* alias is used. This calculation is done in the
|
* alias is used. This calculation is done in the
|
||||||
* {@link AuditCriterion#addToQuery(EnversService, AuditReaderImplementor, Map, String, QueryBuilder, Parameters)}
|
* {@link AuditCriterion#addToQuery(EnversService, AuditReaderImplementor, Map, Map, String, QueryBuilder, Parameters)}
|
||||||
* implementation and then delegated for the concrete work to the template method
|
* implementation and then delegated for the concrete work to the template method
|
||||||
* {@link #addToQuery(EnversService, AuditReaderImplementor, String, String, QueryBuilder, Parameters)}.
|
* {@link #addToQuery(EnversService, AuditReaderImplementor, String, String, String, QueryBuilder, Parameters)}
|
||||||
*
|
*
|
||||||
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
*/
|
*/
|
||||||
|
@ -40,12 +40,19 @@ abstract class AbstractAtomicExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
final String effectiveAlias = alias == null ? baseAlias : alias;
|
final String effectiveAlias = alias == null ? baseAlias : alias;
|
||||||
final String entityName = aliasToEntityNameMap.get( effectiveAlias );
|
final String entityName = aliasToEntityNameMap.get( effectiveAlias );
|
||||||
addToQuery(enversService, versionsReader, entityName, effectiveAlias, qb, parameters);
|
final String componentPrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
effectiveAlias
|
||||||
|
);
|
||||||
|
addToQuery(enversService, versionsReader, entityName, effectiveAlias, componentPrefix, qb, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void addToQuery(
|
protected abstract void addToQuery(
|
||||||
|
@ -53,6 +60,7 @@ abstract class AbstractAtomicExpression implements AuditCriterion {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters);
|
Parameters parameters);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class BetweenAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -41,10 +42,11 @@ public class BetweenAuditExpression extends AbstractAtomicExpression {
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, prefixedPropertyName );
|
||||||
|
|
||||||
Parameters subParams = parameters.addSubParameters( Parameters.AND );
|
Parameters subParams = parameters.addSubParameters( Parameters.AND );
|
||||||
subParams.addWhereWithParam( alias, propertyName, ">=", lo );
|
subParams.addWhereWithParam( alias, prefixedPropertyName, ">=", lo );
|
||||||
subParams.addWhereWithParam( alias, propertyName, "<=", hi );
|
subParams.addWhereWithParam( alias, prefixedPropertyName, "<=", hi );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,12 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.exception.AuditException;
|
import org.hibernate.envers.exception.AuditException;
|
||||||
|
import org.hibernate.envers.internal.entities.ComponentDescription;
|
||||||
import org.hibernate.envers.internal.entities.RelationDescription;
|
import org.hibernate.envers.internal.entities.RelationDescription;
|
||||||
import org.hibernate.envers.internal.entities.RelationType;
|
import org.hibernate.envers.internal.entities.RelationType;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
@ -66,6 +68,13 @@ public abstract class CriteriaTools {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ComponentDescription getComponent(
|
||||||
|
EnversService enversService,
|
||||||
|
String entityName,
|
||||||
|
String propertyName) {
|
||||||
|
return enversService.getEntitiesConfigurations().getComponentDescription( entityName, propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
public static String determinePropertyName(
|
public static String determinePropertyName(
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
|
@ -119,6 +128,36 @@ public abstract class CriteriaTools {
|
||||||
return propertyName;
|
return propertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param enversService The EnversService
|
||||||
|
* @param aliasToEntityNameMap the map from aliases to entity names
|
||||||
|
* @param aliasToComponentPropertyNameMap the map from aliases to component property name, if an alias is for a
|
||||||
|
* component
|
||||||
|
* @param alias the alias
|
||||||
|
* @return The prefix that has to be used when referring to a property of a component. If no prefix is required or
|
||||||
|
* the alias is not a component, the empty string is returned (but never null)
|
||||||
|
*/
|
||||||
|
public static String determineComponentPropertyPrefix(
|
||||||
|
EnversService enversService,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
|
String alias) {
|
||||||
|
String componentPrefix = "";
|
||||||
|
final String entityName = aliasToEntityNameMap.get( alias );
|
||||||
|
final String owningComponentPropertyName = aliasToComponentPropertyNameMap.get( alias );
|
||||||
|
if ( owningComponentPropertyName != null ) {
|
||||||
|
final ComponentDescription componentDescription = CriteriaTools.getComponent(
|
||||||
|
enversService,
|
||||||
|
entityName,
|
||||||
|
owningComponentPropertyName
|
||||||
|
);
|
||||||
|
if ( componentDescription.getType() == ComponentDescription.ComponentType.ONE ) {
|
||||||
|
componentPrefix = componentDescription.getPropertyName().concat( "_" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return componentPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param sessionFactory Session factory.
|
* @param sessionFactory Session factory.
|
||||||
* @param entityName Entity name.
|
* @param entityName Entity name.
|
||||||
|
|
|
@ -40,12 +40,14 @@ public class FunctionFunctionAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor auditReader,
|
AuditReaderImplementor auditReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder,
|
QueryBuilder queryBuilder,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
parameters.addWhereWithFunction(
|
parameters.addWhereWithFunction(
|
||||||
enversService.getConfig(),
|
enversService.getConfig(),
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
leftFunction,
|
leftFunction,
|
||||||
op,
|
op,
|
||||||
rightFunction
|
rightFunction
|
||||||
|
|
|
@ -45,6 +45,7 @@ public class FunctionPropertyAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor auditReader,
|
AuditReaderImplementor auditReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder,
|
QueryBuilder queryBuilder,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
|
@ -54,13 +55,22 @@ public class FunctionPropertyAuditExpression implements AuditCriterion {
|
||||||
enversService,
|
enversService,
|
||||||
auditReader,
|
auditReader,
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter );
|
propertyNameGetter
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
);
|
||||||
|
String propertyNamePrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
effectiveAlias
|
||||||
|
);
|
||||||
|
String prefixedPropertyName = propertyNamePrefix.concat( propertyName );
|
||||||
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, prefixedPropertyName );
|
||||||
parameters.addWhereWithFunction(
|
parameters.addWhereWithFunction(
|
||||||
enversService.getConfig(),
|
enversService.getConfig(),
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
effectiveAlias,
|
effectiveAlias,
|
||||||
propertyName,
|
prefixedPropertyName,
|
||||||
op,
|
op,
|
||||||
function
|
function
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class IdentifierEqAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String prefix = enversService.getConfig().getOriginalIdPropertyName();
|
String prefix = enversService.getConfig().getOriginalIdPropertyName();
|
||||||
|
|
|
@ -27,8 +27,12 @@ public class IlikeAuditExpression extends AbstractAtomicExpression {
|
||||||
@Override
|
@Override
|
||||||
protected void addToQuery(
|
protected void addToQuery(
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader, String entityName,
|
AuditReaderImplementor versionsReader,
|
||||||
String alias, QueryBuilder qb, Parameters parameters) {
|
String entityName,
|
||||||
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
|
QueryBuilder qb,
|
||||||
|
Parameters parameters) {
|
||||||
|
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
enversService,
|
enversService,
|
||||||
|
@ -36,9 +40,10 @@ public class IlikeAuditExpression extends AbstractAtomicExpression {
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
|
||||||
|
|
||||||
parameters.addWhereWithFunction( alias, propertyName, " lower ", " like ", value.toLowerCase( Locale.ROOT ) );
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, prefixedPropertyName );
|
||||||
|
parameters.addWhereWithFunction( alias, prefixedPropertyName, " lower ", " like ", value.toLowerCase( Locale.ROOT ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class InAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -39,7 +40,8 @@ public class InAuditExpression extends AbstractAtomicExpression {
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
parameters.addWhereWithParams( alias, propertyName, "in (", values, ")" );
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, prefixedPropertyName );
|
||||||
|
parameters.addWhereWithParams( alias, prefixedPropertyName, "in (", values, ")" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,30 @@ public class LogicalAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String alias,
|
String alias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
Parameters opParameters = parameters.addSubParameters( op );
|
Parameters opParameters = parameters.addSubParameters( op );
|
||||||
|
|
||||||
lhs.addToQuery( enversService, versionsReader, aliasToEntityNameMap, alias, qb, opParameters.addSubParameters( "and" ) );
|
lhs.addToQuery(
|
||||||
rhs.addToQuery( enversService, versionsReader, aliasToEntityNameMap, alias, qb, opParameters.addSubParameters( "and" ) );
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
qb,
|
||||||
|
opParameters.addSubParameters( "and" )
|
||||||
|
);
|
||||||
|
|
||||||
|
rhs.addToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
qb,
|
||||||
|
opParameters.addSubParameters( "and" )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,18 @@ public class NotAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String alias,
|
String alias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
criterion.addToQuery( enversService, versionsReader, aliasToEntityNameMap, alias, qb, parameters.addNegatedParameters() );
|
criterion.addToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
qb,
|
||||||
|
parameters.addNegatedParameters()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class NotNullAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -42,10 +43,11 @@ public class NotNullAuditExpression extends AbstractAtomicExpression {
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, propertyName );
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, prefixedPropertyName );
|
||||||
|
|
||||||
if ( relatedEntity == null ) {
|
if ( relatedEntity == null ) {
|
||||||
parameters.addNotNullRestriction( alias, propertyName );
|
parameters.addNotNullRestriction( alias, prefixedPropertyName );
|
||||||
}
|
}
|
||||||
else if ( relatedEntity.getRelationType() == RelationType.TO_ONE ) {
|
else if ( relatedEntity.getRelationType() == RelationType.TO_ONE ) {
|
||||||
relatedEntity.getIdMapper().addIdEqualsToQuery( parameters, null, alias, null, false );
|
relatedEntity.getIdMapper().addIdEqualsToQuery( parameters, null, alias, null, false );
|
||||||
|
|
|
@ -34,6 +34,7 @@ public class NullAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -43,9 +44,10 @@ public class NullAuditExpression extends AbstractAtomicExpression {
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, propertyName );
|
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, propertyName );
|
||||||
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
|
||||||
if ( relatedEntity == null ) {
|
if ( relatedEntity == null ) {
|
||||||
parameters.addNullRestriction( alias, propertyName );
|
parameters.addNullRestriction( alias, prefixedPropertyName );
|
||||||
}
|
}
|
||||||
else if ( relatedEntity.getRelationType() == RelationType.TO_ONE ) {
|
else if ( relatedEntity.getRelationType() == RelationType.TO_ONE ) {
|
||||||
relatedEntity.getIdMapper().addIdEqualsToQuery( parameters, null, alias, null, true );
|
relatedEntity.getIdMapper().addIdEqualsToQuery( parameters, null, alias, null, true );
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class PropertyAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
|
@ -57,15 +58,29 @@ public class PropertyAuditExpression implements AuditCriterion {
|
||||||
entityName,
|
entityName,
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, entityName, propertyName );
|
String propertyNamePrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
effectiveAlias
|
||||||
|
);
|
||||||
|
String otherPropertyNamePrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
effectiveOtherAlias
|
||||||
|
);
|
||||||
|
String prefixedPropertyName = propertyNamePrefix.concat( propertyName );
|
||||||
|
String prefixedOtherPropertyName = otherPropertyNamePrefix.concat( otherPropertyName );
|
||||||
|
CriteriaTools.checkPropertyNotARelation( enversService, entityName, prefixedPropertyName );
|
||||||
/*
|
/*
|
||||||
* Check that the other property name is not a relation. However, we can only
|
* Check that the other property name is not a relation. However, we can only
|
||||||
* do this for audited entities. If the other property belongs to a non-audited
|
* do this for audited entities. If the other property belongs to a non-audited
|
||||||
* entity, we have to skip this check.
|
* entity, we have to skip this check.
|
||||||
*/
|
*/
|
||||||
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, otherEntityName, otherPropertyName );
|
CriteriaTools.checkPropertyNotARelation( enversService, otherEntityName, prefixedOtherPropertyName );
|
||||||
}
|
}
|
||||||
parameters.addWhere( effectiveAlias, propertyName, op, effectiveOtherAlias, otherPropertyName );
|
parameters.addWhere( effectiveAlias, prefixedPropertyName, op, effectiveOtherAlias, prefixedOtherPropertyName );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ public class PropertyFunctionAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor auditReader,
|
AuditReaderImplementor auditReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder,
|
QueryBuilder queryBuilder,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
|
@ -53,11 +54,21 @@ public class PropertyFunctionAuditExpression implements AuditCriterion {
|
||||||
* the other property belongs to a non-audited entity, we have to skip this check.
|
* the other property belongs to a non-audited entity, we have to skip this check.
|
||||||
*/
|
*/
|
||||||
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
if ( enversService.getEntitiesConfigurations().isVersioned( otherEntityName ) ) {
|
||||||
CriteriaTools.checkPropertyNotARelation( enversService, otherEntityName, otherPropertyName );
|
String otherPropertyNamePrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap, effectiveOtherAlias
|
||||||
|
);
|
||||||
|
CriteriaTools.checkPropertyNotARelation(
|
||||||
|
enversService,
|
||||||
|
otherEntityName,
|
||||||
|
otherPropertyNamePrefix.concat( otherPropertyName )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
parameters.addWhereWithFunction(
|
parameters.addWhereWithFunction(
|
||||||
enversService.getConfig(),
|
enversService.getConfig(),
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
function,
|
function,
|
||||||
op,
|
op,
|
||||||
effectiveOtherAlias,
|
effectiveOtherAlias,
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class RelatedAuditEqualityExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -48,7 +49,12 @@ public class RelatedAuditEqualityExpression extends AbstractAtomicExpression {
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
|
|
||||||
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, propertyName );
|
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity(
|
||||||
|
enversService,
|
||||||
|
entityName,
|
||||||
|
componentPrefix.concat( propertyName )
|
||||||
|
);
|
||||||
|
|
||||||
if ( relatedEntity == null ) {
|
if ( relatedEntity == null ) {
|
||||||
throw new AuditException(
|
throw new AuditException(
|
||||||
"This criterion can only be used on a property that is a relation to another property." );
|
"This criterion can only be used on a property that is a relation to another property." );
|
||||||
|
|
|
@ -40,6 +40,7 @@ public class RelatedAuditInExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -49,7 +50,12 @@ public class RelatedAuditInExpression extends AbstractAtomicExpression {
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
|
|
||||||
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, propertyName );
|
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity(
|
||||||
|
enversService,
|
||||||
|
entityName,
|
||||||
|
componentPrefix.concat( propertyName )
|
||||||
|
);
|
||||||
|
|
||||||
if ( relatedEntity == null ) {
|
if ( relatedEntity == null ) {
|
||||||
throw new AuditException(
|
throw new AuditException(
|
||||||
"The criterion can only be used on a property that is a relation to another property." );
|
"The criterion can only be used on a property that is a relation to another property." );
|
||||||
|
@ -69,7 +75,7 @@ public class RelatedAuditInExpression extends AbstractAtomicExpression {
|
||||||
List<QueryParameterData> qpdList = relatedEntity.getIdMapper().mapToQueryParametersFromId( propertyName );
|
List<QueryParameterData> qpdList = relatedEntity.getIdMapper().mapToQueryParametersFromId( propertyName );
|
||||||
if ( qpdList != null ) {
|
if ( qpdList != null ) {
|
||||||
QueryParameterData qpd = qpdList.iterator().next();
|
QueryParameterData qpd = qpdList.iterator().next();
|
||||||
parameters.addWhereWithParams( alias, qpd.getQueryParameterName(), "in (", ids, ")" );
|
parameters.addWhereWithParams( alias, componentPrefix.concat( qpd.getQueryParameterName() ), "in (", ids, ")" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class RevisionTypeAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
parameters.addWhereWithParam( alias, enversService.getConfig().getRevisionTypePropertyName(), op, value );
|
parameters.addWhereWithParam( alias, enversService.getConfig().getRevisionTypePropertyName(), op, value );
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Locale;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.exception.AuditException;
|
import org.hibernate.envers.exception.AuditException;
|
||||||
|
import org.hibernate.envers.internal.entities.ComponentDescription;
|
||||||
import org.hibernate.envers.internal.entities.RelationDescription;
|
import org.hibernate.envers.internal.entities.RelationDescription;
|
||||||
import org.hibernate.envers.internal.entities.RelationType;
|
import org.hibernate.envers.internal.entities.RelationType;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
@ -25,6 +26,7 @@ import org.hibernate.type.Type;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class SimpleAuditExpression extends AbstractAtomicExpression {
|
public class SimpleAuditExpression extends AbstractAtomicExpression {
|
||||||
|
|
||||||
private PropertyNameGetter propertyNameGetter;
|
private PropertyNameGetter propertyNameGetter;
|
||||||
private Object value;
|
private Object value;
|
||||||
private String op;
|
private String op;
|
||||||
|
@ -42,6 +44,7 @@ public class SimpleAuditExpression extends AbstractAtomicExpression {
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
String entityName,
|
String entityName,
|
||||||
String alias,
|
String alias,
|
||||||
|
String componentPrefix,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
String propertyName = CriteriaTools.determinePropertyName(
|
String propertyName = CriteriaTools.determinePropertyName(
|
||||||
|
@ -51,7 +54,8 @@ public class SimpleAuditExpression extends AbstractAtomicExpression {
|
||||||
propertyNameGetter
|
propertyNameGetter
|
||||||
);
|
);
|
||||||
|
|
||||||
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, propertyName );
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
RelationDescription relatedEntity = CriteriaTools.getRelatedEntity( enversService, entityName, prefixedPropertyName );
|
||||||
|
|
||||||
if ( relatedEntity == null ) {
|
if ( relatedEntity == null ) {
|
||||||
// HHH-9178 - Add support to component type equality.
|
// HHH-9178 - Add support to component type equality.
|
||||||
|
@ -75,14 +79,14 @@ public class SimpleAuditExpression extends AbstractAtomicExpression {
|
||||||
final Object componentValue = componentType.getPropertyValue( value, i, session );
|
final Object componentValue = componentType.getPropertyValue( value, i, session );
|
||||||
parameters.addWhereWithParam(
|
parameters.addWhereWithParam(
|
||||||
alias,
|
alias,
|
||||||
propertyName + "_" + componentType.getPropertyNames()[ i ],
|
prefixedPropertyName + "_" + componentType.getPropertyNames()[ i ],
|
||||||
op,
|
op,
|
||||||
componentValue
|
componentValue
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parameters.addWhereWithParam( alias, propertyName, op, value );
|
parameters.addWhereWithParam( alias, prefixedPropertyName, op, value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( relatedEntity.getRelationType() == RelationType.TO_ONE ) {
|
else if ( relatedEntity.getRelationType() == RelationType.TO_ONE ) {
|
||||||
|
|
|
@ -37,10 +37,18 @@ public class SimpleFunctionAuditExpression implements AuditCriterion {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor versionsReader,
|
AuditReaderImplementor versionsReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder qb,
|
QueryBuilder qb,
|
||||||
Parameters parameters) {
|
Parameters parameters) {
|
||||||
parameters.addWhereWithFunction( enversService.getConfig(), aliasToEntityNameMap, function, op, value );
|
parameters.addWhereWithFunction(
|
||||||
|
enversService.getConfig(),
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
function,
|
||||||
|
op,
|
||||||
|
value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
protected String versionsEntityName;
|
protected String versionsEntityName;
|
||||||
protected QueryBuilder qb;
|
protected QueryBuilder qb;
|
||||||
protected final Map<String, String> aliasToEntityNameMap = new HashMap<>();
|
protected final Map<String, String> aliasToEntityNameMap = new HashMap<>();
|
||||||
|
protected final Map<String, String> aliasToComponentPropertyNameMap = new HashMap<>();
|
||||||
|
|
||||||
protected boolean hasOrder;
|
protected boolean hasOrder;
|
||||||
|
|
||||||
|
@ -138,7 +139,14 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
String projectionEntityAlias = projection.getAlias( REFERENCED_ENTITY_ALIAS );
|
String projectionEntityAlias = projection.getAlias( REFERENCED_ENTITY_ALIAS );
|
||||||
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
registerProjection( projectionEntityName, projection );
|
registerProjection( projectionEntityName, projection );
|
||||||
projection.addProjectionToQuery( enversService, versionsReader, aliasToEntityNameMap, REFERENCED_ENTITY_ALIAS, qb );
|
projection.addProjectionToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
REFERENCED_ENTITY_ALIAS,
|
||||||
|
qb
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +170,18 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
orderEntityName,
|
orderEntityName,
|
||||||
orderData.getPropertyName()
|
orderData.getPropertyName()
|
||||||
);
|
);
|
||||||
qb.addOrder( orderEntityAlias, propertyName, orderData.isAscending(), orderData.getNullPrecedence() );
|
String componentPrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
orderEntityAlias
|
||||||
|
);
|
||||||
|
qb.addOrder(
|
||||||
|
orderEntityAlias,
|
||||||
|
componentPrefix.concat( propertyName ),
|
||||||
|
orderData.isAscending(),
|
||||||
|
orderData.getNullPrecedence()
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +206,7 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
associationName,
|
associationName,
|
||||||
joinType,
|
joinType,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
REFERENCED_ENTITY_ALIAS,
|
REFERENCED_ENTITY_ALIAS,
|
||||||
alias
|
alias
|
||||||
);
|
);
|
||||||
|
@ -312,7 +332,15 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
if ( projections.size() == 1 ) {
|
if ( projections.size() == 1 ) {
|
||||||
// qr is the value of the projection itself
|
// qr is the value of the projection itself
|
||||||
final Pair<String, AuditProjection> projection = projections.get( 0 );
|
final Pair<String, AuditProjection> projection = projections.get( 0 );
|
||||||
result.add( projection.getSecond().convertQueryResult( enversService, entityInstantiator, projection.getFirst(), revision, qr ) );
|
result.add(
|
||||||
|
projection.getSecond().convertQueryResult(
|
||||||
|
enversService,
|
||||||
|
entityInstantiator,
|
||||||
|
projection.getFirst(),
|
||||||
|
revision,
|
||||||
|
qr
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// qr is an array where each of its components holds the value of corresponding projection
|
// qr is an array where each of its components holds the value of corresponding projection
|
||||||
|
@ -320,7 +348,13 @@ public abstract class AbstractAuditQuery implements AuditQueryImplementor {
|
||||||
Object[] tresults = new Object[qresults.length];
|
Object[] tresults = new Object[qresults.length];
|
||||||
for ( int i = 0; i < qresults.length; i++ ) {
|
for ( int i = 0; i < qresults.length; i++ ) {
|
||||||
final Pair<String, AuditProjection> projection = projections.get( i );
|
final Pair<String, AuditProjection> projection = projections.get( i );
|
||||||
tresults[i] = projection.getSecond().convertQueryResult( enversService, entityInstantiator, projection.getFirst(), revision, qresults[i] );
|
tresults[i] = projection.getSecond().convertQueryResult(
|
||||||
|
enversService,
|
||||||
|
entityInstantiator,
|
||||||
|
projection.getFirst(),
|
||||||
|
revision,
|
||||||
|
qresults[i]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
result.add( tresults );
|
result.add( tresults );
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ import org.hibernate.envers.RevisionType;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.configuration.Configuration;
|
import org.hibernate.envers.configuration.Configuration;
|
||||||
import org.hibernate.envers.exception.AuditException;
|
import org.hibernate.envers.exception.AuditException;
|
||||||
|
import org.hibernate.envers.internal.entities.ComponentDescription;
|
||||||
|
import org.hibernate.envers.internal.entities.ComponentDescription.ComponentType;
|
||||||
import org.hibernate.envers.internal.entities.RelationDescription;
|
import org.hibernate.envers.internal.entities.RelationDescription;
|
||||||
import org.hibernate.envers.internal.entities.RelationType;
|
import org.hibernate.envers.internal.entities.RelationType;
|
||||||
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
import org.hibernate.envers.internal.entities.mapper.id.IdMapper;
|
||||||
|
@ -51,10 +53,12 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
private final JoinType joinType;
|
private final JoinType joinType;
|
||||||
private final String entityName;
|
private final String entityName;
|
||||||
private final RelationDescription relationDescription;
|
private final RelationDescription relationDescription;
|
||||||
|
private final ComponentDescription componentDescription;
|
||||||
private final String ownerAlias;
|
private final String ownerAlias;
|
||||||
private final String ownerEntityName;
|
private final String ownerEntityName;
|
||||||
private final String alias;
|
private final String alias;
|
||||||
private final Map<String, String> aliasToEntityNameMap;
|
private final Map<String, String> aliasToEntityNameMap;
|
||||||
|
private final Map<String, String> aliasToComponentPropertyNameMap;
|
||||||
private final List<AuditCriterion> criterions = new ArrayList<>();
|
private final List<AuditCriterion> criterions = new ArrayList<>();
|
||||||
private final Parameters parameters;
|
private final Parameters parameters;
|
||||||
private final List<AuditAssociationQueryImpl<?>> associationQueries = new ArrayList<>();
|
private final List<AuditAssociationQueryImpl<?>> associationQueries = new ArrayList<>();
|
||||||
|
@ -68,6 +72,7 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
final String propertyName,
|
final String propertyName,
|
||||||
final JoinType joinType,
|
final JoinType joinType,
|
||||||
final Map<String, String> aliasToEntityNameMap,
|
final Map<String, String> aliasToEntityNameMap,
|
||||||
|
final Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
final String ownerAlias,
|
final String ownerAlias,
|
||||||
final String userSuppliedAlias) {
|
final String userSuppliedAlias) {
|
||||||
this.enversService = enversService;
|
this.enversService = enversService;
|
||||||
|
@ -77,12 +82,26 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
this.joinType = joinType;
|
this.joinType = joinType;
|
||||||
|
|
||||||
ownerEntityName = aliasToEntityNameMap.get( ownerAlias );
|
ownerEntityName = aliasToEntityNameMap.get( ownerAlias );
|
||||||
final RelationDescription relationDescription = CriteriaTools.getRelatedEntity(
|
this.ownerAlias = ownerAlias;
|
||||||
|
this.alias = userSuppliedAlias == null ? queryBuilder.generateAlias() : userSuppliedAlias;
|
||||||
|
|
||||||
|
String componentPrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
ownerAlias
|
||||||
|
);
|
||||||
|
String prefixedPropertyName = componentPrefix.concat( propertyName );
|
||||||
|
|
||||||
|
relationDescription = CriteriaTools.getRelatedEntity(
|
||||||
enversService,
|
enversService,
|
||||||
ownerEntityName,
|
ownerEntityName,
|
||||||
propertyName
|
prefixedPropertyName
|
||||||
);
|
);
|
||||||
if ( relationDescription == null ) {
|
|
||||||
|
componentDescription = CriteriaTools.getComponent( enversService, ownerEntityName, prefixedPropertyName );
|
||||||
|
|
||||||
|
if ( relationDescription == null && componentDescription == null ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
String.format(
|
String.format(
|
||||||
Locale.ENGLISH,
|
Locale.ENGLISH,
|
||||||
|
@ -92,12 +111,17 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.entityName = relationDescription.getToEntityName();
|
|
||||||
this.relationDescription = relationDescription;
|
if ( relationDescription != null ) {
|
||||||
this.ownerAlias = ownerAlias;
|
this.entityName = relationDescription.getToEntityName();
|
||||||
this.alias = userSuppliedAlias == null ? queryBuilder.generateAlias() : userSuppliedAlias;
|
}
|
||||||
|
else {
|
||||||
|
aliasToComponentPropertyNameMap.put( alias, componentDescription.getPropertyName() );
|
||||||
|
this.entityName = ownerEntityName;
|
||||||
|
}
|
||||||
aliasToEntityNameMap.put( this.alias, entityName );
|
aliasToEntityNameMap.put( this.alias, entityName );
|
||||||
this.aliasToEntityNameMap = aliasToEntityNameMap;
|
this.aliasToEntityNameMap = aliasToEntityNameMap;
|
||||||
|
this.aliasToComponentPropertyNameMap = aliasToComponentPropertyNameMap;
|
||||||
parameters = queryBuilder.addParameters( this.alias );
|
parameters = queryBuilder.addParameters( this.alias );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +166,7 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
associationName,
|
associationName,
|
||||||
joinType,
|
joinType,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
this.alias,
|
this.alias,
|
||||||
alias
|
alias
|
||||||
);
|
);
|
||||||
|
@ -162,7 +187,14 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
String projectionEntityAlias = projection.getAlias( alias );
|
String projectionEntityAlias = projection.getAlias( alias );
|
||||||
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
String projectionEntityName = aliasToEntityNameMap.get( projectionEntityAlias );
|
||||||
registerProjection( projectionEntityName, projection );
|
registerProjection( projectionEntityName, projection );
|
||||||
projection.addProjectionToQuery( enversService, auditReader, aliasToEntityNameMap, alias, queryBuilder );
|
projection.addProjectionToQuery(
|
||||||
|
enversService,
|
||||||
|
auditReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
queryBuilder
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +209,18 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
orderEntityName,
|
orderEntityName,
|
||||||
orderData.getPropertyName()
|
orderData.getPropertyName()
|
||||||
);
|
);
|
||||||
queryBuilder.addOrder( orderEntityAlias, propertyName, orderData.isAscending(), orderData.getNullPrecedence() );
|
String componentPrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
orderEntityAlias
|
||||||
|
);
|
||||||
|
queryBuilder.addOrder(
|
||||||
|
orderEntityAlias,
|
||||||
|
componentPrefix.concat( propertyName ),
|
||||||
|
orderData.isAscending(),
|
||||||
|
orderData.getNullPrecedence()
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +283,31 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addCriterionsToQuery(AuditReaderImplementor versionsReader) {
|
protected void addCriterionsToQuery(AuditReaderImplementor versionsReader) {
|
||||||
final Configuration configuration = enversService.getConfig();
|
if ( relationDescription != null ) {
|
||||||
|
createEntityJoin( enversService.getConfig() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createComponentJoin( enversService.getConfig() );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( AuditCriterion criterion : criterions ) {
|
||||||
|
criterion.addToQuery(
|
||||||
|
enversService,
|
||||||
|
versionsReader,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
alias,
|
||||||
|
queryBuilder,
|
||||||
|
parameters
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( AuditAssociationQueryImpl<?> query : associationQueries ) {
|
||||||
|
query.addCriterionsToQuery( versionsReader );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createEntityJoin(Configuration configuration) {
|
||||||
boolean targetIsAudited = enversService.getEntitiesConfigurations().isVersioned( entityName );
|
boolean targetIsAudited = enversService.getEntitiesConfigurations().isVersioned( entityName );
|
||||||
String targetEntityName = entityName;
|
String targetEntityName = entityName;
|
||||||
if ( targetIsAudited ) {
|
if ( targetIsAudited ) {
|
||||||
|
@ -414,22 +481,85 @@ public class AuditAssociationQueryImpl<Q extends AuditQueryImplementor>
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for ( AuditCriterion criterion : criterions ) {
|
private void createComponentJoin(Configuration configuration) {
|
||||||
criterion.addToQuery(
|
String originalIdPropertyName = configuration.getOriginalIdPropertyName();
|
||||||
enversService,
|
String revisionPropertyPath = configuration.getRevisionNumberPath();
|
||||||
versionsReader,
|
if ( componentDescription.getType() == ComponentType.MANY ) {
|
||||||
aliasToEntityNameMap,
|
// join middle_entity
|
||||||
|
Parameters joinConditionParameters = queryBuilder.addJoin(
|
||||||
|
joinType,
|
||||||
|
componentDescription.getAuditMiddleEntityName(),
|
||||||
alias,
|
alias,
|
||||||
queryBuilder,
|
false
|
||||||
parameters
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
for ( final AuditAssociationQueryImpl<?> sub : associationQueries ) {
|
String middleOriginalIdPropertyPath = alias + "." + originalIdPropertyName;
|
||||||
sub.addCriterionsToQuery( versionsReader );
|
// join condition: owner.reference_id = middle.id_ref_ing
|
||||||
}
|
String ownerPrefix = ownerAlias + "." + originalIdPropertyName;
|
||||||
|
MiddleIdData middleIdData = componentDescription.getMiddleIdData();
|
||||||
|
middleIdData.getPrefixedMapper().addIdsEqualToQuery(
|
||||||
|
joinConditionParameters,
|
||||||
|
middleOriginalIdPropertyPath,
|
||||||
|
middleIdData.getOriginalMapper(),
|
||||||
|
ownerPrefix
|
||||||
|
);
|
||||||
|
|
||||||
|
// filter revisions of middle entity
|
||||||
|
Parameters middleParameters = queryBuilder.addParameters( alias );
|
||||||
|
Parameters middleParametersToUse = middleParameters;
|
||||||
|
if ( joinType == JoinType.LEFT ) {
|
||||||
|
middleParametersToUse = middleParameters.addSubParameters( Parameters.OR );
|
||||||
|
middleParametersToUse.addNullRestriction( revisionPropertyPath, true );
|
||||||
|
middleParametersToUse = middleParametersToUse.addSubParameters( Parameters.AND );
|
||||||
|
}
|
||||||
|
configuration.getAuditStrategy().addAssociationAtRevisionRestriction(
|
||||||
|
queryBuilder,
|
||||||
|
middleParametersToUse,
|
||||||
|
revisionPropertyPath,
|
||||||
|
configuration.getRevisionEndFieldName(),
|
||||||
|
true,
|
||||||
|
middleIdData,
|
||||||
|
componentDescription.getAuditMiddleEntityName(),
|
||||||
|
middleOriginalIdPropertyPath,
|
||||||
|
revisionPropertyPath,
|
||||||
|
originalIdPropertyName,
|
||||||
|
alias,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// filter deleted middle entities
|
||||||
|
String middleRevTypePropertyPath = middleOriginalIdPropertyPath + "." + configuration.getRevisionTypePropertyName();
|
||||||
|
if ( joinType == JoinType.LEFT ) {
|
||||||
|
middleParametersToUse = middleParameters.addSubParameters( Parameters.OR );
|
||||||
|
middleParametersToUse.addNullRestriction( middleRevTypePropertyPath, false );
|
||||||
|
}
|
||||||
|
middleParametersToUse.addWhereWithParam( middleRevTypePropertyPath, false, "!=", RevisionType.DEL );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ComponentType.ONE
|
||||||
|
/*
|
||||||
|
* The properties of a single component are directly mapped on the owner entity. Therefore no join would be
|
||||||
|
* required to access those properties (except the case an explicit on-clause has been specified). However,
|
||||||
|
* the user has supplied an alias and may be accessing properties of this component through that alias: If
|
||||||
|
* no join is generated, the 'virtual' alias has to be retranslated to the owning entity alias. To keep
|
||||||
|
* things simple a join on the owning entity itself is generated. The join is cheaper than other audit joins
|
||||||
|
* because we can join on the complete primary key (id + rev) and do not have to range filter on the target
|
||||||
|
* revision number.
|
||||||
|
*/
|
||||||
|
String targetEntityName = configuration.getAuditEntityName( entityName );
|
||||||
|
Parameters joinConditionParameters = queryBuilder.addJoin( joinType, targetEntityName, alias, false );
|
||||||
|
|
||||||
|
// join condition: owner.reference_id = middle.id_reference_id
|
||||||
|
String ownerPrefix = ownerAlias + "." + originalIdPropertyName;
|
||||||
|
String middleOriginalIdPropertyPath = alias + "." + originalIdPropertyName;
|
||||||
|
IdMapper idMapper = enversService.getEntitiesConfigurations().get( entityName ).getIdMapper();
|
||||||
|
idMapper.addIdsEqualToQuery( joinConditionParameters, ownerPrefix, middleOriginalIdPropertyPath );
|
||||||
|
|
||||||
|
// join condition: owner.rev=middle.rev
|
||||||
|
joinConditionParameters.addWhere( ownerAlias, revisionPropertyPath, "=", alias, revisionPropertyPath );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -114,6 +114,7 @@ public class EntitiesAtRevisionQuery extends AbstractAuditQuery {
|
||||||
enversService,
|
enversService,
|
||||||
versionsReader,
|
versionsReader,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
QueryConstants.REFERENCED_ENTITY_ALIAS,
|
QueryConstants.REFERENCED_ENTITY_ALIAS,
|
||||||
qb,
|
qb,
|
||||||
qb.getRootParameters()
|
qb.getRootParameters()
|
||||||
|
|
|
@ -66,6 +66,7 @@ public class EntitiesModifiedAtRevisionQuery extends AbstractAuditQuery {
|
||||||
enversService,
|
enversService,
|
||||||
versionsReader,
|
versionsReader,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
QueryConstants.REFERENCED_ENTITY_ALIAS,
|
QueryConstants.REFERENCED_ENTITY_ALIAS,
|
||||||
qb,
|
qb,
|
||||||
qb.getRootParameters()
|
qb.getRootParameters()
|
||||||
|
|
|
@ -112,6 +112,7 @@ public class RevisionsOfEntityQuery extends AbstractAuditQuery {
|
||||||
enversService,
|
enversService,
|
||||||
versionsReader,
|
versionsReader,
|
||||||
aliasToEntityNameMap,
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
QueryConstants.REFERENCED_ENTITY_ALIAS,
|
QueryConstants.REFERENCED_ENTITY_ALIAS,
|
||||||
qb,
|
qb,
|
||||||
qb.getRootParameters()
|
qb.getRootParameters()
|
||||||
|
|
|
@ -32,6 +32,7 @@ public interface AuditProjection {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor auditReader,
|
AuditReaderImplementor auditReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder);
|
QueryBuilder queryBuilder);
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,13 @@ public class EntityAuditProjection implements AuditProjection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addProjectionToQuery(EnversService enversService, AuditReaderImplementor auditReader,
|
public void addProjectionToQuery(
|
||||||
Map<String, String> aliasToEntityNameMap, String baseAlias, QueryBuilder queryBuilder) {
|
EnversService enversService,
|
||||||
|
AuditReaderImplementor auditReader,
|
||||||
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
|
String baseAlias,
|
||||||
|
QueryBuilder queryBuilder) {
|
||||||
String projectionEntityAlias = getAlias( baseAlias );
|
String projectionEntityAlias = getAlias( baseAlias );
|
||||||
queryBuilder.addProjection(
|
queryBuilder.addProjection(
|
||||||
null,
|
null,
|
||||||
|
|
|
@ -43,6 +43,7 @@ public class PropertyAuditProjection implements AuditProjection {
|
||||||
EnversService enversService,
|
EnversService enversService,
|
||||||
AuditReaderImplementor auditReader,
|
AuditReaderImplementor auditReader,
|
||||||
Map<String, String> aliasToEntityNameMap,
|
Map<String, String> aliasToEntityNameMap,
|
||||||
|
Map<String, String> aliasToComponentPropertyNameMap,
|
||||||
String baseAlias,
|
String baseAlias,
|
||||||
QueryBuilder queryBuilder) {
|
QueryBuilder queryBuilder) {
|
||||||
String projectionEntityAlias = getAlias( baseAlias );
|
String projectionEntityAlias = getAlias( baseAlias );
|
||||||
|
@ -51,16 +52,29 @@ public class PropertyAuditProjection implements AuditProjection {
|
||||||
enversService,
|
enversService,
|
||||||
auditReader,
|
auditReader,
|
||||||
projectionEntityName,
|
projectionEntityName,
|
||||||
propertyNameGetter );
|
propertyNameGetter
|
||||||
|
);
|
||||||
|
String propertyNamePrefix = CriteriaTools.determineComponentPropertyPrefix(
|
||||||
|
enversService,
|
||||||
|
aliasToEntityNameMap,
|
||||||
|
aliasToComponentPropertyNameMap,
|
||||||
|
projectionEntityAlias
|
||||||
|
);
|
||||||
queryBuilder.addProjection(
|
queryBuilder.addProjection(
|
||||||
function,
|
function,
|
||||||
projectionEntityAlias,
|
projectionEntityAlias,
|
||||||
propertyName,
|
propertyNamePrefix.concat( propertyName ),
|
||||||
distinct );
|
distinct
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object convertQueryResult(EnversService enversService, EntityInstantiator entityInstantiator, String entityName, Number revision, Object value) {
|
public Object convertQueryResult(
|
||||||
|
EnversService enversService,
|
||||||
|
EntityInstantiator entityInstantiator,
|
||||||
|
String entityName,
|
||||||
|
Number revision,
|
||||||
|
Object value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.envers.integration.query;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jakarta.persistence.ElementCollection;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Embedded;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.criteria.JoinType;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
import org.hibernate.envers.query.AuditEntity;
|
||||||
|
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
|
||||||
|
import org.hibernate.orm.test.envers.Priority;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@TestForIssue(jiraKey = "HHH-11895")
|
||||||
|
public class ComponentQueryTest extends BaseEnversJPAFunctionalTestCase {
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Symbol {
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
private SymbolType type;
|
||||||
|
private String identifier;
|
||||||
|
|
||||||
|
public Symbol() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Symbol(final SymbolType type, final String identifier) {
|
||||||
|
this.type = type;
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymbolType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(SymbolType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdentifier(String identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "SymbolType")
|
||||||
|
@Audited
|
||||||
|
public static class SymbolType {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Asset")
|
||||||
|
@Audited
|
||||||
|
public static class Asset {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Symbol singleSymbol;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
private Set<Symbol> multiSymbols = new HashSet<>();
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Symbol getSingleSymbol() {
|
||||||
|
return singleSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSingleSymbol(Symbol singleSymbol) {
|
||||||
|
this.singleSymbol = singleSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Symbol> getMultiSymbols() {
|
||||||
|
return multiSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMultiSymbols(Set<Symbol> multiSymbols) {
|
||||||
|
this.multiSymbols = multiSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[]{ Asset.class, Symbol.class, SymbolType.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
private SymbolType type1;
|
||||||
|
private SymbolType type2;
|
||||||
|
|
||||||
|
private Asset asset1;
|
||||||
|
private Asset asset2;
|
||||||
|
private Asset asset3;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
type1 = new SymbolType();
|
||||||
|
type1.setName( "T1" );
|
||||||
|
em.persist( type1 );
|
||||||
|
|
||||||
|
type2 = new SymbolType();
|
||||||
|
type2.setName( "T2" );
|
||||||
|
em.persist( type2 );
|
||||||
|
|
||||||
|
asset1 = new Asset();
|
||||||
|
em.persist( asset1 );
|
||||||
|
|
||||||
|
asset2 = new Asset();
|
||||||
|
asset2.setSingleSymbol( new Symbol( type1, "X1" ) );
|
||||||
|
asset2.getMultiSymbols().add( new Symbol( type1, "X" ) );
|
||||||
|
em.persist( asset2 );
|
||||||
|
|
||||||
|
asset3 = new Asset();
|
||||||
|
asset3.setSingleSymbol( new Symbol( type2, "X2" ) );
|
||||||
|
asset3.getMultiSymbols().add( new Symbol( type1, "Y" ) );
|
||||||
|
asset3.getMultiSymbols().add( new Symbol( type2, "X" ) );
|
||||||
|
em.persist( asset3 );
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleSymbolUsingIdentifier() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.traverseRelation( "singleSymbol", JoinType.INNER, "s" )
|
||||||
|
.add( AuditEntity.property( "s", "identifier" ).eq( "X1" ) )
|
||||||
|
.up()
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected only asset2 to be returned", Collections.singletonList( asset2.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiSymbolUsingIdentifier() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.traverseRelation( "multiSymbols", JoinType.INNER, "s" )
|
||||||
|
.add( AuditEntity.property( "s", "identifier" ).like( "X%" ) )
|
||||||
|
.up()
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.addOrder( AuditEntity.id().asc() )
|
||||||
|
.getResultList();
|
||||||
|
List<Integer> expected = new ArrayList<>();
|
||||||
|
Collections.addAll( expected, asset2.getId(), asset3.getId() );
|
||||||
|
assertEquals( "Expected only the ids of the assets with symbol T1", expected, actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleSymbolUsingType() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.traverseRelation( "singleSymbol", JoinType.INNER, "s" )
|
||||||
|
.add( AuditEntity.property( "s", "type" ).eq( type1 ) )
|
||||||
|
.up()
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected only asset2 to be returned", Collections.singletonList( asset2.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiSymbolUsingType() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.traverseRelation( "multiSymbols", JoinType.INNER, "s" )
|
||||||
|
.add( AuditEntity.property( "s", "type" ).eq( type2 ) )
|
||||||
|
.up()
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( " Expected only asset3 to be returned", Collections.singletonList( asset3.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinOnSingleComponentAssociation() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.traverseRelation( "singleSymbol", JoinType.INNER, "s" )
|
||||||
|
.traverseRelation( "type", JoinType.INNER, "t" )
|
||||||
|
.add( AuditEntity.property( "t", "name" ).eq( "T1" ) )
|
||||||
|
.up()
|
||||||
|
.up()
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected only asset2 to be returned", Collections.singletonList( asset2.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinOnMultiComponentAssociation() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.traverseRelation( "multiSymbols", JoinType.INNER, "s" )
|
||||||
|
.traverseRelation( "type", JoinType.INNER, "t" )
|
||||||
|
.add( AuditEntity.property( "t", "name" ).eq( "T2" ) )
|
||||||
|
.up()
|
||||||
|
.up()
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected only asset3 to be returned", Collections.singletonList( asset3.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrderingOnSingleComponent() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.traverseRelation( "singleSymbol", JoinType.LEFT, "s" )
|
||||||
|
.addOrder( AuditEntity.property( "s", "identifier" ).asc() )
|
||||||
|
.getResultList();
|
||||||
|
List<Integer> expected = new ArrayList<>();
|
||||||
|
Collections.addAll( expected, asset1.getId(), asset2.getId(), asset3.getId() );
|
||||||
|
assertEquals( "Expected all assets in correct order", expected, actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOrderingOnMultiComponent() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.traverseRelation( "multiSymbols", JoinType.LEFT, "s" )
|
||||||
|
.traverseRelation( "type", JoinType.LEFT, "t" )
|
||||||
|
.addOrder( AuditEntity.property( "t", "name" ).asc() )
|
||||||
|
.addOrder( AuditEntity.property( "s", "identifier" ).asc() )
|
||||||
|
.getResultList();
|
||||||
|
List<Integer> expected = new ArrayList<>();
|
||||||
|
Collections.addAll( expected, asset1.getId(), asset2.getId(), asset3.getId(), asset3.getId() );
|
||||||
|
assertEquals( "Expected all assets in correct order", expected, actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProjectionOnSingleComponentProperty() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.add( AuditEntity.id().eq( asset2.getId() ) )
|
||||||
|
.traverseRelation( "singleSymbol", JoinType.INNER, "s" )
|
||||||
|
.addProjection( AuditEntity.property( "s", "identifier" ) )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected the symbol identifier of asset2 to be returned", Collections.singletonList( "X1" ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProjectionOnMultiComponentProperty() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.add( AuditEntity.id().eq( asset2.getId() ) )
|
||||||
|
.traverseRelation( "multiSymbols", JoinType.INNER, "s" )
|
||||||
|
.addProjection( AuditEntity.property( "s", "identifier" ) )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected the symbol identifier of asset2 to be returned", Collections.singletonList( "X" ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFunctionOnSingleComponentProperty() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.add( AuditEntity.id().eq( asset2.getId() ) )
|
||||||
|
.traverseRelation( "singleSymbol", JoinType.INNER, "s" )
|
||||||
|
.addProjection( AuditEntity.function( "CONCAT", AuditEntity.property( "s", "identifier" ), "Z" ) )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expecte the symbol identfier of asset2 concatenated with 'Z'", Collections.singletonList( "X1Z" ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFunctionOnMultiComponentProperty() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( Asset.class, 1 )
|
||||||
|
.add( AuditEntity.id().eq( asset2.getId() ) )
|
||||||
|
.traverseRelation( "multiSymbols", JoinType.INNER, "s" )
|
||||||
|
.addProjection( AuditEntity.function( "CONCAT", AuditEntity.property( "s", "identifier" ), "Z" ) )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expecte the symbol identfier of asset2 concatenated with 'Z'", Collections.singletonList( "XZ" ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.envers.integration.query;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Embedded;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.criteria.JoinType;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
import org.hibernate.envers.query.AuditEntity;
|
||||||
|
import org.hibernate.orm.test.envers.BaseEnversJPAFunctionalTestCase;
|
||||||
|
import org.hibernate.orm.test.envers.Priority;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Felix Feisst (feisst dot felix at gmail dot com)
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-11895")
|
||||||
|
public class NestedComponentQueryTest extends BaseEnversJPAFunctionalTestCase {
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Component1 {
|
||||||
|
|
||||||
|
private String name1;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Component2 component2;
|
||||||
|
|
||||||
|
public String getName1() {
|
||||||
|
return name1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName1(String name1) {
|
||||||
|
this.name1 = name1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component2 getComponent2() {
|
||||||
|
return component2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComponent2(Component2 component2) {
|
||||||
|
this.component2 = component2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class Component2 {
|
||||||
|
|
||||||
|
private String name2;
|
||||||
|
|
||||||
|
public String getName2() {
|
||||||
|
return name2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName2(String name2) {
|
||||||
|
this.name2 = name2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "EntityOwner")
|
||||||
|
@Audited
|
||||||
|
public static class EntityOwner {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private Component1 component1;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component1 getComponent1() {
|
||||||
|
return component1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComponent1(Component1 component1) {
|
||||||
|
this.component1 = component1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class<?>[]{ EntityOwner.class, Component1.class, Component2.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityOwner owner1;
|
||||||
|
private EntityOwner owner2;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Priority(10)
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
owner1 = new EntityOwner();
|
||||||
|
Component1 component1 = new Component1();
|
||||||
|
component1.setName1( "X" );
|
||||||
|
owner1.setComponent1( component1 );
|
||||||
|
Component2 component2 = new Component2();
|
||||||
|
component2.setName2( "Y" );
|
||||||
|
component1.setComponent2( component2 );
|
||||||
|
em.persist( owner1 );
|
||||||
|
owner2 = new EntityOwner();
|
||||||
|
Component1 component12 = new Component1();
|
||||||
|
component12.setName1( "Z" );
|
||||||
|
owner2.setComponent1( component12 );
|
||||||
|
Component2 component22 = new Component2();
|
||||||
|
component22.setName2( "Z" );
|
||||||
|
component12.setComponent2( component22 );
|
||||||
|
em.persist( owner2 );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryNestedComponent() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( EntityOwner.class, 1 )
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.traverseRelation( "component1", JoinType.INNER, "c1" )
|
||||||
|
.traverseRelation( "component2", JoinType.INNER, "c2" )
|
||||||
|
.add( AuditEntity.property( "c2", "name2" ).eq( "Y" ) )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected owner1 to be returned", Collections.singletonList( owner1.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryNestedComponentWithPropertyEquals() {
|
||||||
|
List actual = getAuditReader().createQuery()
|
||||||
|
.forEntitiesAtRevision( EntityOwner.class, 1 )
|
||||||
|
.addProjection( AuditEntity.id() )
|
||||||
|
.traverseRelation( "component1", JoinType.INNER, "c1" )
|
||||||
|
.traverseRelation( "component2", JoinType.INNER, "c2" )
|
||||||
|
.add( AuditEntity.property( "c1", "name1" ).eqProperty( "c2", "name2" ) )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( "Expected owner2 to be returned", Collections.singletonList( owner2.getId() ), actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue