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