HHH-16382 Fix resolving table references especially for self-referential associations
This commit is contained in:
parent
b754325cab
commit
e96402a005
|
@ -26,7 +26,7 @@ public class TableGroupFilterAliasGenerator implements FilterAliasGenerator {
|
|||
if ( table == null ) {
|
||||
table = defaultTable;
|
||||
}
|
||||
final TableReference tableReference = tableGroup.getTableReference( null, table, true, true );
|
||||
final TableReference tableReference = tableGroup.getTableReference( null, table, true );
|
||||
return tableReference == null ? null : tableReference.getIdentificationVariable();
|
||||
}
|
||||
|
||||
|
|
|
@ -291,4 +291,8 @@ public abstract class AbstractCompositeIdentifierMapping
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
return entityMapping.containsTableReference( tableExpression );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.hibernate.type.descriptor.java.MutabilityPlanExposer;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface AttributeMapping
|
||||
extends ValuedModelPart, Fetchable, DatabaseSnapshotContributor, PropertyBasedMapping, MutabilityPlanExposer {
|
||||
extends OwnedValuedModelPart, Fetchable, DatabaseSnapshotContributor, PropertyBasedMapping, MutabilityPlanExposer {
|
||||
/**
|
||||
* The name of the mapped attribute
|
||||
*/
|
||||
|
|
|
@ -18,4 +18,11 @@ public interface BasicEntityIdentifierMapping extends SingleAttributeIdentifierM
|
|||
default int getFetchableKey() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isNullable();
|
||||
|
||||
@Override
|
||||
boolean isInsertable();
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.function.IntFunction;
|
|||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.mapping.internal.VirtualIdEmbeddable;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
|
@ -42,7 +43,9 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValuedModelPart
|
|||
|
||||
ValuedModelPart getTargetPart();
|
||||
|
||||
default ModelPart getPart(Nature nature) {
|
||||
boolean isKeyPart(ValuedModelPart modelPart);
|
||||
|
||||
default ValuedModelPart getPart(Nature nature) {
|
||||
if ( nature == Nature.KEY ) {
|
||||
return getKeyPart();
|
||||
}
|
||||
|
@ -76,27 +79,45 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValuedModelPart
|
|||
|
||||
/**
|
||||
* Create a DomainResult for the referring-side of the fk
|
||||
* The table group must be the one containing the target.
|
||||
*/
|
||||
DomainResult<?> createKeyDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState);
|
||||
|
||||
/**
|
||||
* Create a DomainResult for the referring-side of the fk
|
||||
* The table group must be the one containing the target.
|
||||
* The {@link Nature} is the association side of the foreign key i.e. {@link Association#getSideNature()}.
|
||||
*/
|
||||
DomainResult<?> createKeyDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup targetTableGroup,
|
||||
Nature fromSide,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState);
|
||||
|
||||
/**
|
||||
* Create a DomainResult for the target-side of the fk
|
||||
* The table group must be the one containing the target
|
||||
*/
|
||||
DomainResult<?> createTargetDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState);
|
||||
|
||||
DomainResult<?> createDomainResult(
|
||||
/**
|
||||
* Create a DomainResult for the referring-side of the fk
|
||||
* The table group must be the one containing the target.
|
||||
*/
|
||||
@Override
|
||||
<T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
Nature side,
|
||||
FetchParent fetchParent,
|
||||
TableGroup targetTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState);
|
||||
|
||||
Predicate generateJoinPredicate(
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Marker interface for valued model parts that have a declaring/owner type.
|
||||
*/
|
||||
public interface OwnedValuedModelPart extends ValuedModelPart {
|
||||
MappingType getDeclaringType();
|
||||
}
|
|
@ -121,7 +121,7 @@ public interface PluralAttributeMapping
|
|||
@Override
|
||||
default <T> DomainResult<T> createSnapshotDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup parentTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new BasicResult( 0, null, getJavaType() );
|
||||
|
|
|
@ -63,7 +63,11 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
SqlAstCreationState creationState) {
|
||||
if ( referenceModelPart instanceof BasicValuedModelPart ) {
|
||||
final BasicValuedModelPart selection = (BasicValuedModelPart) referenceModelPart;
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( getNavigablePath(), selection.getContainingTableExpression() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
getNavigablePath(),
|
||||
selection,
|
||||
selection.getContainingTableExpression()
|
||||
);
|
||||
return creationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
createColumnReferenceKey( tableReference, selection.getSelectionExpression() ),
|
||||
processingState -> new ColumnReference(
|
||||
|
|
|
@ -308,7 +308,7 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
return getCollectionDescriptor().getAttributeMapping().containsTableReference( tableExpression );
|
||||
return getAssociatedEntityMappingType().containsTableReference( tableExpression );
|
||||
}
|
||||
|
||||
public TableGroup createTableGroupInternal(
|
||||
|
@ -319,7 +319,6 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
final SqlAliasBase sqlAliasBase,
|
||||
SqlAstCreationState creationState) {
|
||||
final SqlAstCreationContext creationContext = creationState.getCreationContext();
|
||||
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
|
||||
final TableReference primaryTableReference = getEntityMappingType().createPrimaryTableReference(
|
||||
sqlAliasBase,
|
||||
creationState
|
||||
|
@ -389,7 +388,7 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
final CompositeType compositeType;
|
||||
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
|
||||
&& compositeType.getPropertyNames().length == 1 ) {
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
compositeType.getPropertyNames()[0],
|
||||
compositeType.getSubtypes()[0],
|
||||
|
@ -397,39 +396,27 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
compositeType.getSubtypes()[0],
|
||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
null,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
entityBinding.getIdentifierProperty().getName(),
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
return targetKeyPropertyNames;
|
||||
}
|
||||
|
@ -442,18 +429,12 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
// todo (PropertyMapping) : the problem here is timing. this needs to be delayed.
|
||||
final Type propertyType = ( (PropertyMapping) elementTypeDescriptor.getEntityPersister() )
|
||||
.toType( referencedPropertyName );
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
referencedPropertyName,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
return targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
|
@ -462,7 +443,7 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
|
||||
&& compositeType.getPropertyNames().length == 1 ) {
|
||||
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
compositeType.getPropertyNames()[0],
|
||||
compositeType.getSubtypes()[0],
|
||||
|
@ -470,34 +451,34 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa
|
|||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
compositeType.getSubtypes()[0],
|
||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
return targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||
targetKeyPropertyNames.add( EntityIdentifierMapping.ROLE_LOCAL_NAME );
|
||||
targetKeyPropertyNames.add( referencedPropertyName );
|
||||
final String mapsIdAttributeName;
|
||||
if ( ( mapsIdAttributeName = ToOneAttributeMapping.findMapsIdPropertyName( elementTypeDescriptor, referencedPropertyName ) ) != null ) {
|
||||
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||
targetKeyPropertyNames.add( referencedPropertyName );
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
mapsIdAttributeName,
|
||||
elementTypeDescriptor.getEntityPersister().getIdentifierType(),
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
elementTypeDescriptor.getEntityPersister().getIdentifierType(),
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
return targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
return Set.of( referencedPropertyName, ForeignKeyDescriptor.PART_NAME );
|
||||
ToOneAttributeMapping.addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
null,
|
||||
propertyType,
|
||||
creationProcess.getCreationContext().getSessionFactory()
|
||||
);
|
||||
}
|
||||
return targetKeyPropertyNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
|
@ -147,7 +146,15 @@ public class BasicAttributeMapping
|
|||
if ( original instanceof SingleAttributeIdentifierMapping ) {
|
||||
final SingleAttributeIdentifierMapping mapping = (SingleAttributeIdentifierMapping) original;
|
||||
attributeName = mapping.getAttributeName();
|
||||
attributeMetadata = null;
|
||||
attributeMetadata = new SimpleAttributeMetadata(
|
||||
propertyAccess,
|
||||
mapping.getExpressibleJavaType().getMutabilityPlan(),
|
||||
selectableMapping.isNullable(),
|
||||
insertable,
|
||||
updateable,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
else if ( original instanceof SingularAttributeMapping ) {
|
||||
final SingularAttributeMapping mapping = (SingularAttributeMapping) original;
|
||||
|
@ -297,7 +304,7 @@ public class BasicAttributeMapping
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, null, creationState );
|
||||
|
||||
//noinspection unchecked
|
||||
return new BasicResult(
|
||||
|
@ -311,14 +318,13 @@ public class BasicAttributeMapping
|
|||
private SqlSelection resolveSqlSelection(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
@SuppressWarnings("SameParameterValue") boolean allowFkOptimization,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
getContainingTableExpression(),
|
||||
allowFkOptimization
|
||||
this,
|
||||
getContainingTableExpression()
|
||||
);
|
||||
|
||||
return expressionResolver.resolveSqlSelection(
|
||||
|
@ -337,7 +343,7 @@ public class BasicAttributeMapping
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
|
||||
resolveSqlSelection( navigablePath, tableGroup, null, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -346,7 +352,7 @@ public class BasicAttributeMapping
|
|||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState,
|
||||
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
|
||||
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, true, null, creationState ), getJdbcMapping() );
|
||||
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, null, creationState ), getJdbcMapping() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -375,7 +381,12 @@ public class BasicAttributeMapping
|
|||
|
||||
assert tableGroup != null;
|
||||
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, fetchParent, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection(
|
||||
fetchablePath,
|
||||
tableGroup,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
valuesArrayPosition = sqlSelection.getValuesArrayPosition();
|
||||
if ( sqlSelection.getExpressionType() != null) {
|
||||
// if the expression type is different that the expected type coerce the value
|
||||
|
|
|
@ -225,7 +225,7 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, null, creationState );
|
||||
|
||||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
|
@ -240,7 +240,7 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
|
||||
resolveSqlSelection( navigablePath, tableGroup, null, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -250,7 +250,7 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
DomainResultCreationState creationState,
|
||||
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
|
||||
selectionConsumer.accept(
|
||||
resolveSqlSelection( navigablePath, tableGroup, true, null, creationState ),
|
||||
resolveSqlSelection( navigablePath, tableGroup, null, creationState ),
|
||||
getJdbcMapping()
|
||||
);
|
||||
}
|
||||
|
@ -258,14 +258,13 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
private SqlSelection resolveSqlSelection(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
boolean allowFkOptimization,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState()
|
||||
.getSqlExpressionResolver();
|
||||
final TableReference rootTableReference;
|
||||
try {
|
||||
rootTableReference = tableGroup.resolveTableReference( navigablePath, rootTable, allowFkOptimization );
|
||||
rootTableReference = tableGroup.resolveTableReference( navigablePath, rootTable );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
|
@ -315,12 +314,12 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return updateable;
|
||||
return insertable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdateable() {
|
||||
return insertable;
|
||||
return updateable;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -414,7 +413,7 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
|
||||
assert tableGroup != null;
|
||||
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, false, fetchParent, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, fetchParent, creationState );
|
||||
final JdbcMappingContainer selectionType = sqlSelection.getExpressionType();
|
||||
return new BasicFetch<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -160,7 +159,7 @@ public class BasicValuedCollectionPart
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, null, creationState );
|
||||
|
||||
return new BasicResult<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
|
@ -173,7 +172,6 @@ public class BasicValuedCollectionPart
|
|||
private SqlSelection resolveSqlSelection(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
boolean allowFkOptimization,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver exprResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
|
@ -189,8 +187,7 @@ public class BasicValuedCollectionPart
|
|||
}
|
||||
final TableReference tableReference = targetTableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
getContainingTableExpression(),
|
||||
allowFkOptimization
|
||||
getContainingTableExpression()
|
||||
);
|
||||
return exprResolver.resolveSqlSelection(
|
||||
exprResolver.resolveSqlExpression(
|
||||
|
@ -206,7 +203,7 @@ public class BasicValuedCollectionPart
|
|||
@Override
|
||||
public void applySqlSelections(
|
||||
NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||
resolveSqlSelection( navigablePath, tableGroup, true, null, creationState );
|
||||
resolveSqlSelection( navigablePath, tableGroup, null, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -215,7 +212,7 @@ public class BasicValuedCollectionPart
|
|||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState,
|
||||
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
|
||||
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, true, null, creationState ), getJdbcMapping() );
|
||||
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, null, creationState ), getJdbcMapping() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -272,7 +269,7 @@ public class BasicValuedCollectionPart
|
|||
final TableGroup tableGroup = creationState.getSqlAstCreationState()
|
||||
.getFromClauseAccess()
|
||||
.findTableGroup( parentNavigablePath );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, true, fetchParent, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( fetchablePath, tableGroup, fetchParent, creationState );
|
||||
|
||||
return new BasicFetch<>(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -95,7 +94,6 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
|||
(tableName, tableDiscriminatorDetails) -> tableGroup.getTableReference(
|
||||
fetchablePath,
|
||||
tableName,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
@ -244,7 +242,6 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
|||
final TableReference tableReference = entityTableGroup.getTableReference(
|
||||
entityTableGroup.getNavigablePath(),
|
||||
tableName,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
|
|
|
@ -266,7 +266,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
selectableMappings,
|
||||
inverseMappingType,
|
||||
creationProcess,
|
||||
valueMapping.getDeclaringType(),
|
||||
this,
|
||||
attributeMappings
|
||||
)
|
||||
);
|
||||
|
|
|
@ -298,12 +298,12 @@ public class EmbeddedAttributeMapping
|
|||
}
|
||||
final List<ColumnReference> columnReferences = CollectionHelper.arrayList( embeddableMappingType.getJdbcTypeCount() );
|
||||
final NavigablePath navigablePath = tableGroup.getNavigablePath().append( getNavigableRole().getNavigableName() );
|
||||
final TableReference defaultTableReference = tableGroup.resolveTableReference( navigablePath, getContainingTableExpression() );
|
||||
final TableReference defaultTableReference = tableGroup.resolveTableReference( navigablePath, this, getContainingTableExpression() );
|
||||
getEmbeddableTypeDescriptor().forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
final TableReference tableReference = getContainingTableExpression().equals( selection.getContainingTableExpression() )
|
||||
? defaultTableReference
|
||||
: tableGroup.resolveTableReference( navigablePath, selection.getContainingTableExpression() );
|
||||
: tableGroup.resolveTableReference( navigablePath, this, selection.getContainingTableExpression() );
|
||||
final Expression columnReference = sqlAstCreationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
tableReference,
|
||||
selection
|
||||
|
@ -394,4 +394,17 @@ public class EmbeddedAttributeMapping
|
|||
public boolean isSelectable() {
|
||||
return selectable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
final ManagedMappingType declaringType = getDeclaringType();
|
||||
final TableGroupProducer producer;
|
||||
if ( declaringType instanceof TableGroupProducer ) {
|
||||
producer = (TableGroupProducer) declaringType;
|
||||
}
|
||||
else {
|
||||
producer = ( (EmbeddableMappingType) declaringType ).getEmbeddedValueMapping();
|
||||
}
|
||||
return producer.containsTableReference( tableExpression );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.hibernate.sql.ast.tree.from.PluralTableGroup;
|
|||
import org.hibernate.sql.ast.tree.from.StandardVirtualTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -207,6 +208,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
tableGroup.getNavigablePath()
|
||||
.append( getNavigableRole().getNavigableName() ),
|
||||
this,
|
||||
selection.getContainingTableExpression()
|
||||
);
|
||||
expressions.add(
|
||||
|
@ -322,4 +324,13 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
return FetchTiming.IMMEDIATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
if ( collectionDescriptor.isOneToMany() ) {
|
||||
return ( (EntityCollectionPart) collectionDescriptor.getAttributeMapping().getElementDescriptor() )
|
||||
.getPartMappingType().containsTableReference( tableExpression );
|
||||
}
|
||||
return collectionDescriptor.getAttributeMapping().containsTableReference( tableExpression );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.internal.util.IndexedConsumer;
|
||||
import org.hibernate.internal.util.MutableInteger;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.AttributeMappingsList;
|
||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -24,9 +25,11 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
|
|||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -35,10 +38,12 @@ import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
|||
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.OneToManyTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.VirtualTableGroup;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
@ -171,6 +176,27 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
return targetSide.getModelPart().getEmbeddableTypeDescriptor().getEmbeddedValueMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeyPart(ValuedModelPart modelPart) {
|
||||
final EmbeddableValuedModelPart keyPart = getKeyPart();
|
||||
if ( this == modelPart || keyPart == modelPart ) {
|
||||
return true;
|
||||
}
|
||||
else if ( keyPart instanceof NonAggregatedIdentifierMapping ) {
|
||||
final AttributeMappingsList attributeMappings = ( (NonAggregatedIdentifierMapping) keyPart ).getVirtualIdEmbeddable()
|
||||
.getAttributeMappings();
|
||||
for ( int i = 0; i < attributeMappings.size(); i++ ) {
|
||||
if ( modelPart == attributeMappings.get( i ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( keyPart.isVirtual() && keyPart.getNumberOfFetchables() == 1 ) {
|
||||
return keyPart.getFetchable( 0 ) == modelPart;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side getKeySide() {
|
||||
return keySide;
|
||||
|
@ -209,15 +235,35 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
@Override
|
||||
public DomainResult<?> createKeyDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
assert isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
targetTableGroup,
|
||||
null,
|
||||
keyTable,
|
||||
keySide.getModelPart(),
|
||||
Nature.KEY,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> createKeyDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup targetTableGroup,
|
||||
Nature fromSide,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
assert fromSide == Nature.TARGET
|
||||
? targetTableGroup.getTableReference( navigablePath, associationKey.getTable(), false ) != null
|
||||
: isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath.append( ForeignKeyDescriptor.PART_NAME ),
|
||||
targetTableGroup,
|
||||
null,
|
||||
Nature.KEY,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
|
@ -226,70 +272,57 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
@Override
|
||||
public DomainResult<?> createTargetDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
assert tableGroup.getTableReference( navigablePath, targetTable ) != null;
|
||||
|
||||
assert isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
targetTableGroup,
|
||||
null,
|
||||
targetTable,
|
||||
targetSide.getModelPart(),
|
||||
Nature.TARGET,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
Nature side,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( side == Nature.KEY ) {
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
null,
|
||||
keyTable,
|
||||
keySide.getModelPart(),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
null,
|
||||
targetTable,
|
||||
targetSide.getModelPart(),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
assert isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
targetTableGroup,
|
||||
resultVariable,
|
||||
keyTable,
|
||||
keySide.getModelPart(),
|
||||
Nature.KEY,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isTargetTableGroup(TableGroup tableGroup) {
|
||||
tableGroup = getUnderlyingTableGroup( tableGroup );
|
||||
final TableGroupProducer tableGroupProducer;
|
||||
if ( tableGroup instanceof OneToManyTableGroup ) {
|
||||
tableGroupProducer = (TableGroupProducer) ( (OneToManyTableGroup) tableGroup ).getElementTableGroup()
|
||||
.getModelPart();
|
||||
}
|
||||
else {
|
||||
tableGroupProducer = (TableGroupProducer) tableGroup.getModelPart();
|
||||
}
|
||||
return tableGroupProducer.containsTableReference( targetSide.getModelPart().getContainingTableExpression() );
|
||||
}
|
||||
|
||||
private static TableGroup getUnderlyingTableGroup(TableGroup tableGroup) {
|
||||
if ( tableGroup instanceof VirtualTableGroup ) {
|
||||
tableGroup = getUnderlyingTableGroup( ( (VirtualTableGroup) tableGroup ).getUnderlyingTableGroup() );
|
||||
}
|
||||
return tableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySqlSelections(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -311,15 +344,17 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
String columnContainingTable,
|
||||
EmbeddableValuedModelPart modelPart,
|
||||
Nature nature,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
final EmbeddableValuedModelPart modelPart;
|
||||
final NavigablePath resultNavigablePath;
|
||||
if ( modelPart == keySide.getModelPart() ) {
|
||||
if ( nature == Nature.KEY ) {
|
||||
modelPart = keySide.getModelPart();
|
||||
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.PART_NAME );
|
||||
}
|
||||
else {
|
||||
modelPart = targetSide.getModelPart();
|
||||
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME );
|
||||
}
|
||||
|
||||
|
@ -343,7 +378,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
|
||||
final Nature currentForeignKeyResolvingKey = creationState.getCurrentlyResolvingForeignKeyPart();
|
||||
try {
|
||||
creationState.setCurrentlyResolvingForeignKeyPart( keySide.getModelPart() == modelPart ? Nature.KEY : Nature.TARGET );
|
||||
creationState.setCurrentlyResolvingForeignKeyPart( nature );
|
||||
return new EmbeddableForeignKeyResultImpl<>(
|
||||
resultNavigablePath,
|
||||
modelPart,
|
||||
|
@ -364,13 +399,11 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
SqlAstCreationState creationState) {
|
||||
final TableReference lhsTableReference = targetSideTableGroup.resolveTableReference(
|
||||
targetSideTableGroup.getNavigablePath(),
|
||||
targetTable,
|
||||
false
|
||||
targetTable
|
||||
);
|
||||
final TableReference rhsTableKeyReference = keySideTableGroup.resolveTableReference(
|
||||
null,
|
||||
keyTable,
|
||||
false
|
||||
keyTable
|
||||
);
|
||||
|
||||
return generateJoinPredicate( lhsTableReference, rhsTableKeyReference, creationState );
|
||||
|
|
|
@ -139,7 +139,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
|
|||
selectableMappings,
|
||||
inverseMappingType,
|
||||
creationProcess,
|
||||
valueMapping.getDeclaringType(),
|
||||
this,
|
||||
this.attributeMappings
|
||||
)
|
||||
);
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
|||
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
@ -74,7 +75,8 @@ import static org.hibernate.metamodel.mapping.internal.MappingModelCreationHelpe
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ManyToManyCollectionPart extends AbstractEntityCollectionPart implements EntityAssociationMapping {
|
||||
public class ManyToManyCollectionPart extends AbstractEntityCollectionPart implements EntityAssociationMapping,
|
||||
LazyTableGroup.ParentTableGroupUseChecker {
|
||||
private ForeignKeyDescriptor foreignKey;
|
||||
private ValuedModelPart fkTargetModelPart;
|
||||
|
||||
|
@ -292,24 +294,7 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple
|
|||
sqlAliasBase,
|
||||
creationState
|
||||
),
|
||||
(np, tableExpression) -> {
|
||||
if ( ! foreignKey.getKeyTable().equals( tableExpression ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( navigablePath.equals( np.getParent() ) ) {
|
||||
return getTargetKeyPropertyNames().contains( np.getLocalName() );
|
||||
}
|
||||
|
||||
final String relativePath = np.relativize( navigablePath );
|
||||
if ( relativePath == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Empty relative path means the navigable paths are equal,
|
||||
// in which case we allow resolving the parent table group
|
||||
return relativePath.isEmpty() || getTargetKeyPropertyNames().contains( relativePath );
|
||||
},
|
||||
this,
|
||||
this,
|
||||
explicitSourceAlias,
|
||||
sqlAliasBase,
|
||||
|
@ -337,6 +322,11 @@ public class ManyToManyCollectionPart extends AbstractEntityCollectionPart imple
|
|||
return lazyTableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseParentTableGroup(TableGroupProducer producer, NavigablePath navigablePath, ValuedModelPart valuedModelPart) {
|
||||
return foreignKey.isKeyPart( valuedModelPart );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPartitionedSelectionMapping() {
|
||||
return foreignKey.hasPartitionedSelectionMapping();
|
||||
|
|
|
@ -130,6 +130,11 @@ public class OneToManyCollectionPart extends AbstractEntityCollectionPart implem
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
return getAssociatedEntityMappingType().containsTableReference( tableExpression );
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// TableGroupJoinProducer
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
|
|||
import org.hibernate.metamodel.mapping.PropertyBasedMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
@ -42,10 +43,12 @@ 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.OneToManyTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnknownTableReferenceException;
|
||||
import org.hibernate.sql.ast.tree.from.VirtualTableGroup;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -179,6 +182,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
return targetSide.getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeyPart(ValuedModelPart modelPart) {
|
||||
return this == modelPart || keySide.getModelPart() == modelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side getKeySide() {
|
||||
return keySide;
|
||||
|
@ -217,12 +225,32 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
@Override
|
||||
public DomainResult<?> createKeyDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
assert isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
navigablePath.append( ForeignKeyDescriptor.PART_NAME ),
|
||||
targetTableGroup,
|
||||
keySide.getModelPart(),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> createKeyDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup targetTableGroup,
|
||||
Nature fromSide,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
assert fromSide == Nature.TARGET
|
||||
? targetTableGroup.getTableReference( navigablePath, associationKey.getTable(), false ) != null
|
||||
: isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath.append( ForeignKeyDescriptor.PART_NAME ),
|
||||
targetTableGroup,
|
||||
keySide.getModelPart(),
|
||||
fetchParent,
|
||||
creationState
|
||||
|
@ -232,39 +260,53 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
@Override
|
||||
public DomainResult<?> createTargetDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
assert isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME ),
|
||||
targetTableGroup,
|
||||
targetSide.getModelPart(),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
Nature side,
|
||||
FetchParent fetchParent, DomainResultCreationState creationState) {
|
||||
if ( side == Nature.KEY ) {
|
||||
return createDomainResult( navigablePath, tableGroup, keySide.getModelPart(), fetchParent, creationState );
|
||||
}
|
||||
else {
|
||||
return createDomainResult( navigablePath, tableGroup, targetSide.getModelPart(), fetchParent, creationState );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return createDomainResult( navigablePath, tableGroup, keySide.getModelPart(), null, creationState );
|
||||
assert isTargetTableGroup( targetTableGroup );
|
||||
return createDomainResult(
|
||||
navigablePath.append( ForeignKeyDescriptor.PART_NAME ),
|
||||
targetTableGroup,
|
||||
keySide.getModelPart(),
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isTargetTableGroup(TableGroup tableGroup) {
|
||||
tableGroup = getUnderlyingTableGroup( tableGroup );
|
||||
final TableGroupProducer tableGroupProducer;
|
||||
if ( tableGroup instanceof OneToManyTableGroup ) {
|
||||
tableGroupProducer = (TableGroupProducer) ( (OneToManyTableGroup) tableGroup ).getElementTableGroup()
|
||||
.getModelPart();
|
||||
}
|
||||
else {
|
||||
tableGroupProducer = (TableGroupProducer) tableGroup.getModelPart();
|
||||
}
|
||||
return tableGroupProducer.containsTableReference( targetSide.getModelPart().getContainingTableExpression() );
|
||||
}
|
||||
|
||||
private static TableGroup getUnderlyingTableGroup(TableGroup tableGroup) {
|
||||
if ( tableGroup instanceof VirtualTableGroup ) {
|
||||
tableGroup = getUnderlyingTableGroup( ( (VirtualTableGroup) tableGroup ).getUnderlyingTableGroup() );
|
||||
}
|
||||
return tableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -287,23 +329,16 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
private <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
SelectableMapping selectableMapping,
|
||||
BasicValuedModelPart selectableMapping,
|
||||
FetchParent fetchParent,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||
|
||||
final NavigablePath resultNavigablePath;
|
||||
if ( selectableMapping == keySide.getModelPart() ) {
|
||||
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.PART_NAME );
|
||||
}
|
||||
else {
|
||||
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME );
|
||||
}
|
||||
final TableReference tableReference;
|
||||
try {
|
||||
tableReference = tableGroup.resolveTableReference(
|
||||
resultNavigablePath,
|
||||
navigablePath,
|
||||
selectableMapping,
|
||||
selectableMapping.getContainingTableExpression()
|
||||
);
|
||||
}
|
||||
|
@ -356,13 +391,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
SqlAstCreationState creationState) {
|
||||
final TableReference lhsTableReference = targetSideTableGroup.resolveTableReference(
|
||||
targetSideTableGroup.getNavigablePath(),
|
||||
targetSide.getModelPart().getContainingTableExpression(),
|
||||
false
|
||||
targetSide.getModelPart().getContainingTableExpression()
|
||||
);
|
||||
final TableReference rhsTableKeyReference = keySideTableGroup.resolveTableReference(
|
||||
null,
|
||||
keySide.getModelPart().getContainingTableExpression(),
|
||||
false
|
||||
keySide.getModelPart().getContainingTableExpression()
|
||||
);
|
||||
|
||||
return generateJoinPredicate( lhsTableReference, rhsTableKeyReference, creationState );
|
||||
|
|
|
@ -6,18 +6,85 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.AttributeMetadata;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.PropertyBasedMapping;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SingleAttributeIdentifierMapping extends EntityIdentifierMapping, PropertyBasedMapping {
|
||||
public interface SingleAttributeIdentifierMapping extends EntityIdentifierMapping, PropertyBasedMapping,
|
||||
AttributeMapping, AttributeMetadata {
|
||||
/**
|
||||
* Access to the identifier attribute's PropertyAccess
|
||||
*/
|
||||
PropertyAccess getPropertyAccess();
|
||||
|
||||
String getAttributeName();
|
||||
|
||||
@Override
|
||||
default String getPartName() {
|
||||
return ROLE_LOCAL_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
default Generator getGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getStateArrayPosition() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
default AttributeMetadata getAttributeMetadata() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
default ManagedMappingType getDeclaringType() {
|
||||
return findContainingEntityMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isNullable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isUpdatable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isIncludedInDirtyChecking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isIncludedInOptimisticLocking() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default MutabilityPlan getMutabilityPlan() {
|
||||
return ImmutableMutabilityPlan.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectablePath;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.persister.collection.AbstractCollectionPersister;
|
||||
|
@ -106,7 +107,8 @@ import org.hibernate.type.Type;
|
|||
*/
|
||||
public class ToOneAttributeMapping
|
||||
extends AbstractSingularAttributeMapping
|
||||
implements EntityValuedFetchable, EntityAssociationMapping, TableGroupJoinProducer {
|
||||
implements EntityValuedFetchable, EntityAssociationMapping, TableGroupJoinProducer,
|
||||
LazyTableGroup.ParentTableGroupUseChecker {
|
||||
|
||||
public enum Cardinality {
|
||||
ONE_TO_ONE,
|
||||
|
@ -409,18 +411,18 @@ public class ToOneAttributeMapping
|
|||
compositeType.getSubtypes()[0],
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.targetKeyPropertyName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
null,
|
||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.targetKeyPropertyName = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
targetKeyPropertyName,
|
||||
null,
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
|
@ -440,7 +442,7 @@ public class ToOneAttributeMapping
|
|||
else if ( bootValue.isReferenceToPrimaryKey() ) {
|
||||
this.targetKeyPropertyName = referencedPropertyName;
|
||||
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||
addPrefixedPropertyPaths(
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
targetKeyPropertyName,
|
||||
bootValue.getType(),
|
||||
|
@ -463,30 +465,41 @@ public class ToOneAttributeMapping
|
|||
compositeType.getSubtypes()[0],
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||
this.targetKeyPropertyName = referencedPropertyName;
|
||||
final String mapsIdAttributeName;
|
||||
// If there is a "virtual property" for a non-PK join mapping, we try to see if the columns match the
|
||||
// primary key columns and if so, we add the primary key property name as target key property
|
||||
if ( ( mapsIdAttributeName = findMapsIdPropertyName( entityMappingType, referencedPropertyName ) ) != null ) {
|
||||
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||
targetKeyPropertyNames.add( targetKeyPropertyName );
|
||||
addPrefixedPropertyPaths(
|
||||
targetKeyPropertyNames,
|
||||
mapsIdAttributeName,
|
||||
entityMappingType.getEntityPersister().getIdentifierType(),
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
else {
|
||||
this.targetKeyPropertyNames = Set.of(
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
targetKeyPropertyName,
|
||||
ForeignKeyDescriptor.PART_NAME
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
}
|
||||
addPrefixedPropertyNames(
|
||||
targetKeyPropertyNames,
|
||||
ForeignKeyDescriptor.PART_NAME,
|
||||
propertyType,
|
||||
declaringEntityPersister.getFactory()
|
||||
);
|
||||
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -653,7 +666,7 @@ public class ToOneAttributeMapping
|
|||
return null;
|
||||
}
|
||||
|
||||
private static void addPrefixedPropertyPaths(
|
||||
public static void addPrefixedPropertyPaths(
|
||||
Set<String> targetKeyPropertyNames,
|
||||
String prefix,
|
||||
Type type,
|
||||
|
@ -715,21 +728,40 @@ public class ToOneAttributeMapping
|
|||
propertyName = entityType.getRHSUniqueKeyPropertyName();
|
||||
}
|
||||
final String newPrefix;
|
||||
final String newPkPrefix;
|
||||
final String newFkPrefix;
|
||||
if ( prefix == null ) {
|
||||
newPrefix = propertyName;
|
||||
newPkPrefix = propertyName + "." + EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
newFkPrefix = ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
else if ( propertyName == null ) {
|
||||
newPrefix = prefix;
|
||||
newPkPrefix = prefix + "." + EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
newFkPrefix = prefix + "." + ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
else {
|
||||
newPrefix = prefix + "." + propertyName;
|
||||
newPkPrefix = prefix + "." + EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
newFkPrefix = prefix + "." + ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newPrefix, identifierOrUniqueKeyType, factory );
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newPkPrefix, identifierOrUniqueKeyType, factory );
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newFkPrefix, identifierOrUniqueKeyType, factory );
|
||||
if ( identifierOrUniqueKeyType instanceof EmbeddedComponentType ) {
|
||||
final String newEmbeddedPkPrefix;
|
||||
final String newEmbeddedFkPrefix;
|
||||
if ( prefix == null ) {
|
||||
newEmbeddedPkPrefix = EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
newEmbeddedFkPrefix = ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
else {
|
||||
newEmbeddedPkPrefix = prefix + "." + EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
newEmbeddedFkPrefix = prefix + "." + ForeignKeyDescriptor.PART_NAME;
|
||||
}
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newEmbeddedPkPrefix, identifierOrUniqueKeyType, factory );
|
||||
addPrefixedPropertyNames( targetKeyPropertyNames, newEmbeddedFkPrefix, identifierOrUniqueKeyType, factory );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -843,7 +875,11 @@ public class ToOneAttributeMapping
|
|||
else {
|
||||
fkPart = foreignKeyDescriptor.getTargetPart();
|
||||
}
|
||||
if ( fkPart instanceof EmbeddableValuedModelPart && fkPart instanceof VirtualModelPart ) {
|
||||
if ( fkPart instanceof EmbeddableValuedModelPart && fkPart instanceof VirtualModelPart
|
||||
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name )
|
||||
&& !ForeignKeyDescriptor.PART_NAME.equals( name )
|
||||
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( name )
|
||||
&& !fkPart.getPartName().equals( name ) ) {
|
||||
return ( (ModelPartContainer) fkPart ).findSubPart( name, targetType );
|
||||
}
|
||||
return fkPart;
|
||||
|
@ -940,14 +976,23 @@ public class ToOneAttributeMapping
|
|||
assert !creationState.isResolvingCircularFetch();
|
||||
try {
|
||||
creationState.setResolvingCircularFetch( true );
|
||||
foreignKeyDomainResult = foreignKeyDescriptor.createDomainResult(
|
||||
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
|
||||
foreignKeyDomainResult = foreignKeyDescriptor.createKeyDomainResult(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
sideNature,
|
||||
createTableGroupForDelayedFetch( fetchablePath, parentTableGroup, null, creationState ),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
foreignKeyDomainResult = foreignKeyDescriptor.createTargetDomainResult(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
creationState.setResolvingCircularFetch( false );
|
||||
}
|
||||
|
@ -1154,10 +1199,15 @@ public class ToOneAttributeMapping
|
|||
// For now, we don't do this if the key table is nullable to avoid an additional join
|
||||
if ( sideNature == ForeignKeyDescriptor.Nature.KEY && !isKeyTableNullable ) {
|
||||
keyDomainResult = foreignKeyDescriptor.createKeyDomainResult(
|
||||
fetchablePath,
|
||||
createTableGroupForDelayedFetch(
|
||||
fetchablePath,
|
||||
creationState.getSqlAstCreationState()
|
||||
.getFromClauseAccess()
|
||||
.findTableGroup( realFetchParent.getNavigablePath() ),
|
||||
null,
|
||||
creationState
|
||||
),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
|
@ -1207,14 +1257,24 @@ public class ToOneAttributeMapping
|
|||
else {
|
||||
realParent = parentNavigablePath;
|
||||
}
|
||||
final TableGroup tableGroup = fromClauseAccess.getTableGroup( realParent );
|
||||
final DomainResult<?> domainResult = foreignKeyDescriptor.createDomainResult(
|
||||
final TableGroup parentTableGroup = fromClauseAccess.getTableGroup( realParent );
|
||||
final DomainResult<?> domainResult;
|
||||
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
|
||||
domainResult = foreignKeyDescriptor.createKeyDomainResult(
|
||||
fetchablePath,
|
||||
tableGroup,
|
||||
sideNature,
|
||||
createTableGroupForDelayedFetch( fetchablePath, parentTableGroup, null, creationState ),
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
domainResult = foreignKeyDescriptor.createTargetDomainResult(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
if ( fetchTiming == FetchTiming.IMMEDIATE ) {
|
||||
return buildEntityFetchSelect(
|
||||
fetchParent,
|
||||
|
@ -1421,7 +1481,7 @@ public class ToOneAttributeMapping
|
|||
if ( notFoundAction != null || !isInternalLoadNullable ) {
|
||||
keyResult = foreignKeyDescriptor.createKeyDomainResult(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
tableGroup,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
|
@ -1484,13 +1544,29 @@ public class ToOneAttributeMapping
|
|||
else {
|
||||
side = this.sideNature;
|
||||
}
|
||||
final DomainResult<?> keyResult = foreignKeyDescriptor.createDomainResult(
|
||||
final DomainResult<?> keyResult;
|
||||
if ( side == ForeignKeyDescriptor.Nature.KEY ) {
|
||||
final TableGroup tableGroup = sideNature == ForeignKeyDescriptor.Nature.KEY
|
||||
? createTableGroupForDelayedFetch( fetchablePath, parentTableGroup, null, creationState )
|
||||
: parentTableGroup;
|
||||
keyResult = foreignKeyDescriptor.createKeyDomainResult(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
side,
|
||||
tableGroup,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
final TableGroup tableGroup = sideNature == ForeignKeyDescriptor.Nature.TARGET
|
||||
? parentTableGroup
|
||||
: createTableGroupForDelayedFetch( fetchablePath, parentTableGroup, null, creationState );
|
||||
keyResult = foreignKeyDescriptor.createTargetDomainResult(
|
||||
fetchablePath,
|
||||
tableGroup,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
final boolean selectByUniqueKey = isSelectByUniqueKey( side );
|
||||
|
||||
// Consider all associations annotated with @NotFound as EAGER
|
||||
|
@ -1577,6 +1653,38 @@ public class ToOneAttributeMapping
|
|||
);
|
||||
}
|
||||
|
||||
private TableGroup createTableGroupForDelayedFetch(
|
||||
NavigablePath fetchablePath,
|
||||
TableGroup parentTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
// Check if we can reuse a table group join of the parent
|
||||
final TableGroup compatibleTableGroup = parentTableGroup.findCompatibleJoinedGroup(
|
||||
this,
|
||||
SqlAstJoinType.LEFT
|
||||
);
|
||||
if ( compatibleTableGroup != null ) {
|
||||
return compatibleTableGroup;
|
||||
}
|
||||
// We have to create the table group that points to the target so that table reference resolving works
|
||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
resultVariable,
|
||||
null,
|
||||
SqlAstJoinType.LEFT,
|
||||
false,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||
creationState.getSqlAstCreationState().getFromClauseAccess().registerTableGroup(
|
||||
fetchablePath,
|
||||
tableGroupJoin.getJoinedGroup()
|
||||
);
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
}
|
||||
|
||||
private boolean isSelectByUniqueKey(ForeignKeyDescriptor.Nature side) {
|
||||
if ( side == ForeignKeyDescriptor.Nature.KEY ) {
|
||||
// case 1.2
|
||||
|
@ -1598,7 +1706,7 @@ public class ToOneAttributeMapping
|
|||
@Override
|
||||
public <T> DomainResult<T> createSnapshotDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup parentTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
// We need a join if either
|
||||
|
@ -1615,31 +1723,36 @@ public class ToOneAttributeMapping
|
|||
np -> {
|
||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
parentTableGroup,
|
||||
null,
|
||||
null,
|
||||
getDefaultSqlAstJoinType( tableGroup ),
|
||||
getDefaultSqlAstJoinType( parentTableGroup ),
|
||||
true,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
tableGroup.addTableGroupJoin( tableGroupJoin );
|
||||
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
tableGroupToUse = tableGroup;
|
||||
tableGroupToUse = createTableGroupForDelayedFetch(
|
||||
navigablePath,
|
||||
parentTableGroup,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
if ( hasNotFoundAction() ) {
|
||||
assert tableGroupToUse != tableGroup;
|
||||
assert tableGroupToUse != parentTableGroup;
|
||||
//noinspection unchecked
|
||||
return new NotFoundSnapshotResult(
|
||||
navigablePath,
|
||||
this,
|
||||
parentTableGroup,
|
||||
tableGroupToUse,
|
||||
tableGroup,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
@ -1727,6 +1840,11 @@ public class ToOneAttributeMapping
|
|||
return predicate == null || foreignKeyDescriptor.isSimpleJoinPredicate( predicate );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
return getEntityMappingType().containsTableReference( tableExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfFetchables() {
|
||||
return getEntityMappingType().getNumberOfFetchables();
|
||||
|
@ -1767,8 +1885,18 @@ public class ToOneAttributeMapping
|
|||
embeddablePathSb = new StringBuilder();
|
||||
}
|
||||
embeddablePathSb.insert( 0, parentContainer.getPartName() + "." );
|
||||
parentTableGroup = fromClauseAccess.findTableGroup( parentTableGroup.getNavigablePath().getParent() );
|
||||
parentContainer = parentTableGroup.getModelPart();
|
||||
final NavigablePath parentNavigablePath = parentTableGroup.getNavigablePath();
|
||||
final TableGroup tableGroup = fromClauseAccess.findTableGroup( parentNavigablePath.getParent() );
|
||||
if ( tableGroup == null ) {
|
||||
assert parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME )
|
||||
|| parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.TARGET_PART_NAME );
|
||||
// Might happen that we don't register a table group for the collection role if this is a
|
||||
// foreign key part and the collection is delayed. We can just break out in this case though,
|
||||
// since these checks here are only for reusing a map key property, which we won't have
|
||||
break;
|
||||
}
|
||||
parentTableGroup = tableGroup;
|
||||
parentContainer = tableGroup.getModelPart();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
|
@ -1803,28 +1931,7 @@ public class ToOneAttributeMapping
|
|||
indexTableGroup,
|
||||
fetched,
|
||||
pluralTableGroup,
|
||||
(np, tableExpression) -> {
|
||||
if ( !canUseParentTableGroup ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !identifyingColumnsTableExpression.equals( tableExpression ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( navigablePath.equals( np.getParent() ) ) {
|
||||
return targetKeyPropertyNames.contains( np.getLocalName() );
|
||||
}
|
||||
|
||||
final String relativePath = np.relativize( navigablePath );
|
||||
if ( relativePath == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Empty relative path means the navigable paths are equal,
|
||||
// in which case we allow resolving the parent table group
|
||||
return relativePath.isEmpty() || targetKeyPropertyNames.contains( relativePath );
|
||||
}
|
||||
this
|
||||
),
|
||||
null
|
||||
);
|
||||
|
@ -1850,8 +1957,11 @@ public class ToOneAttributeMapping
|
|||
lazyTableGroup,
|
||||
null
|
||||
);
|
||||
|
||||
final TableReference lhsTableReference = lhs.resolveTableReference( navigablePath, identifyingColumnsTableExpression );
|
||||
final TableReference lhsTableReference = lhs.resolveTableReference(
|
||||
navigablePath,
|
||||
this,
|
||||
identifyingColumnsTableExpression
|
||||
);
|
||||
|
||||
lazyTableGroup.setTableGroupInitializerCallback(
|
||||
tableGroup -> {
|
||||
|
@ -1932,7 +2042,19 @@ public class ToOneAttributeMapping
|
|||
TableGroup realParentTableGroup = lhs;
|
||||
final FromClauseAccess fromClauseAccess = creationState.getFromClauseAccess();
|
||||
while ( realParentTableGroup.getModelPart() instanceof EmbeddableValuedModelPart ) {
|
||||
realParentTableGroup = fromClauseAccess.findTableGroup( realParentTableGroup.getNavigablePath().getParent() );
|
||||
final NavigablePath parentNavigablePath = realParentTableGroup.getNavigablePath();
|
||||
final TableGroup tableGroup = fromClauseAccess.findTableGroup( parentNavigablePath.getParent() );
|
||||
if ( tableGroup == null ) {
|
||||
assert parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME )
|
||||
|| parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.TARGET_PART_NAME );
|
||||
// Might happen that we don't register a table group for the collection role if this is a
|
||||
// foreign key part and the collection is delayed. We can just break out in this case though,
|
||||
// since the realParentTableGroup is only relevant if this association is actually joined,
|
||||
// which it is not, because this is part of the target FK
|
||||
realParentTableGroup = null;
|
||||
break;
|
||||
}
|
||||
realParentTableGroup = tableGroup;
|
||||
}
|
||||
|
||||
final TableGroupProducer tableGroupProducer;
|
||||
|
@ -1958,28 +2080,7 @@ public class ToOneAttributeMapping
|
|||
sqlAliasBase,
|
||||
creationState
|
||||
),
|
||||
(np, tableExpression) -> {
|
||||
if ( !canUseParentTableGroup || tableGroupProducer != ToOneAttributeMapping.this ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !identifyingColumnsTableExpression.equals( tableExpression ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( navigablePath.pathsMatch( np.getParent() ) ) {
|
||||
return targetKeyPropertyNames.contains( np.getLocalName() );
|
||||
}
|
||||
|
||||
final String relativePath = np.relativize( navigablePath );
|
||||
if ( relativePath == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Empty relative path means the navigable paths are equal,
|
||||
// in which case we allow resolving the parent table group
|
||||
return relativePath.isEmpty() || targetKeyPropertyNames.contains( relativePath );
|
||||
},
|
||||
this,
|
||||
tableGroupProducer,
|
||||
explicitSourceAlias,
|
||||
sqlAliasBase,
|
||||
|
@ -2015,6 +2116,16 @@ public class ToOneAttributeMapping
|
|||
return lazyTableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseParentTableGroup(
|
||||
TableGroupProducer producer,
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart valuedModelPart) {
|
||||
return producer == this
|
||||
&& sideNature == ForeignKeyDescriptor.Nature.KEY
|
||||
&& foreignKeyDescriptor.isKeyPart( valuedModelPart );
|
||||
}
|
||||
|
||||
private void initializeIfNeeded(TableGroup lhs, SqlAstJoinType sqlAstJoinType, TableGroup tableGroup) {
|
||||
if ( sqlAstJoinType == SqlAstJoinType.INNER && ( isNullable || !lhs.canUseInnerJoins() ) ) {
|
||||
// Force initialization of the underlying table group join to retain cardinality
|
||||
|
|
|
@ -89,7 +89,7 @@ public class VirtualIdEmbeddable extends AbstractEmbeddableMapping implements Id
|
|||
selectableMappings,
|
||||
inverseMappingType,
|
||||
creationProcess,
|
||||
valueMapping.getDeclaringType(),
|
||||
this,
|
||||
this.attributeMappings
|
||||
)
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.metamodel.internal.MetadataContext;
|
|||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.IdentifiableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
|
@ -197,6 +198,13 @@ public class SingularAttributeImpl<D,J>
|
|||
if ( parent.getReferencedPathSource() instanceof PluralPersistentAttribute<?, ?, ?> ) {
|
||||
navigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() );
|
||||
}
|
||||
if ( getDeclaringType() instanceof IdentifiableDomainType<?> ) {
|
||||
final IdentifiableDomainType<?> declaringType = (IdentifiableDomainType<?>) getDeclaringType();
|
||||
if ( !declaringType.hasSingleIdAttribute() ) {
|
||||
return new EntityIdentifierNavigablePath( navigablePath, null )
|
||||
.append( getName(), SqmCreationHelper.determineAlias( alias ) );
|
||||
}
|
||||
}
|
||||
return new EntityIdentifierNavigablePath( navigablePath, SqmCreationHelper.determineAlias( alias ), getName() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1327,7 +1327,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
// Table references not appearing in this set can later be pruned away
|
||||
for ( String subclassTableName : subclassTableNames ) {
|
||||
final TableReference tableReference =
|
||||
tableGroup.getTableReference( null, subclassTableName, false, false );
|
||||
tableGroup.getTableReference( null, subclassTableName, false );
|
||||
if ( tableReference == null ) {
|
||||
throw new UnknownTableReferenceException( getRootTableName(), "Couldn't find table reference" );
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import org.hibernate.engine.spi.IdentifierValue;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
|
||||
|
@ -25,11 +27,12 @@ public class AnonymousTupleBasicEntityIdentifierMapping
|
|||
private final BasicEntityIdentifierMapping delegate;
|
||||
|
||||
public AnonymousTupleBasicEntityIdentifierMapping(
|
||||
MappingType declaringType,
|
||||
String selectionExpression,
|
||||
SqmExpressible<?> expressible,
|
||||
JdbcMapping jdbcMapping,
|
||||
BasicEntityIdentifierMapping delegate) {
|
||||
super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping, -1 );
|
||||
super( declaringType, delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping, -1 );
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
|
@ -67,4 +70,9 @@ public class AnonymousTupleBasicEntityIdentifierMapping
|
|||
public String getAttributeName() {
|
||||
return getPartName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedMappingType getDeclaringType() {
|
||||
return (ManagedMappingType) super.getDeclaringType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.OwnedValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
|
@ -41,9 +41,10 @@ import org.hibernate.type.descriptor.java.JavaType;
|
|||
* @author Christian Beikov
|
||||
*/
|
||||
@Incubating
|
||||
public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingType, BasicValuedModelPart {
|
||||
public class AnonymousTupleBasicValuedModelPart implements OwnedValuedModelPart, MappingType, BasicValuedModelPart {
|
||||
|
||||
private static final FetchOptions FETCH_OPTIONS = FetchOptions.valueOf( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
|
||||
private final MappingType declaringType;
|
||||
private final String partName;
|
||||
private final String selectionExpression;
|
||||
private final SqmExpressible<?> expressible;
|
||||
|
@ -51,11 +52,13 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp
|
|||
private final int fetchableIndex;
|
||||
|
||||
public AnonymousTupleBasicValuedModelPart(
|
||||
MappingType declaringType,
|
||||
String partName,
|
||||
String selectionExpression,
|
||||
SqmExpressible<?> expressible,
|
||||
JdbcMapping jdbcMapping,
|
||||
int fetchableIndex) {
|
||||
this.declaringType = declaringType;
|
||||
this.partName = partName;
|
||||
this.selectionExpression = selectionExpression;
|
||||
this.expressible = expressible;
|
||||
|
@ -78,6 +81,11 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp
|
|||
return expressible.getExpressibleJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getDeclaringType() {
|
||||
return declaringType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPartName() {
|
||||
return partName;
|
||||
|
@ -217,6 +225,7 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp
|
|||
final SqlExpressionResolver expressionResolver = creationState.getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
this,
|
||||
getContainingTableExpression()
|
||||
);
|
||||
final Expression expression = expressionResolver.resolveSqlExpression( tableReference, this );
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.derived;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -34,7 +35,9 @@ import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
|
@ -60,6 +63,8 @@ import org.hibernate.sql.results.graph.Fetchable;
|
|||
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
import jakarta.persistence.metamodel.Attribute;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
|
@ -76,12 +81,25 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued
|
|||
private final int fetchableIndex;
|
||||
|
||||
public AnonymousTupleEmbeddableValuedModelPart(
|
||||
Map<String, ModelPart> modelPartMap,
|
||||
SqmExpressible<?> sqmExpressible,
|
||||
List<SqlSelection> sqlSelections,
|
||||
int selectionIndex,
|
||||
String selectionExpression,
|
||||
Set<String> compatibleTableExpressions,
|
||||
Set<Attribute<?, ?>> attributes,
|
||||
DomainType<?> domainType,
|
||||
String componentName,
|
||||
EmbeddableValuedModelPart existingModelPartContainer,
|
||||
int fetchableIndex) {
|
||||
this.modelPartMap = modelPartMap;
|
||||
this.modelPartMap = createModelParts(
|
||||
sqmExpressible,
|
||||
sqlSelections,
|
||||
selectionIndex,
|
||||
selectionExpression,
|
||||
compatibleTableExpressions,
|
||||
attributes,
|
||||
existingModelPartContainer
|
||||
);
|
||||
this.modelParts = modelPartMap.values().toArray( new ModelPart[0] );
|
||||
this.domainType = domainType;
|
||||
this.componentName = componentName;
|
||||
|
@ -89,6 +107,38 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued
|
|||
this.fetchableIndex = fetchableIndex;
|
||||
}
|
||||
|
||||
private Map<String, ModelPart> createModelParts(
|
||||
SqmExpressible<?> sqmExpressible,
|
||||
List<SqlSelection> sqlSelections,
|
||||
int selectionIndex,
|
||||
String selectionExpression,
|
||||
Set<String> compatibleTableExpressions,
|
||||
Set<Attribute<?, ?>> attributes,
|
||||
EmbeddableValuedModelPart modelPartContainer) {
|
||||
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
|
||||
int index = 0;
|
||||
for ( Attribute<?, ?> attribute : attributes ) {
|
||||
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
|
||||
throw new IllegalArgumentException( "Only embeddables without collections are supported!" );
|
||||
}
|
||||
final DomainType<?> attributeType = ( (SingularPersistentAttribute<?, ?>) attribute ).getType();
|
||||
final ModelPart modelPart = AnonymousTupleTableGroupProducer.createModelPart(
|
||||
this,
|
||||
sqmExpressible,
|
||||
attributeType,
|
||||
sqlSelections,
|
||||
selectionIndex,
|
||||
selectionExpression + "_" + attribute.getName(),
|
||||
attribute.getName(),
|
||||
modelPartContainer.findSubPart( attribute.getName(), null ),
|
||||
compatibleTableExpressions,
|
||||
index++
|
||||
);
|
||||
modelParts.put( modelPart.getPartName(), modelPart );
|
||||
}
|
||||
return modelParts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||
return modelPartMap.get( name );
|
||||
|
@ -281,7 +331,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued
|
|||
SqlAstCreationState sqlAstCreationState) {
|
||||
final List<ColumnReference> columnReferences = CollectionHelper.arrayList( getJdbcTypeCount() );
|
||||
final NavigablePath navigablePath = tableGroup.getNavigablePath().append( componentName );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, getContainingTableExpression() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, this, getContainingTableExpression() );
|
||||
for ( ModelPart modelPart : modelParts ) {
|
||||
modelPart.forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
|
|
|
@ -6,17 +6,26 @@
|
|||
*/
|
||||
package org.hibernate.query.derived;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.spi.IdentifierValue;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
|
||||
import jakarta.persistence.metamodel.Attribute;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
|
@ -28,14 +37,23 @@ public class AnonymousTupleEmbeddedEntityIdentifierMapping extends AnonymousTupl
|
|||
private final CompositeIdentifierMapping delegate;
|
||||
|
||||
public AnonymousTupleEmbeddedEntityIdentifierMapping(
|
||||
Map<String, ModelPart> modelParts,
|
||||
SqmExpressible<?> sqmExpressible,
|
||||
List<SqlSelection> sqlSelections,
|
||||
int selectionIndex,
|
||||
String selectionExpression,
|
||||
Set<String> compatibleTableExpressions,
|
||||
Set<Attribute<?, ?>> attributes,
|
||||
DomainType<?> domainType,
|
||||
String componentName,
|
||||
CompositeIdentifierMapping delegate) {
|
||||
super(
|
||||
modelParts,
|
||||
sqmExpressible,
|
||||
sqlSelections,
|
||||
selectionIndex,
|
||||
selectionExpression,
|
||||
compatibleTableExpressions,
|
||||
attributes,
|
||||
domainType,
|
||||
componentName,
|
||||
delegate.getAttributeName(),
|
||||
delegate,
|
||||
-1
|
||||
);
|
||||
|
@ -72,6 +90,11 @@ public class AnonymousTupleEmbeddedEntityIdentifierMapping extends AnonymousTupl
|
|||
return ((SingleAttributeIdentifierMapping) delegate).getPropertyAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Object value1, Object value2) {
|
||||
return super.compare( value1, value2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeName() {
|
||||
return getPartName();
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.TableDetails;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.OneToManyCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
|
@ -59,6 +60,7 @@ import org.hibernate.sql.ast.tree.from.StandardTableGroup;
|
|||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
@ -74,7 +76,8 @@ import static org.hibernate.internal.util.collections.CollectionHelper.arrayList
|
|||
*/
|
||||
@Incubating
|
||||
public class AnonymousTupleEntityValuedModelPart
|
||||
implements EntityValuedModelPart, EntityMappingType, TableGroupJoinProducer {
|
||||
implements EntityValuedModelPart, EntityMappingType, TableGroupJoinProducer, ValuedModelPart,
|
||||
LazyTableGroup.ParentTableGroupUseChecker {
|
||||
|
||||
private final EntityIdentifierMapping identifierMapping;
|
||||
private final DomainType<?> domainType;
|
||||
|
@ -115,7 +118,7 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
@Override
|
||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
|
||||
if ( ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName().equals( name ) ) {
|
||||
if ( identifierMapping.getAttributeName().equals( name ) ) {
|
||||
return identifierMapping;
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +144,11 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getMappedType() {
|
||||
return getPartMappingType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<?> getJavaType() {
|
||||
return domainType.getExpressibleJavaType();
|
||||
|
@ -151,6 +159,11 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
return componentName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCount() {
|
||||
return delegate.getJdbcTypeCount();
|
||||
|
@ -227,6 +240,11 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
return identifierMapping.forEachSelectable( offset, consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectableMapping getSelectable(int columnIndex) {
|
||||
return identifierMapping.getSelectable( columnIndex );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType<?> getMappedJavaType() {
|
||||
return delegate.getJavaType();
|
||||
|
@ -375,8 +393,7 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
final SelectableMapping targetMapping = targetMappings.get( i );
|
||||
final TableReference targetTableReference = tg.resolveTableReference(
|
||||
null,
|
||||
targetMapping.getContainingTableExpression(),
|
||||
false
|
||||
targetMapping.getContainingTableExpression()
|
||||
);
|
||||
predicateConsumer.accept(
|
||||
new ComparisonPredicate(
|
||||
|
@ -444,7 +461,6 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
creationState.getSqlAliasBaseGenerator()
|
||||
);
|
||||
final boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins();
|
||||
final EntityPersister entityPersister = delegate.getEntityMappingType().getEntityPersister();
|
||||
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
|
||||
canUseInnerJoin,
|
||||
navigablePath,
|
||||
|
@ -457,23 +473,7 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
sqlAliasBase,
|
||||
creationState
|
||||
),
|
||||
(np, tableExpression) -> {
|
||||
if ( !tableExpression.isEmpty() && !entityPersister.containsTableReference( tableExpression ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( navigablePath.equals( np.getParent() ) ) {
|
||||
return targetKeyPropertyNames.contains( np.getLocalName() );
|
||||
}
|
||||
|
||||
final String relativePath = np.relativize( navigablePath );
|
||||
if ( relativePath == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Empty relative path means the navigable paths are equal,
|
||||
// in which case we allow resolving the parent table group
|
||||
return relativePath.isEmpty() || targetKeyPropertyNames.contains( relativePath );
|
||||
},
|
||||
this,
|
||||
this,
|
||||
explicitSourceAlias,
|
||||
sqlAliasBase,
|
||||
|
@ -490,6 +490,22 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
return lazyTableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseParentTableGroup(TableGroupProducer producer, NavigablePath navigablePath, ValuedModelPart valuedModelPart) {
|
||||
final ModelPart foreignKeyPart = getForeignKeyPart();
|
||||
if ( foreignKeyPart instanceof AnonymousTupleNonAggregatedEntityIdentifierMapping ) {
|
||||
final AnonymousTupleNonAggregatedEntityIdentifierMapping identifierMapping = (AnonymousTupleNonAggregatedEntityIdentifierMapping) foreignKeyPart;
|
||||
final int numberOfFetchables = identifierMapping.getNumberOfFetchables();
|
||||
for ( int i = 0; i< numberOfFetchables; i++ ) {
|
||||
if ( valuedModelPart == identifierMapping.getFetchable( i ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return foreignKeyPart == valuedModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlAliasStem() {
|
||||
return getPartName();
|
||||
|
@ -707,4 +723,9 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
? ( (TableGroupJoinProducer) delegate ).isSimpleJoinPredicate( predicate )
|
||||
: false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
return ( (TableGroupProducer) delegate ).containsTableReference( tableExpression );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.query.derived;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
|
@ -19,6 +21,10 @@ import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
|||
import org.hibernate.metamodel.mapping.internal.IdClassEmbeddable;
|
||||
import org.hibernate.metamodel.mapping.internal.VirtualIdEmbeddable;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
|
||||
import jakarta.persistence.metamodel.Attribute;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
|
@ -30,12 +36,22 @@ public class AnonymousTupleNonAggregatedEntityIdentifierMapping extends Anonymou
|
|||
private final NonAggregatedIdentifierMapping delegate;
|
||||
|
||||
public AnonymousTupleNonAggregatedEntityIdentifierMapping(
|
||||
Map<String, ModelPart> modelParts,
|
||||
SqmExpressible<?> sqmExpressible,
|
||||
List<SqlSelection> sqlSelections,
|
||||
int selectionIndex,
|
||||
String selectionExpression,
|
||||
Set<String> compatibleTableExpressions,
|
||||
Set<Attribute<?, ?>> attributes,
|
||||
DomainType<?> domainType,
|
||||
String componentName,
|
||||
NonAggregatedIdentifierMapping delegate) {
|
||||
super(
|
||||
modelParts,
|
||||
sqmExpressible,
|
||||
sqlSelections,
|
||||
selectionIndex,
|
||||
selectionExpression,
|
||||
compatibleTableExpressions,
|
||||
attributes,
|
||||
domainType,
|
||||
componentName,
|
||||
delegate,
|
||||
|
|
|
@ -36,7 +36,6 @@ import org.hibernate.metamodel.model.domain.DomainType;
|
|||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||
|
@ -92,6 +91,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
|
|||
final SqmPath<?> sqmPath = (SqmPath<?>) selectableNode;
|
||||
final TableGroup tableGroup = fromClauseAccess.findTableGroup( sqmPath.getNavigablePath() );
|
||||
modelPart = createModelPart(
|
||||
this,
|
||||
selectableNode.getExpressible(),
|
||||
sqmPath.getNodeType().getSqmPathType(),
|
||||
sqlSelections,
|
||||
|
@ -105,6 +105,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
|
|||
}
|
||||
else {
|
||||
modelPart = new AnonymousTupleBasicValuedModelPart(
|
||||
this,
|
||||
partName,
|
||||
partName,
|
||||
selectableNode.getExpressible(),
|
||||
|
@ -129,7 +130,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
|
|||
return tableGroup.getModelPart();
|
||||
}
|
||||
|
||||
private ModelPart createModelPart(
|
||||
public static ModelPart createModelPart(
|
||||
MappingType mappingType,
|
||||
SqmExpressible<?> sqmExpressible,
|
||||
DomainType<?> domainType,
|
||||
List<SqlSelection> sqlSelections,
|
||||
|
@ -145,41 +147,24 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
|
|||
.getIdentifierMapping();
|
||||
final EntityIdentifierMapping newIdentifierMapping;
|
||||
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
|
||||
final String attributeName = identifierMapping.getAttributeName();
|
||||
if ( identifierMapping.getPartMappingType() instanceof ManagedMappingType ) {
|
||||
//noinspection unchecked
|
||||
final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) ( (EntityDomainType<?>) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes();
|
||||
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
|
||||
final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping;
|
||||
int index = 0;
|
||||
for ( Attribute<?, ?> attribute : attributes ) {
|
||||
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
|
||||
throw new IllegalArgumentException( "Only embeddables without collections are supported!" );
|
||||
}
|
||||
final DomainType<?> attributeType = ( (SingularPersistentAttribute<?, ?>) attribute ).getType();
|
||||
final ModelPart modelPart = createModelPart(
|
||||
newIdentifierMapping = new AnonymousTupleEmbeddedEntityIdentifierMapping(
|
||||
sqmExpressible,
|
||||
attributeType,
|
||||
sqlSelections,
|
||||
selectionIndex,
|
||||
selectionExpression + "_" + attributeName + "_" + attribute.getName(),
|
||||
attribute.getName(),
|
||||
modelPartContainer.findSubPart( attribute.getName(), null ),
|
||||
selectionExpression + "_" + identifierMapping.getAttributeName(),
|
||||
compatibleTableExpressions,
|
||||
index++
|
||||
);
|
||||
modelParts.put( modelPart.getPartName(), modelPart );
|
||||
}
|
||||
newIdentifierMapping = new AnonymousTupleEmbeddedEntityIdentifierMapping(
|
||||
modelParts,
|
||||
attributes,
|
||||
domainType,
|
||||
attributeName,
|
||||
(CompositeIdentifierMapping) identifierMapping
|
||||
);
|
||||
}
|
||||
else {
|
||||
newIdentifierMapping = new AnonymousTupleBasicEntityIdentifierMapping(
|
||||
selectionExpression + "_" + attributeName,
|
||||
mappingType,
|
||||
selectionExpression + "_" + identifierMapping.getAttributeName(),
|
||||
sqmExpressible,
|
||||
sqlSelections.get( selectionIndex ).getExpressionType().getSingleJdbcMapping(),
|
||||
(BasicEntityIdentifierMapping) identifierMapping
|
||||
|
@ -189,29 +174,13 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
|
|||
else {
|
||||
//noinspection unchecked
|
||||
final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) ( (EntityDomainType<?>) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes();
|
||||
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
|
||||
final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping;
|
||||
int index = 0;
|
||||
for ( Attribute<?, ?> attribute : attributes ) {
|
||||
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
|
||||
throw new IllegalArgumentException( "Only embeddables without collections are supported!" );
|
||||
}
|
||||
final DomainType<?> attributeType = ( (SingularPersistentAttribute<?, ?>) attribute ).getType();
|
||||
final ModelPart modelPart = createModelPart(
|
||||
sqmExpressible,
|
||||
attributeType,
|
||||
sqlSelections,
|
||||
selectionIndex + index,
|
||||
selectionExpression + "_" + attribute.getName(),
|
||||
attribute.getName(),
|
||||
modelPartContainer.findSubPart( attribute.getName(), null ),
|
||||
compatibleTableExpressions,
|
||||
index++
|
||||
);
|
||||
modelParts.put( modelPart.getPartName(), modelPart );
|
||||
}
|
||||
newIdentifierMapping = new AnonymousTupleNonAggregatedEntityIdentifierMapping(
|
||||
modelParts,
|
||||
sqmExpressible,
|
||||
sqlSelections,
|
||||
selectionIndex,
|
||||
selectionExpression,
|
||||
compatibleTableExpressions,
|
||||
attributes,
|
||||
domainType,
|
||||
selectionExpression,
|
||||
(NonAggregatedIdentifierMapping) identifierMapping
|
||||
|
@ -232,31 +201,22 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map
|
|||
else if ( domainType instanceof ManagedDomainType<?> ) {
|
||||
//noinspection unchecked
|
||||
final Set<Attribute<?, ?>> attributes = (Set<Attribute<?, ?>>) ( (ManagedDomainType<?>) domainType ).getAttributes();
|
||||
final Map<String, ModelPart> modelParts = CollectionHelper.linkedMapOfSize( attributes.size() );
|
||||
final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) existingModelPart;
|
||||
int index = 0;
|
||||
for ( Attribute<?, ?> attribute : attributes ) {
|
||||
if ( !( attribute instanceof SingularPersistentAttribute<?, ?> ) ) {
|
||||
throw new IllegalArgumentException( "Only embeddables without collections are supported" );
|
||||
}
|
||||
final DomainType<?> attributeType = ( (SingularPersistentAttribute<?, ?>) attribute ).getType();
|
||||
final ModelPart modelPart = createModelPart(
|
||||
return new AnonymousTupleEmbeddableValuedModelPart(
|
||||
sqmExpressible,
|
||||
attributeType,
|
||||
sqlSelections,
|
||||
selectionIndex + index,
|
||||
selectionExpression + "_" + attribute.getName(),
|
||||
attribute.getName(),
|
||||
modelPartContainer.findSubPart( attribute.getName(), null ),
|
||||
selectionIndex,
|
||||
selectionExpression,
|
||||
compatibleTableExpressions,
|
||||
index++
|
||||
attributes,
|
||||
domainType,
|
||||
selectionExpression,
|
||||
(EmbeddableValuedModelPart) existingModelPart,
|
||||
fetchableIndex
|
||||
);
|
||||
modelParts.put( modelPart.getPartName(), modelPart );
|
||||
}
|
||||
return new AnonymousTupleEmbeddableValuedModelPart( modelParts, domainType, selectionExpression, modelPartContainer, fetchableIndex );
|
||||
}
|
||||
else {
|
||||
return new AnonymousTupleBasicValuedModelPart(
|
||||
mappingType,
|
||||
partName,
|
||||
selectionExpression,
|
||||
sqmExpressible,
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteTable;
|
||||
|
@ -43,19 +44,24 @@ public class CteTupleTableGroupProducer extends AnonymousTupleTableGroupProducer
|
|||
final BasicType<String> stringType = cteStatement.nodeBuilder()
|
||||
.getTypeConfiguration()
|
||||
.getBasicTypeForJavaType( String.class );
|
||||
this.searchModelPart = createModelPart( cteStatement.getSearchAttributeName(), stringType );
|
||||
this.searchModelPart = createModelPart( this, cteStatement.getSearchAttributeName(), stringType );
|
||||
this.cycleMarkModelPart = createModelPart(
|
||||
this,
|
||||
cteStatement.getCycleMarkAttributeName(),
|
||||
cteStatement.getCycleLiteral() == null
|
||||
? null
|
||||
: (BasicType<?>) cteStatement.getCycleLiteral().getNodeType()
|
||||
);
|
||||
this.cyclePathModelPart = createModelPart( cteStatement.getCyclePathAttributeName(), stringType );
|
||||
this.cyclePathModelPart = createModelPart( this, cteStatement.getCyclePathAttributeName(), stringType );
|
||||
}
|
||||
|
||||
private static AnonymousTupleBasicValuedModelPart createModelPart(String attributeName, BasicType<?> basicType) {
|
||||
private static AnonymousTupleBasicValuedModelPart createModelPart(
|
||||
MappingType declaringType,
|
||||
String attributeName,
|
||||
BasicType<?> basicType) {
|
||||
if ( attributeName != null ) {
|
||||
return new AnonymousTupleBasicValuedModelPart(
|
||||
declaringType,
|
||||
attributeName,
|
||||
attributeName,
|
||||
basicType,
|
||||
|
|
|
@ -374,8 +374,8 @@ public class DomainResultCreationStateImpl
|
|||
|
||||
@Override
|
||||
public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
|
||||
final EntityValuedModelPart entityValuedFetchable = fetchParent.getEntityValuedModelPart();
|
||||
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
|
||||
final EntityValuedModelPart parentModelPart = fetchParent.getEntityValuedModelPart();
|
||||
final EntityIdentifierMapping identifierMapping = parentModelPart.getEntityMappingType().getIdentifierMapping();
|
||||
final String identifierAttributeName = attributeName( identifierMapping );
|
||||
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
|
||||
final String fullPath;
|
||||
|
@ -388,7 +388,7 @@ public class DomainResultCreationStateImpl
|
|||
oldEntry.getKey() + "." + identifierAttributeName;
|
||||
}
|
||||
|
||||
final Fetchable fetchable = (Fetchable) identifierMapping;
|
||||
final Fetchable identifierFetchable = (Fetchable) identifierMapping;
|
||||
final FetchBuilder explicitFetchBuilder = (FetchBuilder) fetchBuilderResolverStack
|
||||
.getCurrent()
|
||||
.apply( fullPath );
|
||||
|
@ -423,7 +423,7 @@ public class DomainResultCreationStateImpl
|
|||
}
|
||||
else {
|
||||
if ( fetchBuilderLegacy == null ) {
|
||||
fetchBuilder = Builders.implicitFetchBuilder( fetchPath, fetchable, this );
|
||||
fetchBuilder = Builders.implicitFetchBuilder( fetchPath, identifierFetchable, this );
|
||||
}
|
||||
else {
|
||||
fetchBuilder = fetchBuilderLegacy;
|
||||
|
|
|
@ -54,15 +54,14 @@ public class TableGroupImpl extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, resolve ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
return super.getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
return super.getTableReference( navigablePath, tableExpression, resolve );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, Basi
|
|||
final String mappedTable = referencedModelPart.getContainingTableExpression();
|
||||
|
||||
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( parent.getNavigablePath() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, mappedTable );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, referencedModelPart, mappedTable );
|
||||
|
||||
final String selectedAlias;
|
||||
final int jdbcPosition;
|
||||
|
|
|
@ -86,7 +86,11 @@ public class CompleteFetchBuilderEmbeddableValuedModelPart
|
|||
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
||||
modelPart.forEachSelectable(
|
||||
(selectionIndex, selectableMapping) -> {
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, selectableMapping.getContainingTableExpression() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
selectableMapping.getContainingTableExpression()
|
||||
);
|
||||
final String columnAlias = columnAliases.get( selectionIndex );
|
||||
creationStateImpl.resolveSqlSelection(
|
||||
ResultsHelper.resolveSqlExpression(
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
import java.util.function.BiFunction;
|
||||
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.query.results.ResultsHelper;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||
|
@ -86,7 +87,11 @@ public class CompleteFetchBuilderEntityValuedModelPart
|
|||
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
||||
modelPart.forEachSelectable(
|
||||
(selectionIndex, selectableMapping) -> {
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, selectableMapping.getContainingTableExpression() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
(ValuedModelPart) modelPart,
|
||||
selectableMapping.getContainingTableExpression()
|
||||
);
|
||||
final String columnAlias = columnAliases.get( selectionIndex );
|
||||
creationStateImpl.resolveSqlSelection(
|
||||
ResultsHelper.resolveSqlExpression(
|
||||
|
|
|
@ -75,7 +75,7 @@ public class CompleteResultBuilderBasicModelPart
|
|||
final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState );
|
||||
|
||||
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, modelPart.getContainingTableExpression() );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, modelPart, modelPart.getContainingTableExpression() );
|
||||
|
||||
final SqlSelection sqlSelection = creationStateImpl.resolveSqlSelection(
|
||||
ResultsHelper.resolveSqlExpression(
|
||||
|
|
|
@ -172,7 +172,11 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
|
|||
(selectionIndex, selectableMapping) -> {
|
||||
resolveSqlSelection(
|
||||
columnNames.get( selectionIndex ),
|
||||
tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() ),
|
||||
tableGroup.resolveTableReference(
|
||||
fetchPath,
|
||||
keyDescriptor.getKeyPart(),
|
||||
selectableMapping.getContainingTableExpression()
|
||||
),
|
||||
selectableMapping,
|
||||
jdbcResultsMetadata,
|
||||
domainResultCreationState
|
||||
|
|
|
@ -12,8 +12,11 @@ import java.util.function.BiFunction;
|
|||
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -80,9 +83,108 @@ public class DynamicFetchBuilderStandard
|
|||
final Fetchable attributeMapping = (Fetchable) parent.getReferencedMappingContainer().findSubPart( fetchableName, null );
|
||||
final SqlExpressionResolver sqlExpressionResolver = domainResultCreationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
|
||||
final SelectableConsumer selectableConsumer = (selectionIndex, selectableMapping) -> {
|
||||
if ( attributeMapping instanceof BasicValuedModelPart ) {
|
||||
attributeMapping.forEachSelectable(
|
||||
getSelectableConsumer(
|
||||
fetchPath,
|
||||
jdbcResultsMetadata,
|
||||
domainResultCreationState,
|
||||
creationStateImpl,
|
||||
ownerTableGroup,
|
||||
sqlExpressionResolver,
|
||||
(BasicValuedModelPart) attributeMapping
|
||||
)
|
||||
);
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
else if ( attributeMapping instanceof EmbeddableValuedFetchable ) {
|
||||
attributeMapping.forEachSelectable(
|
||||
getSelectableConsumer(
|
||||
fetchPath,
|
||||
jdbcResultsMetadata,
|
||||
domainResultCreationState,
|
||||
creationStateImpl,
|
||||
ownerTableGroup,
|
||||
sqlExpressionResolver,
|
||||
(EmbeddableValuedFetchable) attributeMapping
|
||||
)
|
||||
);
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
false,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
|
||||
toOneAttributeMapping.getForeignKeyDescriptor().getPart( toOneAttributeMapping.getSideNature() )
|
||||
.forEachSelectable(
|
||||
getSelectableConsumer(
|
||||
fetchPath,
|
||||
jdbcResultsMetadata,
|
||||
domainResultCreationState,
|
||||
creationStateImpl,
|
||||
ownerTableGroup,
|
||||
sqlExpressionResolver,
|
||||
toOneAttributeMapping.getForeignKeyDescriptor()
|
||||
)
|
||||
);
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.DELAYED,
|
||||
false,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
else {
|
||||
assert attributeMapping instanceof PluralAttributeMapping;
|
||||
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
|
||||
pluralAttributeMapping.getKeyDescriptor().visitTargetSelectables(
|
||||
getSelectableConsumer(
|
||||
fetchPath,
|
||||
jdbcResultsMetadata,
|
||||
domainResultCreationState,
|
||||
creationStateImpl,
|
||||
ownerTableGroup,
|
||||
sqlExpressionResolver,
|
||||
pluralAttributeMapping.getKeyDescriptor()
|
||||
)
|
||||
);
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.DELAYED,
|
||||
false,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private SelectableConsumer getSelectableConsumer(
|
||||
NavigablePath fetchPath,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
DomainResultCreationState domainResultCreationState,
|
||||
DomainResultCreationStateImpl creationStateImpl,
|
||||
TableGroup ownerTableGroup,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
ValuedModelPart valuedModelPart) {
|
||||
return (selectionIndex, selectableMapping) -> {
|
||||
final TableReference tableReference = ownerTableGroup.resolveTableReference(
|
||||
fetchPath,
|
||||
valuedModelPart,
|
||||
selectableMapping.getContainingTableExpression()
|
||||
);
|
||||
final String columnAlias = columnNames.get( selectionIndex );
|
||||
|
@ -102,54 +204,6 @@ public class DynamicFetchBuilderStandard
|
|||
.getTypeConfiguration()
|
||||
);
|
||||
};
|
||||
if ( attributeMapping instanceof BasicValuedMapping ) {
|
||||
attributeMapping.forEachSelectable( selectableConsumer );
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
else if ( attributeMapping instanceof EmbeddableValuedFetchable ) {
|
||||
attributeMapping.forEachSelectable( selectableConsumer );
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
false,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
|
||||
toOneAttributeMapping.getForeignKeyDescriptor().getPart( toOneAttributeMapping.getSideNature() )
|
||||
.forEachSelectable( selectableConsumer );
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.DELAYED,
|
||||
false,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
else {
|
||||
assert attributeMapping instanceof PluralAttributeMapping;
|
||||
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
|
||||
pluralAttributeMapping.getKeyDescriptor().visitTargetSelectables( selectableConsumer );
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.DELAYED,
|
||||
false,
|
||||
null,
|
||||
creationStateImpl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -97,7 +97,7 @@ public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicVal
|
|||
final Expression expression = ResultsHelper.resolveSqlExpression(
|
||||
creationStateImpl,
|
||||
jdbcResultsMetadata,
|
||||
parentTableGroup.resolveTableReference( fetchPath, table ),
|
||||
parentTableGroup.resolveTableReference( fetchPath, fetchable, table ),
|
||||
fetchable,
|
||||
column
|
||||
);
|
||||
|
|
|
@ -13,7 +13,6 @@ import java.util.Map;
|
|||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
|
@ -155,7 +154,6 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final NamedTableReference dmlTableReference = resolveUnionTableReference(
|
||||
|
|
|
@ -758,7 +758,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final TableReference rootTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
rootTableName,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
|
@ -777,7 +776,6 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final List<Map.Entry<List<CteColumn>, Assignment>> assignmentList = assignmentsByTable.get( updatingTableReference );
|
||||
|
|
|
@ -159,7 +159,6 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final List<Assignment> assignmentList = assignmentsByTable.get( updatingTableReference );
|
||||
|
@ -272,7 +271,6 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final List<Assignment> assignmentList = assignmentsByTable.get( updatingTableReference );
|
||||
|
|
|
@ -332,7 +332,6 @@ public class InlineUpdateHandler implements UpdateHandler {
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
|
|
|
@ -301,7 +301,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
|
@ -661,7 +660,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.MutableBoolean;
|
||||
import org.hibernate.internal.util.MutableInteger;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
|
@ -329,7 +328,6 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
final NamedTableReference tableReference = (NamedTableReference) tableGroup.getTableReference(
|
||||
tableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
final QuerySpec idMatchingSubQuerySpec;
|
||||
|
|
|
@ -243,7 +243,6 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
|
|||
final TableReference updatingTableReference = updatingTableGroup.getTableReference(
|
||||
updatingTableGroup.getNavigablePath(),
|
||||
tableExpression,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ import org.hibernate.metamodel.mapping.SelectableMappings;
|
|||
import org.hibernate.metamodel.mapping.SqlExpressible;
|
||||
import org.hibernate.metamodel.mapping.SqlTypedMapping;
|
||||
import org.hibernate.metamodel.mapping.ValueMapping;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ManyToManyCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.OneToManyCollectionPart;
|
||||
|
@ -182,6 +183,7 @@ import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedRoot;
|
||||
import org.hibernate.query.sqm.tree.expression.Conversion;
|
||||
|
@ -2901,7 +2903,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
final int subclassTableSpan = persister.getSubclassTableSpan();
|
||||
for ( int i = 0; i < subclassTableSpan; i++ ) {
|
||||
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ), false );
|
||||
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2927,7 +2929,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
final int subclassTableSpan = persister.getSubclassTableSpan();
|
||||
for ( int i = 0; i < subclassTableSpan; i++ ) {
|
||||
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ), false );
|
||||
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3468,9 +3470,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ( path instanceof SqmFrom<?, ?> ) {
|
||||
else {
|
||||
if ( path instanceof SqmFrom<?, ?> ) {
|
||||
registerTreatUsage( (SqmFrom<?, ?>) path, tableGroup );
|
||||
}
|
||||
if ( path instanceof SqmSimplePath<?> && CollectionPart.Nature.fromName( path.getNavigablePath().getLocalName() ) == null ) {
|
||||
// If a table group for a selection already exists, we must make sure that the join type is INNER
|
||||
fromClauseIndex.findTableGroup( path.getNavigablePath().getParent() )
|
||||
.findTableGroupJoin( tableGroup )
|
||||
.setJoinType( SqlAstJoinType.INNER );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TableGroup createTableGroup(TableGroup parentTableGroup, SqmPath<?> joinedPath) {
|
||||
|
@ -3507,8 +3517,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
else {
|
||||
// Check if we can reuse a table group join of the parent
|
||||
final TableGroup compatibleTableGroup = findCompatibleJoinedGroup(
|
||||
actualParentTableGroup,
|
||||
final TableGroup compatibleTableGroup = actualParentTableGroup.findCompatibleJoinedGroup(
|
||||
joinProducer,
|
||||
SqlAstJoinType.INNER
|
||||
);
|
||||
|
@ -3898,7 +3907,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
navigablePath,
|
||||
tableGroupToUse == null ? tableGroup : tableGroupToUse,
|
||||
expandToAllColumns ? null : resultModelPart,
|
||||
true,
|
||||
interpretationModelPart,
|
||||
treatedMapping,
|
||||
this
|
||||
|
@ -3908,7 +3916,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final EmbeddableValuedModelPart mapping = (EmbeddableValuedModelPart) actualModelPart;
|
||||
result = new EmbeddableValuedPathInterpretation<>(
|
||||
mapping.toSqlExpression(
|
||||
tableGroup,
|
||||
getFromClauseAccess().findTableGroup( path.getLhs().getNavigablePath() ),
|
||||
currentClauseStack.getCurrent(),
|
||||
this,
|
||||
getSqlAstCreationState()
|
||||
|
@ -3923,6 +3931,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final BasicValuedModelPart mapping = (BasicValuedModelPart) actualModelPart;
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath.append( actualModelPart.getPartName() ),
|
||||
mapping,
|
||||
mapping.getContainingTableExpression()
|
||||
);
|
||||
|
||||
|
@ -4439,6 +4448,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
new ColumnReference(
|
||||
tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
(ValuedModelPart) modelPart,
|
||||
selectionMapping.getContainingTableExpression()
|
||||
),
|
||||
selectionMapping
|
||||
|
@ -4564,6 +4574,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final ColumnReference columnReference = new ColumnReference(
|
||||
tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
(ValuedModelPart) modelPart,
|
||||
selectionMapping.getContainingTableExpression()
|
||||
),
|
||||
selectionMapping
|
||||
|
@ -7139,11 +7150,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
@Override
|
||||
public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
|
||||
final EntityIdentifierMapping identifierMapping = fetchParent.getEntityValuedModelPart()
|
||||
.getEntityMappingType()
|
||||
final EntityIdentifierMapping identifierMapping = fetchParent.getReferencedMappingContainer()
|
||||
.getIdentifierMapping();
|
||||
final Fetchable fetchableIdentifierMapping = (Fetchable) identifierMapping;
|
||||
return createFetch( fetchParent, fetchableIdentifierMapping, false );
|
||||
return createFetch( fetchParent, (Fetchable) identifierMapping, false );
|
||||
}
|
||||
|
||||
private Fetch createFetch(FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) {
|
||||
|
|
|
@ -108,6 +108,7 @@ public class BasicValuedPathInterpretation<T> extends AbstractSqmPathInterpretat
|
|||
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
sqmPath.getNavigablePath(),
|
||||
mapping,
|
||||
mapping.getContainingTableExpression()
|
||||
);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.query.derived.AnonymousTupleEntityValuedModelPart;
|
||||
|
@ -44,8 +45,8 @@ import org.hibernate.sql.ast.tree.update.Assignable;
|
|||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
|
||||
public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpretation<T> implements SqlTupleContainer,
|
||||
Assignable {
|
||||
public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpretation<T>
|
||||
implements SqlTupleContainer, Assignable {
|
||||
|
||||
public static <T> EntityValuedPathInterpretation<T> from(
|
||||
SqmEntityValuedSimplePath<T> sqmPath,
|
||||
|
@ -99,7 +100,6 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
sqmPath.getNavigablePath(),
|
||||
tableGroup,
|
||||
pathMapping.getEntityMappingType().getIdentifierMapping(),
|
||||
false,
|
||||
pathMapping,
|
||||
pathMapping,
|
||||
sqlAstCreationState
|
||||
|
@ -149,7 +149,6 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
EntityValuedModelPart mapping,
|
||||
MappingModelExpressible<?> inferredMapping,
|
||||
SqmToSqlAstConverter sqlAstCreationState) {
|
||||
final boolean allowFkOptimization;
|
||||
final ModelPart resultModelPart;
|
||||
final TableGroup resultTableGroup;
|
||||
// For association mappings where the FK optimization i.e. use of the parent table group is allowed,
|
||||
|
@ -220,7 +219,6 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
}
|
||||
resultTableGroup = tableGroup;
|
||||
}
|
||||
allowFkOptimization = true;
|
||||
}
|
||||
else if ( inferredMapping == null && hasNotFound( mapping ) ) {
|
||||
// This is necessary to allow expression like `where root.notFoundAssociation is null`
|
||||
|
@ -229,31 +227,26 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
resultModelPart = keyTargetMatchPart;
|
||||
resultTableGroup = sqlAstCreationState.getFromClauseAccess()
|
||||
.findTableGroup( tableGroup.getNavigablePath().getParent() );
|
||||
allowFkOptimization = false;
|
||||
}
|
||||
else {
|
||||
// If the mapping is an inverse association, use the PK and disallow FK optimizations
|
||||
resultModelPart = ( (EntityAssociationMapping) mapping ).getAssociatedEntityMappingType().getIdentifierMapping();
|
||||
resultTableGroup = tableGroup;
|
||||
allowFkOptimization = false;
|
||||
}
|
||||
}
|
||||
else if ( mapping instanceof AnonymousTupleEntityValuedModelPart ) {
|
||||
resultModelPart = ( (AnonymousTupleEntityValuedModelPart) mapping ).getForeignKeyPart();
|
||||
resultTableGroup = tableGroup;
|
||||
allowFkOptimization = true;
|
||||
}
|
||||
else {
|
||||
// If the mapping is not an association, use the PK and disallow FK optimizations
|
||||
resultModelPart = mapping.getEntityMappingType().getIdentifierMapping();
|
||||
resultTableGroup = tableGroup;
|
||||
allowFkOptimization = false;
|
||||
}
|
||||
return from(
|
||||
navigablePath,
|
||||
resultTableGroup,
|
||||
resultModelPart,
|
||||
allowFkOptimization,
|
||||
mapping,
|
||||
mapping,
|
||||
sqlAstCreationState
|
||||
|
@ -288,7 +281,6 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
ModelPart resultModelPart,
|
||||
boolean allowFkOptimization,
|
||||
EntityValuedModelPart mapping,
|
||||
EntityValuedModelPart treatedMapping,
|
||||
SqmToSqlAstConverter sqlAstCreationState) {
|
||||
|
@ -309,8 +301,7 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
final SelectableConsumer selectableConsumer = (selectionIndex, selectableMapping) -> {
|
||||
final TableReference tableReference = parentTableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
selectableMapping.getContainingTableExpression(),
|
||||
false
|
||||
selectableMapping.getContainingTableExpression()
|
||||
);
|
||||
expressions.add(
|
||||
sqlExprResolver.resolveSqlExpression( tableReference, selectableMapping )
|
||||
|
@ -333,8 +324,8 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
final BasicValuedModelPart basicValuedModelPart = (BasicValuedModelPart) resultModelPart;
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
basicValuedModelPart.getContainingTableExpression(),
|
||||
allowFkOptimization
|
||||
basicValuedModelPart,
|
||||
basicValuedModelPart.getContainingTableExpression()
|
||||
);
|
||||
sqlExpression = sqlExprResolver.resolveSqlExpression( tableReference, basicValuedModelPart );
|
||||
}
|
||||
|
@ -344,8 +335,8 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
(selectionIndex, selectableMapping) -> {
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
navigablePath,
|
||||
selectableMapping.getContainingTableExpression(),
|
||||
allowFkOptimization
|
||||
(ValuedModelPart) resultModelPart,
|
||||
selectableMapping.getContainingTableExpression()
|
||||
);
|
||||
expressions.add( sqlExprResolver.resolveSqlExpression( tableReference, selectableMapping ) );
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
|
|||
if ( dotIdentifierSequence == null ) {
|
||||
return true;
|
||||
}
|
||||
if ( !getLocalName().equals( dotIdentifierSequence.getLocalName() ) ) {
|
||||
if ( !localNamesMatch( dotIdentifierSequence ) ) {
|
||||
return false;
|
||||
}
|
||||
return getParent() != null && getParent().isSuffix( dotIdentifierSequence.getParent() );
|
||||
|
|
|
@ -67,10 +67,9 @@ public class CteTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( compatibleTableExpressions.contains( tableExpression ) ) {
|
||||
return getPrimaryTableReference();
|
||||
|
@ -78,7 +77,7 @@ public class CteTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
@ -86,7 +85,7 @@ public class CteTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.sql.ast.tree.from;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -25,53 +24,14 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// TableReference handling
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
assert tableExpression != null;
|
||||
|
||||
final TableReference tableReference = getTableReferenceInternal(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
true
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine TableReference (`%s`) for `%s`",
|
||||
tableExpression,
|
||||
navigablePath
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference primaryTableReference = getPrimaryTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( primaryTableReference != null) {
|
||||
|
@ -82,7 +42,6 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
final TableReference tableReference = tableJoin.getJoinedTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null) {
|
||||
|
|
|
@ -79,15 +79,13 @@ public class CollectionTableGroup extends StandardTableGroup implements PluralTa
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = super.getTableReferenceInternal(
|
||||
final TableReference tableReference = super.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
|
@ -97,7 +95,6 @@ public class CollectionTableGroup extends StandardTableGroup implements PluralTa
|
|||
final TableReference indexTableReference = indexTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( indexTableReference != null ) {
|
||||
|
@ -108,7 +105,6 @@ public class CollectionTableGroup extends StandardTableGroup implements PluralTa
|
|||
final TableReference elementTableReference = elementTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( elementTableReference != null ) {
|
||||
|
|
|
@ -6,41 +6,89 @@
|
|||
*/
|
||||
package org.hibernate.sql.ast.tree.from;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ColumnReferenceQualifier {
|
||||
default TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return resolveTableReference( navigablePath, tableExpression, true );
|
||||
}
|
||||
|
||||
default TableReference resolveTableReference(String tableExpression) {
|
||||
return resolveTableReference( null, tableExpression, true );
|
||||
return resolveTableReference( null, tableExpression );
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #getTableReference(NavigablePath, String, boolean, boolean)}, but will throw an exception if no
|
||||
* Like {@link #getTableReference(NavigablePath, String, boolean)}, but will throw an exception if no
|
||||
* table reference can be found, even after resolving possible table reference joins.
|
||||
*
|
||||
* @param navigablePath The path for which to look up the table reference, may be null
|
||||
* @param tableExpression The table expression for which to look up the table reference
|
||||
* @param allowFkOptimization Whether a foreign key optimization is allowed i.e. use the FK column on the key-side
|
||||
*
|
||||
* @throws UnknownTableReferenceException to indicate that the given tableExpression could not be resolved
|
||||
*/
|
||||
TableReference resolveTableReference(
|
||||
default TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization);
|
||||
String tableExpression) {
|
||||
assert tableExpression != null;
|
||||
|
||||
final TableReference tableReference = getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
true
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine TableReference (`%s`) for `%s`",
|
||||
tableExpression,
|
||||
navigablePath
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
default TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression) {
|
||||
assert modelPart != null;
|
||||
|
||||
final TableReference tableReference = getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
true
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine TableReference (`%s`) for `%s`",
|
||||
tableExpression,
|
||||
navigablePath
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
default TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return getTableReference( navigablePath, tableExpression, true, false );
|
||||
return getTableReference( navigablePath, tableExpression, false );
|
||||
}
|
||||
|
||||
default TableReference getTableReference(String tableExpression) {
|
||||
return getTableReference( null, tableExpression, true, false );
|
||||
return getTableReference( null, tableExpression, false );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,12 +96,17 @@ public interface ColumnReferenceQualifier {
|
|||
*
|
||||
* @param navigablePath The path for which to look up the table reference, may be null
|
||||
* @param tableExpression The table expression for which to look up the table reference
|
||||
* @param allowFkOptimization Whether a foreign key optimization is allowed i.e. use the FK column on the key-side
|
||||
* @param resolve Whether to potentially create table reference joins for this table group
|
||||
*/
|
||||
TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve);
|
||||
default TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean resolve) {
|
||||
return getTableReference( navigablePath, tableExpression, resolve );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
@ -60,15 +61,53 @@ public class CorrelatedPluralTableGroup extends CorrelatedTableGroup implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = super.getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
if ( indexTableGroup != null && ( navigablePath == null || indexTableGroup.getNavigablePath().isParent( navigablePath ) ) ) {
|
||||
final TableReference indexTableReference = indexTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( indexTableReference != null ) {
|
||||
return indexTableReference;
|
||||
}
|
||||
}
|
||||
if ( elementTableGroup != null && ( navigablePath == null || elementTableGroup.getNavigablePath().isParent( navigablePath ) ) ) {
|
||||
final TableReference elementTableReference = elementTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( elementTableReference != null ) {
|
||||
return elementTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = super.getTableReferenceInternal(
|
||||
final TableReference tableReference = super.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
|
@ -78,7 +117,6 @@ public class CorrelatedPluralTableGroup extends CorrelatedTableGroup implements
|
|||
final TableReference indexTableReference = indexTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( indexTableReference != null ) {
|
||||
|
@ -89,7 +127,6 @@ public class CorrelatedPluralTableGroup extends CorrelatedTableGroup implements
|
|||
final TableReference elementTableReference = elementTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( elementTableReference != null ) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
|
@ -71,15 +72,15 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = correlatedTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
|
@ -88,7 +89,7 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, modelPart, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
@ -96,7 +97,39 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, modelPart, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = correlatedTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
|
@ -58,40 +59,20 @@ public abstract class DelegatingTableGroup implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return resolveTableReference( navigablePath, tableExpression, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(String tableExpression) {
|
||||
return resolveTableReference( null, tableExpression, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return getTableGroup().resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return getTableReference( navigablePath, tableExpression, true, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(String tableExpression) {
|
||||
return getTableReference( null, tableExpression, true, false );
|
||||
boolean resolve) {
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression, resolve );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
return getTableGroup().getTableReference( navigablePath, modelPart, tableExpression, resolve );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.sql.ast.tree.from;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
||||
/**
|
||||
|
@ -45,8 +46,18 @@ public abstract class DerivedTableReference extends AbstractTableReference {
|
|||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
String tableExpression) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
"TableReferences cannot be resolved relative to DerivedTableReferences - `" + tableExpression + "` : " + navigablePath
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
"TableReferences cannot be resolved relative to DerivedTableReferences - `" + tableExpression + "` : " + navigablePath
|
||||
|
@ -57,7 +68,6 @@ public abstract class DerivedTableReference extends AbstractTableReference {
|
|||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -55,10 +55,9 @@ public class FunctionTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( tableExpression == null ) {
|
||||
return getPrimaryTableReference();
|
||||
|
@ -66,7 +65,7 @@ public class FunctionTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
@ -74,7 +73,7 @@ public class FunctionTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
|
|
@ -9,13 +9,12 @@ package org.hibernate.sql.ast.tree.from;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
|
||||
|
@ -37,7 +36,7 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
|||
private final SqlAliasBase sqlAliasBase;
|
||||
private final Supplier<TableGroup> tableGroupSupplier;
|
||||
private final TableGroup parentTableGroup;
|
||||
private final BiPredicate<NavigablePath, String> navigablePathChecker;
|
||||
private final ParentTableGroupUseChecker parentTableGroupUseChecker;
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||
private Consumer<TableGroup> tableGroupConsumer;
|
||||
|
@ -48,7 +47,7 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
|||
NavigablePath navigablePath,
|
||||
boolean fetched,
|
||||
Supplier<TableGroup> tableGroupSupplier,
|
||||
BiPredicate<NavigablePath, String> navigablePathChecker,
|
||||
ParentTableGroupUseChecker parentTableGroupUseChecker,
|
||||
TableGroupProducer tableGroupProducer,
|
||||
String sourceAlias,
|
||||
SqlAliasBase sqlAliasBase,
|
||||
|
@ -61,7 +60,7 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
|||
this.sourceAlias = sourceAlias;
|
||||
this.sqlAliasBase = sqlAliasBase;
|
||||
this.tableGroupSupplier = tableGroupSupplier;
|
||||
this.navigablePathChecker = navigablePathChecker;
|
||||
this.parentTableGroupUseChecker = parentTableGroupUseChecker;
|
||||
this.parentTableGroup = parentTableGroup;
|
||||
}
|
||||
|
||||
|
@ -237,60 +236,34 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
assert tableExpression != null;
|
||||
|
||||
final TableReference tableReference = getTableReferenceInternal(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
true
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine TableReference (`%s`) for `%s`",
|
||||
tableExpression,
|
||||
navigablePath
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
boolean resolve) {
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression, resolve );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
}
|
||||
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( allowFkOptimization && ( navigablePath == null || navigablePathChecker.test( navigablePath, tableExpression ) ) ) {
|
||||
if ( parentTableGroupUseChecker.canUseParentTableGroup( producer, navigablePath, modelPart ) ) {
|
||||
final TableReference reference = parentTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
(ValuedModelPart) producer,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( reference != null ) {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
return getTableGroup().getTableReference( navigablePath, modelPart, tableExpression, resolve );
|
||||
}
|
||||
|
||||
public static interface ParentTableGroupUseChecker {
|
||||
boolean canUseParentTableGroup(TableGroupProducer producer, NavigablePath navigablePath, ValuedModelPart valuedModelPart);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ package org.hibernate.sql.ast.tree.from;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
||||
/**
|
||||
|
@ -21,25 +21,25 @@ import org.hibernate.spi.NavigablePath;
|
|||
public class MappedByTableGroup extends DelegatingTableGroup implements VirtualTableGroup {
|
||||
|
||||
private final NavigablePath navigablePath;
|
||||
private final ModelPartContainer modelPart;
|
||||
private final TableGroupProducer producer;
|
||||
private final TableGroup underlyingTableGroup;
|
||||
private final boolean fetched;
|
||||
private final TableGroup parentTableGroup;
|
||||
private final BiPredicate<NavigablePath, String> navigablePathChecker;
|
||||
private final LazyTableGroup.ParentTableGroupUseChecker parentTableGroupUseChecker;
|
||||
|
||||
public MappedByTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
ModelPartContainer modelPart,
|
||||
TableGroupProducer producer,
|
||||
TableGroup underlyingTableGroup,
|
||||
boolean fetched,
|
||||
TableGroup parentTableGroup,
|
||||
BiPredicate<NavigablePath, String> navigablePathChecker) {
|
||||
LazyTableGroup.ParentTableGroupUseChecker parentTableGroupUseChecker) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.modelPart = modelPart;
|
||||
this.producer = producer;
|
||||
this.underlyingTableGroup = underlyingTableGroup;
|
||||
this.fetched = fetched;
|
||||
this.parentTableGroup = parentTableGroup;
|
||||
this.navigablePathChecker = navigablePathChecker;
|
||||
this.parentTableGroupUseChecker = parentTableGroupUseChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,7 +75,7 @@ public class MappedByTableGroup extends DelegatingTableGroup implements VirtualT
|
|||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return modelPart;
|
||||
return producer;
|
||||
}
|
||||
|
||||
// Don't provide access to table group joins as this is table group is just a "named reference"
|
||||
|
@ -119,12 +119,39 @@ public class MappedByTableGroup extends DelegatingTableGroup implements VirtualT
|
|||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
String tableExpression) {
|
||||
final TableReference tableReference = getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
true
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
throw new UnknownTableReferenceException(
|
||||
tableExpression,
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine TableReference (`%s`) for `%s`",
|
||||
tableExpression,
|
||||
navigablePath
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression) {
|
||||
assert modelPart != null;
|
||||
|
||||
final TableReference tableReference = getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
true
|
||||
);
|
||||
|
||||
|
@ -147,25 +174,31 @@ public class MappedByTableGroup extends DelegatingTableGroup implements VirtualT
|
|||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( allowFkOptimization && ( navigablePath == null || navigablePathChecker.test( navigablePath, tableExpression ) ) ) {
|
||||
final TableReference reference = parentTableGroup.getTableReference(
|
||||
return getTableGroup().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean resolve) {
|
||||
if ( parentTableGroupUseChecker.canUseParentTableGroup( producer, navigablePath, modelPart ) ) {
|
||||
final TableReference reference = parentTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
(ValuedModelPart) producer,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( reference != null ) {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
|
||||
return underlyingTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
return getTableGroup().getTableReference( navigablePath, modelPart, tableExpression, resolve );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,21 +63,12 @@ public class MutatingTableReferenceGroupWrapper implements TableGroup {
|
|||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
return mutatingTableReference.getTableExpression().equals( tableExpression )
|
||||
? mutatingTableReference
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return getTableReference( navigablePath, tableExpression, allowFkOptimization, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
nameCollector.accept( mutatingTableReference.getTableExpression() );
|
||||
|
|
|
@ -83,8 +83,7 @@ public class NamedTableReference extends AbstractTableReference {
|
|||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
String tableExpression) {
|
||||
if ( tableExpression.equals( getTableExpression() ) ) {
|
||||
return this;
|
||||
}
|
||||
|
@ -104,12 +103,8 @@ public class NamedTableReference extends AbstractTableReference {
|
|||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( this.tableExpression.equals( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
return this.tableExpression.equals( tableExpression ) ? this : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -165,15 +165,13 @@ public class OneToManyTableGroup extends AbstractColumnReferenceQualifier implem
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = elementTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null || indexTableGroup == null
|
||||
|
@ -184,7 +182,6 @@ public class OneToManyTableGroup extends AbstractColumnReferenceQualifier implem
|
|||
return indexTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,13 +8,11 @@ package org.hibernate.sql.ast.tree.from;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
|
||||
/**
|
||||
|
@ -83,10 +81,9 @@ public class QueryPartTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( compatibleTableExpressions.contains( tableExpression ) ) {
|
||||
return getPrimaryTableReference();
|
||||
|
@ -94,7 +91,7 @@ public class QueryPartTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
@ -102,7 +99,7 @@ public class QueryPartTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
|
|
@ -131,15 +131,13 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = primaryTableReference.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
|
@ -152,7 +150,7 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
final TableReferenceJoin join = tableJoins.get( i );
|
||||
assert join != null;
|
||||
final TableReference resolveTableReference = join.getJoinedTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( resolveTableReference != null ) {
|
||||
return resolveTableReference;
|
||||
}
|
||||
|
@ -164,13 +162,13 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, resolve ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, resolve ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,11 @@ package org.hibernate.sql.ast.tree.from;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.metamodel.mapping.OwnedValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
||||
/**
|
||||
|
@ -105,21 +109,68 @@ public class StandardVirtualTableGroup extends AbstractTableGroup implements Vir
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
final TableReference tableReference = underlyingTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
return super.getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
|
||||
for ( TableReferenceJoin tableJoin : getTableReferenceJoins() ) {
|
||||
final TableReference joinedTableReference = tableJoin.getJoinedTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( joinedTableReference != null) {
|
||||
return joinedTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean resolve) {
|
||||
final ValuedModelPart parentModelPart;
|
||||
final MappingType declaringType;
|
||||
if ( modelPart instanceof OwnedValuedModelPart
|
||||
&& ( declaringType = ( (OwnedValuedModelPart) modelPart ).getDeclaringType() ) instanceof EmbeddableMappingType ) {
|
||||
parentModelPart = ( (EmbeddableMappingType) declaringType ).getEmbeddedValueMapping();
|
||||
}
|
||||
else {
|
||||
parentModelPart = modelPart;
|
||||
}
|
||||
final TableReference tableReference = underlyingTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
parentModelPart,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
for ( TableReferenceJoin tableJoin : getTableReferenceJoins() ) {
|
||||
final TableReference joinedTableReference = tableJoin.getJoinedTableReference().getTableReference(
|
||||
navigablePath,
|
||||
modelPart,
|
||||
tableExpression,
|
||||
resolve
|
||||
);
|
||||
if ( joinedTableReference != null) {
|
||||
return joinedTableReference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.metamodel.mapping.ModelPartContainer;
|
|||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -159,4 +160,37 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat
|
|||
default boolean isInitialized() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default TableGroup findCompatibleJoinedGroup(
|
||||
TableGroupJoinProducer joinProducer,
|
||||
SqlAstJoinType requestedJoinType) {
|
||||
// We don't look into nested table group joins as that wouldn't be "compatible"
|
||||
for ( TableGroupJoin join : 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;
|
||||
}
|
||||
|
||||
default TableGroupJoin findTableGroupJoin(TableGroup tableGroup) {
|
||||
for ( TableGroupJoin join : getTableGroupJoins() ) {
|
||||
if ( join.getJoinedGroup() == tableGroup ) {
|
||||
return join;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,13 +65,11 @@ public interface TableReference extends SqlAstNode, ColumnReferenceQualifier {
|
|||
@Override
|
||||
TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization);
|
||||
String tableExpression);
|
||||
|
||||
@Override
|
||||
TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve);
|
||||
}
|
||||
|
|
|
@ -44,14 +44,13 @@ public class UnionTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( tableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve ) != null ) {
|
||||
if ( tableReference.getTableReference( navigablePath, tableExpression, resolve ) != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
return super.getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
return super.getTableReference( navigablePath, tableExpression, resolve );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,7 @@ public class UnionTableReference extends NamedTableReference {
|
|||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
String tableExpression) {
|
||||
if ( hasTableExpression( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
|
@ -60,7 +59,6 @@ public class UnionTableReference extends NamedTableReference {
|
|||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( hasTableExpression( tableExpression ) ) {
|
||||
return this;
|
||||
|
|
|
@ -43,10 +43,9 @@ public class ValuesTableGroup extends AbstractTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization,
|
||||
boolean resolve) {
|
||||
if ( ( (TableGroupProducer) getModelPart() ).containsTableReference( tableExpression ) ) {
|
||||
return getPrimaryTableReference();
|
||||
|
@ -54,7 +53,7 @@ public class ValuesTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
@ -62,7 +61,7 @@ public class ValuesTableGroup extends AbstractTableGroup {
|
|||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization, resolve );
|
||||
.getTableReference( navigablePath, tableExpression, resolve );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.Locale;
|
|||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ValuedModelPart;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
|
@ -61,7 +62,9 @@ public class MutatingTableReference implements TableReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression, boolean allowFkOptimization) {
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression) {
|
||||
if ( getTableName().equals( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
|
@ -77,8 +80,36 @@ public class MutatingTableReference implements TableReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression, boolean allowFkOptimization, boolean resolve) {
|
||||
return resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression) {
|
||||
if ( getTableName().equals( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Table-expression (%s) did not match mutating table name - %s",
|
||||
tableExpression,
|
||||
getTableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression, boolean resolve) {
|
||||
return getTableName().equals( tableExpression ) ? this : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
ValuedModelPart modelPart,
|
||||
String tableExpression,
|
||||
boolean resolve) {
|
||||
return getTableName().equals( tableExpression ) ? this : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,9 +24,9 @@ public interface DatabaseSnapshotContributor extends Fetchable {
|
|||
*/
|
||||
default <T> DomainResult<T> createSnapshotDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
TableGroup parentTableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return createDomainResult( navigablePath, tableGroup, null, creationState );
|
||||
return createDomainResult( navigablePath, parentTableGroup, null, creationState );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,12 @@ import java.util.List;
|
|||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.spi.EntityIdentifierNavigablePath;
|
||||
|
@ -88,8 +91,7 @@ public interface DomainResultCreationState {
|
|||
ModelPart resolveModelPart(NavigablePath navigablePath);
|
||||
|
||||
default Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
|
||||
final EntityIdentifierMapping identifierMapping = fetchParent.getEntityValuedModelPart()
|
||||
.getEntityMappingType()
|
||||
final EntityIdentifierMapping identifierMapping = fetchParent.getReferencedMappingContainer()
|
||||
.getIdentifierMapping();
|
||||
return fetchParent.generateFetchableFetch(
|
||||
(Fetchable) identifierMapping,
|
||||
|
|
|
@ -37,7 +37,7 @@ public interface FetchParent extends DomainResultGraphNode {
|
|||
|
||||
default NavigablePath resolveNavigablePath(Fetchable fetchable) {
|
||||
final String fetchableName = fetchable.getFetchableName();
|
||||
if ( NavigablePath.IDENTIFIER_MAPPER_PROPERTY.equals( fetchableName ) || fetchable instanceof EntityIdentifierMapping ) {
|
||||
if ( fetchable instanceof EntityIdentifierMapping ) {
|
||||
return new EntityIdentifierNavigablePath( getNavigablePath(), fetchableName );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -92,7 +92,7 @@ public interface Fetchable extends ModelPart {
|
|||
|
||||
default boolean isSelectable() {
|
||||
final AttributeMapping attributeMapping = asAttributeMapping();
|
||||
if ( attributeMapping != null ) {
|
||||
if ( attributeMapping != null && attributeMapping.getAttributeMetadata() != null ) {
|
||||
return attributeMapping.getAttributeMetadata().isSelectable();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
|
@ -53,10 +54,11 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
|
|||
this.loadingAttribute = loadingAttribute;
|
||||
this.resultVariable = resultVariable;
|
||||
this.tableGroup = tableGroup;
|
||||
|
||||
fkResult = loadingAttribute.getKeyDescriptor().createKeyDomainResult(
|
||||
// The collection is always the target side
|
||||
this.fkResult = loadingAttribute.getKeyDescriptor().createKeyDomainResult(
|
||||
loadingPath,
|
||||
tableGroup,
|
||||
ForeignKeyDescriptor.Nature.TARGET,
|
||||
this,
|
||||
creationState
|
||||
);
|
||||
|
|
|
@ -99,9 +99,11 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
|
|||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
// The collection is always the target side
|
||||
collectionValueKeyResult = keyDescriptor.createKeyDomainResult(
|
||||
fetchedPath,
|
||||
collectionTableGroup,
|
||||
ForeignKeyDescriptor.Nature.TARGET,
|
||||
fetchParent,
|
||||
creationState
|
||||
);
|
||||
|
|
|
@ -234,10 +234,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
|||
// 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.getLocalName() )
|
||||
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() ) ) {
|
||||
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart && !isPartOfKey ) {
|
||||
fetchParentAccess.resolveInstance( processingState );
|
||||
compositeInstance = fetchParentAccess.getInitializedInstance();
|
||||
EntityInitializer entityInitializer = fetchParentAccess.asEntityInitializer();
|
||||
|
|
|
@ -6,15 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.sql.results.graph.entity;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.spi.EntityIdentifierNavigablePath;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.results.graph.AbstractFetchParent;
|
||||
|
@ -25,47 +20,37 @@ import org.hibernate.sql.results.graph.FetchParent;
|
|||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
import static org.hibernate.query.results.ResultsHelper.attributeName;
|
||||
|
||||
/**
|
||||
* AbstractFetchParent sub-class for entity-valued graph nodes
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent implements EntityResultGraphNode {
|
||||
private final EntityValuedModelPart referencedModelPart;
|
||||
private Fetch identifierFetch;
|
||||
private BasicFetch<?> discriminatorFetch;
|
||||
private DomainResult<Object> rowIdResult;
|
||||
|
||||
public AbstractEntityResultGraphNode(EntityValuedModelPart referencedModelPart, NavigablePath navigablePath) {
|
||||
super( referencedModelPart.getEntityMappingType(), navigablePath );
|
||||
this.referencedModelPart = referencedModelPart;
|
||||
super( referencedModelPart, navigablePath );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterInitialize(FetchParent fetchParent, DomainResultCreationState creationState) {
|
||||
final EntityMappingType entityDescriptor = referencedModelPart.getEntityMappingType();
|
||||
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
|
||||
final NavigablePath navigablePath = getNavigablePath();
|
||||
final TableGroup entityTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess()
|
||||
.getTableGroup( navigablePath );
|
||||
final EntityResultGraphNode entityResultGraphNode = (EntityResultGraphNode) fetchParent;
|
||||
if ( navigablePath.getParent() == null && !creationState.forceIdentifierSelection() ) {
|
||||
identifierFetch = null;
|
||||
visitIdentifierMapping(
|
||||
new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) ),
|
||||
creationState,
|
||||
identifierMapping,
|
||||
entityTableGroup
|
||||
);
|
||||
creationState.visitIdentifierFetch( entityResultGraphNode );
|
||||
}
|
||||
else {
|
||||
identifierFetch = creationState.visitIdentifierFetch( this );
|
||||
identifierFetch = creationState.visitIdentifierFetch( entityResultGraphNode );
|
||||
}
|
||||
|
||||
discriminatorFetch = creationState.visitDiscriminatorFetch( this );
|
||||
discriminatorFetch = creationState.visitDiscriminatorFetch( entityResultGraphNode );
|
||||
|
||||
final EntityRowIdMapping rowIdMapping = entityDescriptor.getRowIdMapping();
|
||||
final EntityRowIdMapping rowIdMapping = getEntityValuedModelPart().getEntityMappingType().getRowIdMapping();
|
||||
if ( rowIdMapping == null ) {
|
||||
rowIdResult = null;
|
||||
}
|
||||
|
@ -80,45 +65,6 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
|
|||
super.afterInitialize( fetchParent, creationState );
|
||||
}
|
||||
|
||||
private void visitIdentifierMapping(
|
||||
EntityIdentifierNavigablePath navigablePath,
|
||||
DomainResultCreationState creationState,
|
||||
EntityIdentifierMapping identifierMapping,
|
||||
TableGroup entityTableGroup) {
|
||||
final MappingType mappingType = identifierMapping.getPartMappingType();
|
||||
if ( mappingType instanceof ManagedMappingType ) {
|
||||
( (ManagedMappingType) mappingType ).forEachAttributeMapping(
|
||||
attributeMapping -> {
|
||||
if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||
( (ToOneAttributeMapping) attributeMapping ).getForeignKeyDescriptor()
|
||||
.createKeyDomainResult(
|
||||
navigablePath.getParent(),
|
||||
entityTableGroup,
|
||||
this,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
attributeMapping.createDomainResult(
|
||||
navigablePath,
|
||||
entityTableGroup,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
identifierMapping.createDomainResult(
|
||||
navigablePath,
|
||||
entityTableGroup,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType getReferencedMappingContainer() {
|
||||
return getEntityValuedModelPart().getEntityMappingType();
|
||||
|
@ -126,7 +72,7 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
|
|||
|
||||
@Override
|
||||
public EntityValuedModelPart getEntityValuedModelPart() {
|
||||
return referencedModelPart;
|
||||
return (EntityValuedModelPart) getFetchContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,4 +91,5 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
|
|||
public DomainResult<Object> getRowIdResult() {
|
||||
return rowIdResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,20 +22,18 @@ import org.hibernate.sql.results.graph.entity.internal.EntityAssembler;
|
|||
*/
|
||||
public abstract class AbstractNonLazyEntityFetch extends AbstractFetchParent implements EntityFetch {
|
||||
private final FetchParent fetchParent;
|
||||
private final EntityValuedFetchable referencedModelPart;
|
||||
|
||||
public AbstractNonLazyEntityFetch(
|
||||
FetchParent fetchParent,
|
||||
EntityValuedFetchable fetchedPart,
|
||||
NavigablePath navigablePath) {
|
||||
super( fetchedPart.getEntityMappingType(), navigablePath );
|
||||
this.referencedModelPart = fetchedPart;
|
||||
super( fetchedPart, navigablePath );
|
||||
this.fetchParent = fetchParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityValuedFetchable getEntityValuedModelPart() {
|
||||
return referencedModelPart;
|
||||
return (EntityValuedFetchable) getFetchContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph.entity.internal;
|
|||
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
|
@ -33,13 +34,14 @@ public class EntityDelayedResultImpl implements DomainResult {
|
|||
public EntityDelayedResultImpl(
|
||||
NavigablePath navigablePath,
|
||||
EntityAssociationMapping entityValuedModelPart,
|
||||
TableGroup rootTableGroup,
|
||||
TableGroup targetTableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.entityValuedModelPart = entityValuedModelPart;
|
||||
this.identifierResult = entityValuedModelPart.getForeignKeyDescriptor().createKeyDomainResult(
|
||||
navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ),
|
||||
rootTableGroup,
|
||||
targetTableGroup,
|
||||
entityValuedModelPart.getSideNature(),
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
|
|
|
@ -44,7 +44,12 @@ public class NotFoundSnapshotResult implements DomainResult {
|
|||
// however, that would mean a 1-1 with a join-table which
|
||||
// is pretty odd mapping
|
||||
final ForeignKeyDescriptor fkDescriptor = toOneMapping.getForeignKeyDescriptor();
|
||||
this.keyResult = fkDescriptor.createKeyDomainResult( navigablePath, keyTableGroup, null, creationState );
|
||||
this.keyResult = fkDescriptor.createKeyDomainResult(
|
||||
navigablePath,
|
||||
targetTableGroup,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
this.targetResult = fkDescriptor.createTargetDomainResult(
|
||||
navigablePath,
|
||||
targetTableGroup,
|
||||
|
|
|
@ -20,6 +20,7 @@ public class CardField implements Serializable {
|
|||
|
||||
@EmbeddedId
|
||||
private PrimaryKey primaryKey;
|
||||
private String name;
|
||||
|
||||
CardField(Card card, Key key) {
|
||||
this.primaryKey = new PrimaryKey( card, key);
|
||||
|
|
|
@ -21,6 +21,7 @@ import jakarta.persistence.Table;
|
|||
public class Key implements Serializable {
|
||||
@Id
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
public Key(String id) {
|
||||
this.id = id;
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* 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.annotations.embedded;
|
||||
|
||||
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;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.EmbeddedId;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinColumns;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
EmbeddableWithManyToOneSelfReferenceTest.EntityTest.class,
|
||||
EmbeddableWithManyToOneSelfReferenceTest.IntIdEntity.class
|
||||
}
|
||||
)
|
||||
@SessionFactory(useCollectingStatementInspector = true)
|
||||
public class EmbeddableWithManyToOneSelfReferenceTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
IntIdEntity intIdEntity = new IntIdEntity( 1 );
|
||||
|
||||
EntityTest entity1 = new EntityTest( "1", intIdEntity );
|
||||
EmbeddableTest embeddable1 = new EmbeddableTest();
|
||||
embeddable1.setName( "E1" );
|
||||
|
||||
entity1.setEmbeddedAttribute( embeddable1 );
|
||||
|
||||
EntityTest entity2 = new EntityTest( "2", intIdEntity );
|
||||
|
||||
EmbeddableTest embeddable2 = new EmbeddableTest();
|
||||
embeddable2.setAssociation( entity1 );
|
||||
embeddable2.setName( "E2" );
|
||||
|
||||
entity2.setEmbeddedAttribute( embeddable2 );
|
||||
|
||||
session.persist( intIdEntity );
|
||||
session.persist( entity1 );
|
||||
session.persist( entity2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createMutationQuery( "delete from EntityTest e where e.embeddedAttribute.association is not null" ).executeUpdate();
|
||||
session.createMutationQuery( "delete from EntityTest e" ).executeUpdate();
|
||||
session.createMutationQuery( "delete from IntIdEntity e" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet(SessionFactoryScope scope) {
|
||||
SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||
statementInspector.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityTest entity1 = session.find( EntityTest.class, new EntityTestId( "1", session.getReference( IntIdEntity.class, 1 ) ) );
|
||||
assertNotNull( entity1.getEmbeddedAttribute() );
|
||||
assertNull( entity1.getEmbeddedAttribute().getAssociation() );
|
||||
assertEquals( "E1", entity1.getEmbeddedAttribute().getName() );
|
||||
|
||||
EntityTest entity2 = session.find( EntityTest.class, new EntityTestId( "2", session.getReference( IntIdEntity.class, 1 ) ) );
|
||||
assertNotNull( entity2.getEmbeddedAttribute() );
|
||||
assertNotNull( entity2.getEmbeddedAttribute().getAssociation() );
|
||||
assertEquals( entity1, entity2.getEmbeddedAttribute().getAssociation() );
|
||||
assertEquals( "E2", entity2.getEmbeddedAttribute().getName() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "EntityTest")
|
||||
public static class EntityTest {
|
||||
@EmbeddedId
|
||||
private EntityTestId id;
|
||||
|
||||
@Embedded
|
||||
private EmbeddableTest embeddedAttribute;
|
||||
|
||||
public EntityTest() {
|
||||
}
|
||||
|
||||
public EntityTest(String string, IntIdEntity intIdEntity) {
|
||||
this.id = new EntityTestId(string, intIdEntity);
|
||||
}
|
||||
|
||||
public EntityTestId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(EntityTestId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public EmbeddableTest getEmbeddedAttribute() {
|
||||
return embeddedAttribute;
|
||||
}
|
||||
|
||||
public void setEmbeddedAttribute(EmbeddableTest embeddedAttribute) {
|
||||
this.embeddedAttribute = embeddedAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class EntityTestId {
|
||||
@Column(name = "string_key", length = 10)
|
||||
private String stringKey;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "intIdEntity_id")
|
||||
private IntIdEntity intIdEntity;
|
||||
|
||||
public EntityTestId() {
|
||||
}
|
||||
|
||||
public EntityTestId(String stringKey, IntIdEntity intIdEntity) {
|
||||
this.stringKey = stringKey;
|
||||
this.intIdEntity = intIdEntity;
|
||||
}
|
||||
|
||||
public String getStringKey() {
|
||||
return stringKey;
|
||||
}
|
||||
|
||||
public void setStringKey(String stringField) {
|
||||
this.stringKey = stringField;
|
||||
}
|
||||
|
||||
public IntIdEntity getIntIdEntity() {
|
||||
return intIdEntity;
|
||||
}
|
||||
|
||||
public void setIntIdEntity(IntIdEntity entity) {
|
||||
this.intIdEntity = entity;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class EmbeddableTest {
|
||||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "assoc_string_key", referencedColumnName = "string_key"),
|
||||
@JoinColumn(name = "assoc_intIdEntity_id", referencedColumnName = "intIdEntity_id")
|
||||
})
|
||||
private EntityTest association;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String stringField) {
|
||||
this.name = stringField;
|
||||
}
|
||||
|
||||
public EntityTest getAssociation() {
|
||||
return association;
|
||||
}
|
||||
|
||||
public void setAssociation(EntityTest entity) {
|
||||
this.association = entity;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "IntIdEntity")
|
||||
public static class IntIdEntity {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
public IntIdEntity() {
|
||||
}
|
||||
|
||||
public IntIdEntity(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -108,7 +108,7 @@ public class LazyManyToOneEmbeddedIdWithToOneFKTest {
|
|||
assertTrue( Hibernate.isInitialized( system.getUser() ) );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
|
||||
}
|
||||
);
|
||||
|
@ -147,7 +147,7 @@ public class LazyManyToOneEmbeddedIdWithToOneFKTest {
|
|||
assertTrue( Hibernate.isInitialized( system.getUser() ) );
|
||||
|
||||
statementInspector.assertExecutedCount( 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
|
||||
}
|
||||
);
|
||||
|
|
|
@ -89,7 +89,7 @@ public class ManyToOneEmbeddedIdWithToOneFKTest {
|
|||
statementInspector.assertExecutedCount( 3 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 1 );
|
||||
|
||||
|
||||
assertTrue( Hibernate.isInitialized( system.getDataCenterUser() ) );
|
||||
|
@ -119,7 +119,7 @@ public class ManyToOneEmbeddedIdWithToOneFKTest {
|
|||
statementInspector.assertExecutedCount( 3 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 0 );
|
||||
statementInspector.assertNumberOfOccurrenceInQuery( 2, "join", 1 );
|
||||
assertThat( system, is( notNullValue() ) );
|
||||
DataCenterUser user = system.getDataCenterUser();
|
||||
assertThat( user, is( notNullValue() ) );
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* 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.embeddable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
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.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
EmbeddableQuerySelectTest.Organisation.class,
|
||||
EmbeddableQuerySelectTest.User.class,
|
||||
EmbeddableQuerySelectTest.OrganisationUser.class,
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@TestForIssue(jiraKey = "HHH-16366")
|
||||
public class EmbeddableQuerySelectTest {
|
||||
|
||||
private static final Integer ORGANISATION_ID = 1;
|
||||
private static final Integer USER_ID = 2;
|
||||
|
||||
@BeforeAll
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Organisation organisation = new Organisation( ORGANISATION_ID, "Red Hat" );
|
||||
session.persist( organisation );
|
||||
|
||||
User user = new User( USER_ID, AccountType.FOO );
|
||||
session.persist( user );
|
||||
|
||||
OrganisationUserEmbeddable embeddable = new OrganisationUserEmbeddable( organisation, user, "1" );
|
||||
|
||||
OrganisationUser organisationUser = new OrganisationUser( 3, embeddable );
|
||||
session.persist( organisationUser );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectUsingEmbeddableInWhereClause(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.embeddable.user u where o.embeddable.organisation.id = ?1 and u.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.embeddable.user u join fetch o.embeddable.organisation or where or.id = ?1 and u.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.embeddable.organisation or where or.id = ?1 and o.embeddable.user.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o where o.embeddable.organisation.id = ?1 and o.embeddable.user.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelect(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectJoiningPartOfEmbeddable(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.embeddable.user u ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "OrganisationUser")
|
||||
@Table(name = "ORGANISATION_USER")
|
||||
public static class OrganisationUser {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private OrganisationUserEmbeddable embeddable;
|
||||
|
||||
public OrganisationUser() {
|
||||
}
|
||||
|
||||
public OrganisationUser(Integer id, OrganisationUserEmbeddable organisationUserEmbeddable) {
|
||||
this.id = id;
|
||||
this.embeddable = organisationUserEmbeddable;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public OrganisationUserEmbeddable getEmbeddable() {
|
||||
return embeddable;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "User")
|
||||
@Table(name = "F_USER")
|
||||
public static class User {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "ACCOUNT_TYPE")
|
||||
private AccountType accountType;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(Integer id, AccountType accountType) {
|
||||
this.id = id;
|
||||
this.accountType = accountType;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public AccountType getAccountType() {
|
||||
return accountType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Organisation")
|
||||
@Table(name = "ORGANISATION")
|
||||
public static class Organisation {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Organisation() {
|
||||
}
|
||||
|
||||
public Organisation(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AccountType {
|
||||
FOO,
|
||||
BAR,
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class OrganisationUserEmbeddable {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "ORGANISATION_ID", nullable = false)
|
||||
private Organisation organisation;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "USER_ID", nullable = false)
|
||||
private User user;
|
||||
|
||||
private String code;
|
||||
|
||||
public OrganisationUserEmbeddable() {
|
||||
}
|
||||
|
||||
public OrganisationUserEmbeddable(Organisation organisation, User user, String code) {
|
||||
this.organisation = organisation;
|
||||
this.user = user;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.AttributeMappingsList;
|
|||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.hql.spi.SqmQueryImplementor;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
@ -70,10 +71,10 @@ import jakarta.persistence.criteria.CriteriaQuery;
|
|||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.testing.hamcrest.AssignableMatcher.assignableTo;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.hasSize;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.isEmpty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Nathan Xu
|
||||
|
@ -286,8 +287,11 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
|
|||
.next()
|
||||
.getJoinedGroup();
|
||||
assertThat( compositeTableGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getNestedTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = compositeTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( joinedGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
else {
|
||||
assertThat( tableGroup.getTableGroupJoins(), isEmpty() );
|
||||
|
@ -295,8 +299,11 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
|
|||
|
||||
final TableGroup compositeTableGroup = CollectionUtils.getOnlyElement( tableGroup.getNestedTableGroupJoins() ).getJoinedGroup();
|
||||
assertThat( compositeTableGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getNestedTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = compositeTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( joinedGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
} );
|
||||
|
||||
|
@ -311,7 +318,10 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
|
|||
assertThat( fromClause.getRoots(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup rootTableGroup = fromClause.getRoots().get( 0 );
|
||||
assertThat( rootTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( rootTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup tableGroup = rootTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( tableGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
|
||||
private void assertEntityValuedJoinedGroup(SelectStatement sqlAst, String expectedAttributeName, Class<?> expectedEntityJpaClass, Consumer<TableGroup> tableGroupConsumer) {
|
||||
|
@ -343,12 +353,18 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware {
|
|||
}
|
||||
|
||||
private void assertPersonHomeAddressJoinedGroup(TableGroup tableGroup) {
|
||||
assertThat( tableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
assertThat( tableGroup.getTableGroupJoins(), hasSize( 2 ) );
|
||||
|
||||
final TableGroup joinedGroup = tableGroup.getTableGroupJoins().iterator().next().getJoinedGroup();
|
||||
assertThat( joinedGroup.getModelPart().getPartName(), is( "homeAddress" ) );
|
||||
assertThat( joinedGroup.getModelPart(), instanceOf( EmbeddedAttributeMapping.class ) );
|
||||
assertThat( joinedGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
final TableGroup company = tableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( company.getModelPart().getPartName(), is( "company" ) );
|
||||
assertThat( company.getModelPart(), instanceOf( ToOneAttributeMapping.class ) );
|
||||
assertThat( company, instanceOf( LazyTableGroup.class ) );
|
||||
assertThat( company.isInitialized(), is( false ) );
|
||||
|
||||
final TableGroup homeAddress = tableGroup.getTableGroupJoins().get( 1 ).getJoinedGroup();
|
||||
assertThat( homeAddress.getModelPart().getPartName(), is( "homeAddress" ) );
|
||||
assertThat( homeAddress.getModelPart(), instanceOf( EmbeddedAttributeMapping.class ) );
|
||||
assertThat( homeAddress, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
}
|
||||
|
||||
// util methods for verifying 'domain-result' graph ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.metamodel.mapping.AttributeMappingsList;
|
|||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.sql.ast.tree.from.FromClause;
|
||||
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
|
||||
|
@ -63,10 +64,10 @@ import jakarta.persistence.OneToMany;
|
|||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.testing.hamcrest.AssignableMatcher.assignableTo;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.hasSize;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.isEmpty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Strong Liu
|
||||
|
@ -268,8 +269,11 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
|
|||
|
||||
final TableGroup compositeTableGroup = CollectionUtils.getOnlyElement( tableGroup.getNestedTableGroupJoins() ).getJoinedGroup();
|
||||
assertThat( compositeTableGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getNestedTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = compositeTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( joinedGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
} );
|
||||
|
||||
|
@ -284,7 +288,10 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
|
|||
assertThat( fromClause.getRoots(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup rootTableGroup = fromClause.getRoots().get( 0 );
|
||||
assertThat( rootTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( rootTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup tableGroup = rootTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( tableGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
|
||||
private void assertEntityValuedJoinedGroup(SelectStatement sqlAst, String expectedAttributeName, Class<?> expectedEntityJpaClass, Consumer<TableGroup> tableGroupConsumer) {
|
||||
|
@ -316,12 +323,18 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware
|
|||
}
|
||||
|
||||
private void assertPersonHomeAddressJoinedGroup(TableGroup tableGroup) {
|
||||
assertThat( tableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
assertThat( tableGroup.getTableGroupJoins(), hasSize( 2 ) );
|
||||
|
||||
final TableGroup joinedGroup = CollectionUtils.getOnlyElement( tableGroup.getTableGroupJoins() ).getJoinedGroup();
|
||||
assertThat( joinedGroup.getModelPart().getPartName(), is( "homeAddress" ) );
|
||||
assertThat( joinedGroup.getModelPart(), instanceOf( EmbeddedAttributeMapping.class ) );
|
||||
assertThat( joinedGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
final TableGroup company = tableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( company.getModelPart().getPartName(), is( "company" ) );
|
||||
assertThat( company.getModelPart(), instanceOf( ToOneAttributeMapping.class ) );
|
||||
assertThat( company, instanceOf( LazyTableGroup.class ) );
|
||||
assertThat( company.isInitialized(), is( false ) );
|
||||
|
||||
final TableGroup homeAddress = tableGroup.getTableGroupJoins().get( 1 ).getJoinedGroup();
|
||||
assertThat( homeAddress.getModelPart().getPartName(), is( "homeAddress" ) );
|
||||
assertThat( homeAddress.getModelPart(), instanceOf( EmbeddedAttributeMapping.class ) );
|
||||
assertThat( homeAddress, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
}
|
||||
|
||||
// util methods for verifying 'domain-result' graph ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.metamodel.mapping.AttributeMappingsList;
|
|||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.hql.spi.SqmQueryImplementor;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
@ -68,10 +69,10 @@ import jakarta.persistence.OneToMany;
|
|||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.testing.hamcrest.AssignableMatcher.assignableTo;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.hasSize;
|
||||
import static org.hibernate.testing.hamcrest.CollectionMatchers.isEmpty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Nathan Xu
|
||||
|
@ -284,8 +285,11 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
|
|||
.next()
|
||||
.getJoinedGroup();
|
||||
assertThat( compositeTableGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), isEmpty( ) );
|
||||
assertThat( compositeTableGroup.getNestedTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = compositeTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( joinedGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
else {
|
||||
assertThat( tableGroup.getTableGroupJoins(), isEmpty() );
|
||||
|
@ -293,8 +297,11 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
|
|||
|
||||
final TableGroup compositeTableGroup = CollectionUtils.getOnlyElement( tableGroup.getNestedTableGroupJoins() ).getJoinedGroup();
|
||||
assertThat( compositeTableGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getNestedTableGroupJoins(), isEmpty() );
|
||||
assertThat( compositeTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = compositeTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( joinedGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
@ -308,7 +315,10 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
|
|||
assertThat( fromClause.getRoots(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup rootTableGroup = fromClause.getRoots().get( 0 );
|
||||
assertThat( rootTableGroup.getTableGroupJoins(), isEmpty() );
|
||||
assertThat( rootTableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup tableGroup = rootTableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( tableGroup.isInitialized(), is( false ) );
|
||||
}
|
||||
|
||||
private void assertEntityValuedJoinedGroup(SelectStatement sqlAst, String expectedAttributeName, Class<?> expectedEntityJpaClass, Consumer<TableGroup> tableGroupConsumer) {
|
||||
|
@ -333,19 +343,26 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware {
|
|||
final TableGroup root = fromClause.getRoots().get( 0 );
|
||||
assertThat( root.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = root.getTableGroupJoins().iterator().next().getJoinedGroup();
|
||||
final TableGroup joinedGroup = root.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( joinedGroup.getModelPart().getPartName(), is( expectedPluralAttributeName ) );
|
||||
assertThat( joinedGroup.getModelPart(), instanceOf( PluralAttributeMapping.class ) );
|
||||
tableGroupConsumer.accept( joinedGroup );
|
||||
}
|
||||
|
||||
private void assertPersonHomeAddressJoinedGroup(TableGroup tableGroup) {
|
||||
assertThat( tableGroup.getTableGroupJoins(), hasSize( 1 ) );
|
||||
|
||||
final TableGroup joinedGroup = tableGroup.getTableGroupJoins().iterator().next().getJoinedGroup();
|
||||
assertThat( joinedGroup.getModelPart().getPartName(), is( "homeAddress" ) );
|
||||
assertThat( joinedGroup.getModelPart(), instanceOf( EmbeddedAttributeMapping.class ) );
|
||||
assertThat( joinedGroup, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
assertThat( tableGroup.getTableGroupJoins(), hasSize( 2 ) );
|
||||
|
||||
final TableGroup company = tableGroup.getTableGroupJoins().get( 0 ).getJoinedGroup();
|
||||
assertThat( company.getModelPart().getPartName(), is( "company" ) );
|
||||
assertThat( company.getModelPart(), instanceOf( ToOneAttributeMapping.class ) );
|
||||
assertThat( company, instanceOf( LazyTableGroup.class ) );
|
||||
assertThat( company.isInitialized(), is( false ) );
|
||||
|
||||
final TableGroup homeAddress = tableGroup.getTableGroupJoins().get( 1 ).getJoinedGroup();
|
||||
assertThat( homeAddress.getModelPart().getPartName(), is( "homeAddress" ) );
|
||||
assertThat( homeAddress.getModelPart(), instanceOf( EmbeddedAttributeMapping.class ) );
|
||||
assertThat( homeAddress, instanceOf( StandardVirtualTableGroup.class ) );
|
||||
}
|
||||
|
||||
// util methods for verifying 'domain-result' graph ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -46,7 +46,7 @@ class HHH15065Test {
|
|||
SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||
List<String> sqlQueries = statementInspector.getSqlQueries();
|
||||
assertEquals( 1, sqlQueries.size() );
|
||||
assertEquals( "select b1_0.id,a1_0.id,c1_0.id,c2_0.id,e1_0.id" +
|
||||
assertEquals( "select b1_0.id,a1_0.id,a1_0.name,c1_0.id,c1_0.name,c2_0.id,c2_0.name,e1_0.id,e1_0.name" +
|
||||
" from Book b1_0" +
|
||||
" left join Person a1_0 on a1_0.id=b1_0.author_id" +
|
||||
" left join Person c1_0 on c1_0.id=b1_0.coAuthor_id" +
|
||||
|
@ -73,9 +73,10 @@ class HHH15065Test {
|
|||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public class Person {
|
||||
public static class Person {
|
||||
@Id
|
||||
Long id;
|
||||
String name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import jakarta.persistence.Table;
|
|||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
|
@ -41,9 +43,9 @@ public class ManyToOneJoinReuseTest {
|
|||
@TestForIssue(jiraKey = "HHH-15648")
|
||||
public void fetchAndImplicitPath(SessionFactoryScope scope) {
|
||||
SQLStatementInspector sqlStatementInterceptor = scope.getCollectingStatementInspector();
|
||||
sqlStatementInterceptor.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
sqlStatementInterceptor.clear();
|
||||
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
JpaCriteriaQuery<BookList> query = cb.createQuery( BookList.class );
|
||||
|
||||
|
@ -52,7 +54,11 @@ public class ManyToOneJoinReuseTest {
|
|||
query.where( root.get( "book" ).isNotNull() );
|
||||
|
||||
session.createQuery( query ).getResultList();
|
||||
sqlStatementInterceptor.assertExecuted( "select b1_0.id,b2_0.isbn,b2_0.title from BookList b1_0 join book b2_0 on b2_0.isbn=b1_0.book_isbn where b2_0.isbn is not null" );
|
||||
assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() );
|
||||
assertEquals(
|
||||
"select b1_0.id,b2_0.isbn,b2_0.title from BookList b1_0 join book b2_0 on b2_0.isbn=b1_0.book_isbn where b2_0.isbn is not null",
|
||||
sqlStatementInterceptor.getSqlQueries().get( 0 )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -61,9 +67,9 @@ public class ManyToOneJoinReuseTest {
|
|||
@TestForIssue(jiraKey = "HHH-15645")
|
||||
public void joinAndImplicitPath(SessionFactoryScope scope) {
|
||||
SQLStatementInspector sqlStatementInterceptor = scope.getCollectingStatementInspector();
|
||||
sqlStatementInterceptor.clear();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
sqlStatementInterceptor.clear();
|
||||
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
JpaCriteriaQuery<BookList> query = cb.createQuery( BookList.class );
|
||||
|
||||
|
@ -77,7 +83,11 @@ public class ManyToOneJoinReuseTest {
|
|||
);
|
||||
|
||||
session.createQuery( query ).getResultList();
|
||||
sqlStatementInterceptor.assertExecuted( "select b1_0.id,b1_0.book_isbn from BookList b1_0 join book b2_0 on b2_0.isbn=b1_0.book_isbn where b2_0.isbn is not null and b1_0.book_isbn is not null" );
|
||||
assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() );
|
||||
assertEquals(
|
||||
"select b1_0.id,b1_0.book_isbn from BookList b1_0 join book b2_0 on b2_0.isbn=b1_0.book_isbn where b2_0.isbn is not null and b1_0.book_isbn is not null",
|
||||
sqlStatementInterceptor.getSqlQueries().get( 0 )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* 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.idclass;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
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.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.IdClass;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
IdClassEagerQuerySelectTest.Organisation.class,
|
||||
IdClassEagerQuerySelectTest.User.class,
|
||||
IdClassEagerQuerySelectTest.OrganisationUser.class,
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@TestForIssue(jiraKey = "HHH-16366")
|
||||
public class IdClassEagerQuerySelectTest {
|
||||
|
||||
private static final Integer ORGANISATION_ID = 1;
|
||||
private static final Integer USER_ID = 2;
|
||||
|
||||
@BeforeAll
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Organisation organisation = new Organisation( ORGANISATION_ID, "Red Hat" );
|
||||
session.persist( organisation );
|
||||
|
||||
User user = new User( USER_ID, AccountType.FOO );
|
||||
session.persist( user );
|
||||
|
||||
OrganisationUser organisationUser = new OrganisationUser( organisation, user, "1" );
|
||||
session.persist( organisationUser );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectUsingIdClassInWhereClause(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.user u where o.organisation.id = ?1 and u.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.user u join fetch o.organisation or where or.id = ?1 and u.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.organisation or where or.id = ?1 and o.user.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o where o.organisation.id = ?1 and o.user.accountType = ?2 ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.setParameter( 1, ORGANISATION_ID )
|
||||
.setParameter( 2, AccountType.FOO )
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelect(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectJoiningPartOfIdClass(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
List<OrganisationUser> resultList = session.createQuery(
|
||||
"select distinct o from OrganisationUser o join fetch o.user u ",
|
||||
OrganisationUser.class
|
||||
)
|
||||
.getResultList();
|
||||
|
||||
assertThat( resultList.size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "OrganisationUser")
|
||||
@Table(name = "ORGANISATION_USER")
|
||||
@IdClass(OrganisationUserId.class)
|
||||
public static class OrganisationUser {
|
||||
|
||||
@Id
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "ORGANISATION_ID", nullable = false)
|
||||
private Organisation organisation;
|
||||
|
||||
@Id
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "USER_ID", nullable = false)
|
||||
private User user;
|
||||
|
||||
public OrganisationUser() {
|
||||
}
|
||||
|
||||
public OrganisationUser(Organisation organisation, User user, String code) {
|
||||
this.organisation = organisation;
|
||||
this.user = user;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
private String code;
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "User")
|
||||
@Table(name = "F_USER")
|
||||
public static class User {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "ACCOUNT_TYPE")
|
||||
private AccountType accountType;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(Integer id, AccountType accountType) {
|
||||
this.id = id;
|
||||
this.accountType = accountType;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public AccountType getAccountType() {
|
||||
return accountType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Organisation")
|
||||
@Table(name = "ORGANISATION")
|
||||
public static class Organisation {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID", unique = true)
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Organisation() {
|
||||
}
|
||||
|
||||
public Organisation(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AccountType {
|
||||
FOO,
|
||||
BAR,
|
||||
}
|
||||
|
||||
public static class OrganisationUserId implements Serializable {
|
||||
|
||||
private Integer organisation;
|
||||
private Integer user;
|
||||
|
||||
public OrganisationUserId() {
|
||||
}
|
||||
|
||||
public OrganisationUserId(Integer organisation, Integer user) {
|
||||
this.organisation = organisation;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
OrganisationUserId that = (OrganisationUserId) o;
|
||||
return Objects.equals( organisation, that.organisation ) && Objects.equals( user, that.user );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( organisation, user );
|
||||
}
|
||||
|
||||
public Integer getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
|
||||
public void setOrganisation(Integer organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
public Integer getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(Integer user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue