Cleanup support for virtual embeddable model parts and reuse existing compatible joins for implicit joins

This commit is contained in:
Christian Beikov 2021-12-21 10:47:56 +01:00
parent d5d350e5e7
commit 39484b160d
24 changed files with 543 additions and 111 deletions

View File

@ -39,10 +39,10 @@ import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.Restrictable;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
import org.hibernate.query.ComparisonOperator;
@ -340,7 +340,7 @@ public class LoaderSelectBuilder {
}
for ( ModelPart restrictedPart : restrictedParts ) {
if ( restrictedPart instanceof ForeignKeyDescriptor || restrictedPart instanceof NonAggregatedIdentifierMappingImpl ) {
if ( restrictedPart instanceof ForeignKeyDescriptor || restrictedPart instanceof NonAggregatedIdentifierMapping ) {
return true;
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.metamodel.mapping;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
@ -26,4 +27,9 @@ public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableC
EntityMappingType resolveDiscriminatorValue(Object discriminatorValue);
Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType);
@Override
default boolean isSimpleJoinPredicate(Predicate predicate) {
return predicate == null;
}
}

View File

@ -116,6 +116,8 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValueMapping {
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
boolean isSimpleJoinPredicate(Predicate predicate);
@Override
default String getPartName() {
return PART_NAME;

View File

@ -27,7 +27,7 @@ import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
* @see jakarta.persistence.IdClass
* @see jakarta.persistence.MapsId
*/
public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMapping, EmbeddableValuedFetchable, FetchOptions {
public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMapping, EmbeddableValuedFetchable, FetchOptions, VirtualModelPart {
/**
* The virtual-id representation of this id mapping
*/

View File

@ -89,7 +89,7 @@ public class EmbeddedAttributeMapping
stateArrayPosition,
tableExpression,
attributeMetadataAccess,
getPropertyAccess(parentInjectionAttributeName, embeddableMappingType),
getPropertyAccess( parentInjectionAttributeName, embeddableMappingType ),
mappedFetchTiming,
mappedFetchStyle,
embeddableMappingType,
@ -132,7 +132,7 @@ public class EmbeddedAttributeMapping
}
// Constructor is only used for creating the inverse attribute mapping
private EmbeddedAttributeMapping(
EmbeddedAttributeMapping(
ManagedMappingType keyDeclaringType,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
@ -161,29 +161,6 @@ public class EmbeddedAttributeMapping
this.parentInjectionAttributePropertyAccess = null;
}
public static EmbeddableValuedModelPart createInverseModelPart(
EmbeddableValuedModelPart modelPart,
ManagedMappingType keyDeclaringType,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess) {
final EmbeddableMappingType embeddableTypeDescriptor;
if ( modelPart instanceof CompositeIdentifierMapping ) {
embeddableTypeDescriptor = ( (CompositeIdentifierMapping) modelPart ).getMappedIdEmbeddableTypeDescriptor();
}
else {
embeddableTypeDescriptor = modelPart.getEmbeddableTypeDescriptor();
}
return new EmbeddedAttributeMapping(
keyDeclaringType,
declaringTableGroupProducer,
selectableMappings,
modelPart,
embeddableTypeDescriptor,
creationProcess
);
}
@Override
public EmbeddableMappingType getMappedType() {
return getEmbeddableTypeDescriptor();

View File

@ -36,6 +36,7 @@ import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
@ -115,7 +116,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
this.targetSide = original.targetSide;
this.keySide = new EmbeddedForeignKeyDescriptorSide(
Nature.KEY,
EmbeddedAttributeMapping.createInverseModelPart(
MappingModelCreationHelper.createInverseModelPart(
original.targetSide.getModelPart(),
keyDeclaringType,
keyDeclaringTableGroupProducer,
@ -377,6 +378,84 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return getPredicate( targetSideReference, keySideReference, creationContext, targetSelectableMappings, keySelectableMappings );
}
@Override
public boolean isSimpleJoinPredicate(Predicate predicate) {
if ( !( predicate instanceof Junction ) ) {
return false;
}
final Junction junction = (Junction) predicate;
if ( junction.getNature() != Junction.Nature.CONJUNCTION ) {
return false;
}
final List<Predicate> predicates = junction.getPredicates();
if ( predicates.size() != keySelectableMappings.getJdbcTypeCount() ) {
return false;
}
Boolean lhsIsKey = null;
for ( int i = 0; i < predicates.size(); i++ ) {
final Predicate p = predicates.get( i );
if ( !( p instanceof ComparisonPredicate ) ) {
return false;
}
final ComparisonPredicate comparisonPredicate = (ComparisonPredicate) p;
if ( comparisonPredicate.getOperator() != ComparisonOperator.EQUAL ) {
return false;
}
final Expression lhsExpr = comparisonPredicate.getLeftHandExpression();
final Expression rhsExpr = comparisonPredicate.getRightHandExpression();
if ( !( lhsExpr instanceof ColumnReference ) || !( rhsExpr instanceof ColumnReference ) ) {
return false;
}
final ColumnReference lhs = (ColumnReference) lhsExpr;
final ColumnReference rhs = (ColumnReference) rhsExpr;
if ( lhsIsKey == null ) {
final String keyExpression = keySelectableMappings.getSelectable( i ).getSelectionExpression();
final String targetExpression = targetSelectableMappings.getSelectable( i ).getSelectionExpression();
if ( keyExpression.equals( targetExpression ) ) {
if ( !lhs.getColumnExpression().equals( keyExpression )
|| !rhs.getColumnExpression().equals( keyExpression ) ) {
return false;
}
}
else {
if ( keyExpression.equals( lhs.getColumnExpression() ) ) {
if ( !targetExpression.equals( rhs.getColumnExpression() ) ) {
return false;
}
lhsIsKey = true;
}
else if ( keyExpression.equals( rhs.getColumnExpression() ) ) {
if ( !targetExpression.equals( lhs.getColumnExpression() ) ) {
return false;
}
lhsIsKey = false;
}
else {
return false;
}
}
}
else {
final String lhsSelectionExpression;
final String rhsSelectionExpression;
if ( lhsIsKey ) {
lhsSelectionExpression = keySelectableMappings.getSelectable( i ).getSelectionExpression();
rhsSelectionExpression = targetSelectableMappings.getSelectable( i ).getSelectionExpression();
}
else {
lhsSelectionExpression = targetSelectableMappings.getSelectable( i ).getSelectionExpression();
rhsSelectionExpression = keySelectableMappings.getSelectable( i ).getSelectionExpression();
}
if ( !lhs.getColumnExpression().equals( lhsSelectionExpression )
|| !rhs.getColumnExpression().equals( rhsSelectionExpression ) ) {
return false;
}
}
}
return true;
}
private Predicate getPredicate(
TableReference lhs,
TableReference rhs,

View File

@ -37,6 +37,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
@ -168,7 +169,14 @@ public class EntityCollectionPart
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
this.targetKeyPropertyNames = Collections.singleton( compositeType.getPropertyNames()[0] );
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
ToOneAttributeMapping.addPrefixedPropertyNames(
targetKeyPropertyNames,
compositeType.getPropertyNames()[0],
compositeType.getSubtypes()[0],
creationProcess.getCreationContext().getSessionFactory()
);
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else {
final String mapsIdAttributeName;
@ -327,6 +335,11 @@ public class EntityCollectionPart
return SqlAstJoinType.INNER;
}
@Override
public boolean isSimpleJoinPredicate(Predicate predicate) {
return fkDescriptor.isSimpleJoinPredicate( predicate );
}
@Override
public Nature getNature() {
return nature;
@ -391,13 +404,14 @@ public class EntityCollectionPart
// This is not possible for one-to-many associations because we need to create the target table group eagerly,
// to preserve the cardinality. Also, the OneToManyTableGroup has no reference to the parent table group
if ( !collectionDescriptor.isOneToMany() && targetKeyPropertyNames.contains( name ) ) {
if ( fkDescriptor.getTargetPart() instanceof NonAggregatedIdentifierMappingImpl ) {
return ( (ModelPartContainer) fkDescriptor.getKeyPart() ).findSubPart( name, targetType );
}
if ( fkTargetModelPart instanceof ToOneAttributeMapping ) {
return fkTargetModelPart;
}
return fkDescriptor.getKeyPart();
final ModelPart keyPart = fkDescriptor.getKeyPart();
if ( keyPart instanceof EmbeddableValuedModelPart && keyPart instanceof VirtualModelPart ) {
return ( (ModelPartContainer) keyPart ).findSubPart( name, targetType );
}
return keyPart;
}
return EntityValuedFetchable.super.findSubPart( name, targetType );
}

View File

@ -61,7 +61,6 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.GeneratedValueResolver;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.NonTransientException;
@ -71,6 +70,7 @@ import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
@ -341,7 +341,9 @@ public class MappingModelCreationHelper {
attrType,
tableExpression,
rootTableKeyColumnNames,
attributeMappingType -> new EmbeddedAttributeMapping(
attributeMappingType -> {
if ( component.isEmbedded() ) {
return new VirtualEmbeddedAttributeMapping(
attrName,
declaringType.getNavigableRole().append( attrName ),
stateArrayPosition,
@ -354,7 +356,25 @@ public class MappingModelCreationHelper {
declaringType,
propertyAccess,
bootProperty.getValueGenerationStrategy()
),
);
}
else {
return new EmbeddedAttributeMapping(
attrName,
declaringType.getNavigableRole().append( attrName ),
stateArrayPosition,
tableExpression,
attributeMetadataAccess,
component.getParentProperty(),
FetchTiming.IMMEDIATE,
FetchStyle.JOIN,
attributeMappingType,
declaringType,
propertyAccess,
bootProperty.getValueGenerationStrategy()
);
}
},
creationProcess
);
@ -1172,7 +1192,7 @@ public class MappingModelCreationHelper {
if ( inverse ) {
return new EmbeddedForeignKeyDescriptor(
embeddableValuedModelPart,
EmbeddedAttributeMapping.createInverseModelPart(
createInverseModelPart(
embeddableValuedModelPart,
keyDeclaringType,
keyDeclaringTableGroupProducer,
@ -1189,7 +1209,7 @@ public class MappingModelCreationHelper {
}
else {
return new EmbeddedForeignKeyDescriptor(
EmbeddedAttributeMapping.createInverseModelPart(
createInverseModelPart(
embeddableValuedModelPart,
keyDeclaringType,
keyDeclaringTableGroupProducer,
@ -1494,6 +1514,41 @@ public class MappingModelCreationHelper {
);
}
public static EmbeddableValuedModelPart createInverseModelPart(
EmbeddableValuedModelPart modelPart,
ManagedMappingType keyDeclaringType,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
MappingModelCreationProcess creationProcess) {
final EmbeddableMappingType embeddableTypeDescriptor;
if ( modelPart instanceof CompositeIdentifierMapping ) {
embeddableTypeDescriptor = ( (CompositeIdentifierMapping) modelPart ).getMappedIdEmbeddableTypeDescriptor();
}
else {
embeddableTypeDescriptor = modelPart.getEmbeddableTypeDescriptor();
}
if ( modelPart instanceof VirtualModelPart ) {
return new VirtualEmbeddedAttributeMapping(
keyDeclaringType,
declaringTableGroupProducer,
selectableMappings,
modelPart,
embeddableTypeDescriptor,
creationProcess
);
}
else {
return new EmbeddedAttributeMapping(
keyDeclaringType,
declaringTableGroupProducer,
selectableMappings,
modelPart,
embeddableTypeDescriptor,
creationProcess
);
}
}
@SuppressWarnings("rawtypes")
private static class CollectionMappingTypeImpl implements CollectionMappingType {
private final JavaType collectionJtd;

View File

@ -517,6 +517,11 @@ public class PluralAttributeMappingImpl
return SqlAstJoinType.LEFT;
}
@Override
public boolean isSimpleJoinPredicate(Predicate predicate) {
return fkDescriptor.isSimpleJoinPredicate( predicate );
}
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,

View File

@ -37,6 +37,7 @@ import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
@ -289,6 +290,28 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
);
}
@Override
public boolean isSimpleJoinPredicate(Predicate predicate) {
if ( !( predicate instanceof ComparisonPredicate ) ) {
return false;
}
final ComparisonPredicate comparisonPredicate = (ComparisonPredicate) predicate;
if ( comparisonPredicate.getOperator() != ComparisonOperator.EQUAL ) {
return false;
}
final Expression lhsExpr = comparisonPredicate.getLeftHandExpression();
final Expression rhsExpr = comparisonPredicate.getRightHandExpression();
if ( !( lhsExpr instanceof ColumnReference ) || !( rhsExpr instanceof ColumnReference ) ) {
return false;
}
final String lhs = ( (ColumnReference) lhsExpr ).getColumnExpression();
final String rhs = ( (ColumnReference) rhsExpr ).getColumnExpression();
final String keyExpression = keySide.getModelPart().getSelectionExpression();
final String targetExpression = targetSide.getModelPart().getSelectionExpression();
return ( lhs.equals( keyExpression ) && rhs.equals( targetExpression ) )
|| ( lhs.equals( targetExpression ) && rhs.equals( keyExpression ) );
}
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
final NavigablePath navigablePath = lhs.getNavigablePath().append( getTargetPart().getFetchableName() );
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {

View File

@ -15,7 +15,6 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -30,7 +29,6 @@ import org.hibernate.mapping.OneToOne;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.AssociationKey;
@ -47,6 +45,7 @@ import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.AbstractEntityPersister;
@ -96,6 +95,7 @@ import org.hibernate.tuple.IdentifierProperty;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EmbeddedComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
@ -440,8 +440,15 @@ public class ToOneAttributeMapping
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
this.targetKeyPropertyName = compositeType.getPropertyNames()[0];
this.targetKeyPropertyNames = Collections.singleton( targetKeyPropertyName );
addPrefixedPropertyNames(
targetKeyPropertyNames,
targetKeyPropertyName,
compositeType.getSubtypes()[0],
declaringEntityPersister.getFactory()
);
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else {
this.targetKeyPropertyName = referencedPropertyName;
@ -551,6 +558,9 @@ public class ToOneAttributeMapping
if ( entityType.isReferenceToPrimaryKey() ) {
propertyName = entityType.getAssociatedEntityPersister( factory ).getIdentifierPropertyName();
}
else if ( identifierOrUniqueKeyType instanceof EmbeddedComponentType ) {
propertyName = null;
}
else {
propertyName = entityType.getRHSUniqueKeyPropertyName();
}
@ -651,20 +661,17 @@ public class ToOneAttributeMapping
// Prefer resolving the key part of the foreign key rather than the target part if possible
// This way, we don't have to register table groups the target entity type
if ( canUseParentTableGroup && targetKeyPropertyNames.contains( name ) ) {
final ModelPart fkSideModelPart;
final ModelPart fkTargetModelPart;
final ModelPart fkPart;
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
fkTargetModelPart = foreignKeyDescriptor.getTargetPart();
fkSideModelPart = foreignKeyDescriptor.getKeyPart();
fkPart = foreignKeyDescriptor.getKeyPart();
}
else {
fkTargetModelPart = foreignKeyDescriptor.getKeyPart();
fkSideModelPart = foreignKeyDescriptor.getTargetPart();
fkPart = foreignKeyDescriptor.getTargetPart();
}
if ( fkTargetModelPart instanceof NonAggregatedIdentifierMappingImpl ) {
return ( (ModelPartContainer) fkSideModelPart ).findSubPart( name, targetType );
if ( fkPart instanceof EmbeddableValuedModelPart && fkPart instanceof VirtualModelPart ) {
return ( (ModelPartContainer) fkPart ).findSubPart( name, targetType );
}
return fkSideModelPart;
return fkPart;
}
return EntityValuedFetchable.super.findSubPart( name, targetType );
}
@ -1223,6 +1230,11 @@ public class ToOneAttributeMapping
}
}
@Override
public boolean isSimpleJoinPredicate(Predicate predicate) {
return foreignKeyDescriptor.isSimpleJoinPredicate( predicate );
}
@Override
public int getNumberOfFetchables() {
return getEntityMappingType().getNumberOfFetchables();

View File

@ -0,0 +1,119 @@
/*
* 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.metamodel.mapping.internal;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.tuple.ValueGeneration;
/**
* @author Christian Beikov
*/
public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping implements VirtualModelPart {
public VirtualEmbeddedAttributeMapping(
String name,
NavigableRole navigableRole,
int stateArrayPosition,
String tableExpression,
StateArrayContributorMetadataAccess attributeMetadataAccess,
String parentInjectionAttributeName,
FetchTiming mappedFetchTiming,
FetchStyle mappedFetchStyle,
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
PropertyAccess propertyAccess, ValueGeneration valueGeneration) {
super(
name,
navigableRole,
stateArrayPosition,
tableExpression,
attributeMetadataAccess,
parentInjectionAttributeName,
mappedFetchTiming,
mappedFetchStyle,
embeddableMappingType,
declaringType,
propertyAccess,
valueGeneration
);
}
public VirtualEmbeddedAttributeMapping(
String name,
NavigableRole navigableRole,
int stateArrayPosition,
String tableExpression,
StateArrayContributorMetadataAccess attributeMetadataAccess,
PropertyAccess parentInjectionAttributePropertyAccess,
FetchTiming mappedFetchTiming,
FetchStyle mappedFetchStyle,
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
PropertyAccess propertyAccess, ValueGeneration valueGeneration) {
super(
name,
navigableRole,
stateArrayPosition,
tableExpression,
attributeMetadataAccess,
parentInjectionAttributePropertyAccess,
mappedFetchTiming,
mappedFetchStyle,
embeddableMappingType,
declaringType,
propertyAccess,
valueGeneration
);
}
// Constructor is only used for creating the inverse attribute mapping
VirtualEmbeddedAttributeMapping(
ManagedMappingType keyDeclaringType,
TableGroupProducer declaringTableGroupProducer,
SelectableMappings selectableMappings,
EmbeddableValuedModelPart inverseModelPart,
EmbeddableMappingType embeddableTypeDescriptor,
MappingModelCreationProcess creationProcess) {
super(
keyDeclaringType,
declaringTableGroupProducer,
selectableMappings,
inverseModelPart,
embeddableTypeDescriptor,
creationProcess
);
}
@Override
public AttributeMapping copy(ManagedMappingType declaringType) {
return new VirtualEmbeddedAttributeMapping(
getAttributeName(),
getNavigableRole(),
getStateArrayPosition(),
getContainingTableExpression(),
getAttributeMetadataAccess(),
getParentInjectionAttributePropertyAccess(),
getTiming(),
getStyle(),
getEmbeddableTypeDescriptor(),
declaringType,
getPropertyAccess(),
getValueGeneration()
);
}
}

View File

@ -167,6 +167,7 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.Queryable;
import org.hibernate.metamodel.mapping.SelectableConsumer;
@ -184,7 +185,6 @@ import org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor;
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
import org.hibernate.metamodel.mapping.internal.SimpleNaturalIdMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.EntityInstantiator;
@ -5023,7 +5023,7 @@ public abstract class AbstractEntityPersister
baseValueType = (ManagedMappingType) attributeMapping.getMappedType();
}
}
else if ( identifierMapping instanceof NonAggregatedIdentifierMappingImpl ) {
else if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) {
final EmbeddedAttributeMapping embeddedAttributeMapping = (EmbeddedAttributeMapping) findAttributeMapping( NavigableRole.IDENTIFIER_MAPPER_PROPERTY );
final AttributeMapping mapping = embeddedAttributeMapping.getMappedType()
.findAttributeMapping( basePropertyName );
@ -6386,8 +6386,8 @@ public abstract class AbstractEntityPersister
}
private ModelPart getIdentifierModelPart(String name, EntityMappingType treatTargetType) {
if ( identifierMapping instanceof NonAggregatedIdentifierMappingImpl ) {
final ModelPart subPart = ( (NonAggregatedIdentifierMappingImpl) identifierMapping ).findSubPart(
if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) {
final ModelPart subPart = ( (NonAggregatedIdentifierMapping) identifierMapping ).findSubPart(
name,
treatTargetType
);

View File

@ -28,8 +28,8 @@ import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
import org.hibernate.query.EntityIdentifierNavigablePath;
import org.hibernate.query.NavigablePath;
@ -428,7 +428,7 @@ public class DomainResultCreationStateImpl
if ( fetchableContainer instanceof EntityValuedModelPart ) {
final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer;
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMappingImpl;
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMapping;
final String identifierAttributeName = attributeName( identifierMapping );
if ( idClass ) {
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();

View File

@ -2842,6 +2842,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
querySpec.getFromClause().addRoot( tableGroup );
}
else {
// Check if we can reuse a table group join of the parent
final TableGroup compatibleTableGroup = findCompatibleJoinedGroup(
actualParentTableGroup,
joinProducer,
defaultSqlAstJoinType
);
if ( compatibleTableGroup == null ) {
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
joinedPath.getNavigablePath(),
actualParentTableGroup,
@ -2865,6 +2872,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
tableGroup = tableGroupJoin.getJoinedGroup();
}
else {
tableGroup = compatibleTableGroup;
}
}
fromClauseIndex.register( joinedPath, tableGroup );
registerPluralTableGroupParts( tableGroup );
@ -2875,6 +2886,31 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return tableGroup;
}
private TableGroup findCompatibleJoinedGroup(
TableGroup parentTableGroup,
TableGroupJoinProducer joinProducer,
SqlAstJoinType requestedJoinType) {
// We don't look into nested table group joins as that wouldn't be "compatible"
for ( TableGroupJoin join : parentTableGroup.getTableGroupJoins() ) {
// Compatibility obviously requires the same model part but also join type compatibility
// Note that if the requested join type is left, we can also use an existing inner join
// The other case, when the requested join type is inner and there is an existing left join,
// is not compatible though because the cardinality is different.
// We could reuse the join though if we alter the join type to INNER, but that's an optimization for later
final SqlAstJoinType joinType = join.getJoinType();
if ( join.getJoinedGroup().getModelPart() == joinProducer
&& ( requestedJoinType == joinType || requestedJoinType == SqlAstJoinType.LEFT && joinType == SqlAstJoinType.INNER ) ) {
// If there is an existing inner join, we can always use that as a new join can never produce results
// regardless of the join type or predicate since the LHS is the same table group
// If this is a left join though, we have to check if the predicate is simply the association predicate
if ( joinType == SqlAstJoinType.INNER || joinProducer.isSimpleJoinPredicate( join.getPredicate() ) ) {
return join.getJoinedGroup();
}
}
}
return null;
}
private void registerPluralTableGroupParts(TableGroup tableGroup) {
if ( tableGroup instanceof PluralTableGroup ) {
final PluralTableGroup pluralTableGroup = (PluralTableGroup) tableGroup;

View File

@ -7,11 +7,10 @@
package org.hibernate.query.sqm.sql.internal;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
@ -31,7 +30,7 @@ public class NonAggregatedCompositeValuedPathInterpretation<T>
final TableGroup tableGroup = sqlAstCreationState
.getFromClauseAccess()
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
final NonAggregatedIdentifierMappingImpl mapping = (NonAggregatedIdentifierMappingImpl) tableGroup.getModelPart()
final NonAggregatedIdentifierMapping mapping = (NonAggregatedIdentifierMapping) tableGroup.getModelPart()
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
return new NonAggregatedCompositeValuedPathInterpretation<>(

View File

@ -3912,6 +3912,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
tableGroupJoinCollector
);
}
// A lazy table group, even if uninitialized, might contain table group joins
else if ( joinedGroup instanceof LazyTableGroup ) {
processNestedTableGroupJoins( joinedGroup, tableGroupJoinCollector );
if ( tableGroupJoinCollector != null ) {
tableGroupJoinCollector.addAll( joinedGroup.getTableGroupJoins() );
}
else {
processTableGroupJoins( joinedGroup );
}
}
}
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.sql.ast.tree.from;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiPredicate;
@ -36,6 +37,8 @@ public class LazyTableGroup extends DelegatingTableGroup {
private final Supplier<TableGroup> tableGroupSupplier;
private final TableGroup parentTableGroup;
private final BiPredicate<NavigablePath, String> navigablePathChecker;
private List<TableGroupJoin> tableGroupJoins;
private List<TableGroupJoin> nestedTableGroupJoins;
private Consumer<TableGroup> tableGroupConsumer;
private TableGroup tableGroup;
@ -72,6 +75,18 @@ public class LazyTableGroup extends DelegatingTableGroup {
}
tableGroup = tableGroupSupplier.get();
if ( tableGroupJoins != null ) {
for ( TableGroupJoin tableGroupJoin : tableGroupJoins ) {
tableGroup.addTableGroupJoin( tableGroupJoin );
}
tableGroupJoins = null;
}
if ( nestedTableGroupJoins != null ) {
for ( TableGroupJoin tableGroupJoin : nestedTableGroupJoins ) {
tableGroup.addNestedTableGroupJoin( tableGroupJoin );
}
nestedTableGroupJoins = null;
}
if ( tableGroupConsumer != null ) {
tableGroupConsumer.accept( tableGroup );
tableGroupConsumer = null;
@ -102,24 +117,70 @@ public class LazyTableGroup extends DelegatingTableGroup {
@Override
public List<TableGroupJoin> getTableGroupJoins() {
return tableGroup == null ? Collections.emptyList() : tableGroup.getTableGroupJoins();
if ( tableGroup == null ) {
return nestedTableGroupJoins == null ? Collections.emptyList() : nestedTableGroupJoins;
}
else {
return tableGroup.getTableGroupJoins();
}
}
@Override
public List<TableGroupJoin> getNestedTableGroupJoins() {
return tableGroup == null ? Collections.emptyList() : tableGroup.getNestedTableGroupJoins();
if ( tableGroup == null ) {
return tableGroupJoins == null ? Collections.emptyList() : tableGroupJoins;
}
else {
return tableGroup.getNestedTableGroupJoins();
}
}
@Override
public void addTableGroupJoin(TableGroupJoin join) {
if ( tableGroup == null ) {
if ( tableGroupJoins == null ) {
tableGroupJoins = new ArrayList<>();
}
tableGroupJoins.add( join );
}
else {
getTableGroup().addTableGroupJoin( join );
}
}
@Override
public void addNestedTableGroupJoin(TableGroupJoin join) {
if ( tableGroup == null ) {
if ( nestedTableGroupJoins == null ) {
nestedTableGroupJoins = new ArrayList<>();
}
nestedTableGroupJoins.add( join );
}
else {
getTableGroup().addNestedTableGroupJoin( join );
}
}
@Override
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
if ( tableGroup != null ) {
if ( tableGroup == null ) {
if ( tableGroupJoins != null ) {
tableGroupJoins.forEach( consumer );
}
}
else {
tableGroup.visitTableGroupJoins( consumer );
}
}
@Override
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
if ( tableGroup != null ) {
if ( tableGroup == null ) {
if ( nestedTableGroupJoins != null ) {
nestedTableGroupJoins.forEach( consumer );
}
}
else {
tableGroup.visitNestedTableGroupJoins( consumer );
}
}

View File

@ -24,6 +24,8 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup);
boolean isSimpleJoinPredicate(Predicate predicate);
/**
* Create a TableGroupJoin as defined for this producer
*/

View File

@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.metamodel.EmbeddableRepresentationStrategy;
import org.hibernate.property.access.spi.PropertyAccess;
@ -34,8 +35,6 @@ import org.hibernate.sql.results.graph.collection.CollectionInitializer;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.internal.NullValueAssembler;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.EntityJavaTypeDescriptor;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
@ -231,17 +230,12 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
return;
}
// Special handling for non-aggregated attributes which use the actual entity instance as container,
// which we access through the fetch parent access.
// If this model part is an identifier, we must construct the instance as this is called during resolveKey
final EmbeddableMappingType embeddableTypeDescriptor = embedded.getEmbeddableTypeDescriptor();
final JavaType<?> embeddableJtd = embeddableTypeDescriptor.getMappedJavaTypeDescriptor();
if ( fetchParentAccess != null &&
embeddableJtd.getJavaTypeClass().isAssignableFrom( fetchParentAccess.getInitializedPart().getJavaTypeDescriptor().getJavaTypeClass() )
&& embeddableJtd instanceof EntityJavaTypeDescriptor<?>
&& !( embedded instanceof CompositeIdentifierMapping )
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() ) ) {
// Virtual model parts use the owning entity as container which the fetch parent access provides.
// For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
// so we can't use the fetch parent access in that case.
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() )
&& !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) ) {
fetchParentAccess.resolveInstance( processingState );
compositeInstance = fetchParentAccess.getInitializedInstance();
}

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph.embeddable;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
@ -19,4 +20,9 @@ public interface EmbeddableValuedFetchable extends EmbeddableValuedModelPart, Fe
default SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
return SqlAstJoinType.LEFT;
}
@Override
default boolean isSimpleJoinPredicate(Predicate predicate) {
return predicate == null;
}
}

View File

@ -112,8 +112,11 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
public NavigablePath resolveNavigablePath(Fetchable fetchable) {
if ( fetchable instanceof TableGroupProducer ) {
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
if ( tableGroupJoin.getJoinedGroup().isFetched() && tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return tableGroupJoin.getNavigablePath();
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
if ( tableGroupJoin.getJoinedGroup().isFetched()
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() )
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return navigablePath;
}
}
}

View File

@ -59,8 +59,11 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E
if ( fetchable instanceof TableGroupProducer &&
!getNavigablePath().getUnaliasedLocalName().equals( getNavigablePath().getLocalName() ) ) {
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
if ( tableGroupJoin.getJoinedGroup().isFetched() && tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return tableGroupJoin.getNavigablePath();
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
if ( tableGroupJoin.getJoinedGroup().isFetched()
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() )
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return navigablePath;
}
}
}

View File

@ -5,7 +5,7 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.hql;
package org.hibernate.orm.test.hql;
import org.hibernate.annotations.NaturalId;
import org.hibernate.query.Query;
@ -15,6 +15,7 @@ import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -66,9 +67,21 @@ public class NaturalIdDereferenceTest {
);
}
@AfterEach
public void deleteData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery( "delete from BookRefRef" ).executeUpdate();
session.createQuery( "delete from BookRef" ).executeUpdate();
session.createQuery( "delete from Book" ).executeUpdate();
}
);
}
@Test
public void naturalIdDereferenceTest(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r.normalBook.isbn FROM BookRef r" );
@ -83,6 +96,7 @@ public class NaturalIdDereferenceTest {
@Test
public void normalIdDereferenceFromAlias(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r.normalBook.id FROM BookRef r" );
@ -97,6 +111,7 @@ public class NaturalIdDereferenceTest {
@Test
public void naturalIdDereferenceFromAlias(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r.naturalBook.isbn FROM BookRef r" );
@ -111,6 +126,7 @@ public class NaturalIdDereferenceTest {
@Test
public void normalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook.id FROM BookRefRef r2" );
@ -124,6 +140,7 @@ public class NaturalIdDereferenceTest {
@Test
public void naturalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.normalBookRef.naturalBook.isbn FROM BookRefRef r2" );
@ -142,6 +159,7 @@ public class NaturalIdDereferenceTest {
@Test
public void nestedNaturalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook.isbn FROM BookRefRef r2" );
@ -159,6 +177,7 @@ public class NaturalIdDereferenceTest {
@Test
public void nestedNaturalIdDereferenceFromImplicitJoin2(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook.id FROM BookRefRef r2" );
@ -172,6 +191,7 @@ public class NaturalIdDereferenceTest {
@Test
public void doNotDereferenceNaturalIdIfIsReferenceToPrimaryKey(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook.isbn FROM BookRefRef r2" );
@ -185,6 +205,7 @@ public class NaturalIdDereferenceTest {
@Test
public void selectedEntityIsNotDereferencedForPrimaryKey(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook FROM BookRefRef r2" );
@ -209,6 +230,7 @@ public class NaturalIdDereferenceTest {
@Test
public void selectedEntityIsNotDereferencedForNaturalId(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook FROM BookRefRef r2" );
@ -228,6 +250,7 @@ public class NaturalIdDereferenceTest {
@Test
public void dereferenceNaturalIdInJoin(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery(
@ -251,6 +274,7 @@ public class NaturalIdDereferenceTest {
@Test
public void dereferenceNaturalIdInJoin2(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery( "SELECT b.normalBook FROM BookRefRef a " +
@ -271,6 +295,7 @@ public class NaturalIdDereferenceTest {
@Test
public void dereferenceNaturalIdInJoin3(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery(
@ -292,6 +317,7 @@ public class NaturalIdDereferenceTest {
@Test
public void dereferenceNaturalIdInJoin4(SessionFactoryScope scope) {
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query query = session.createQuery(