Cleanup support for virtual embeddable model parts and reuse existing compatible joins for implicit joins
This commit is contained in:
parent
d5d350e5e7
commit
39484b160d
|
@ -39,10 +39,10 @@ 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.metamodel.mapping.NaturalIdMapping;
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.Restrictable;
|
import org.hibernate.metamodel.mapping.Restrictable;
|
||||||
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||||
import org.hibernate.query.ComparisonOperator;
|
import org.hibernate.query.ComparisonOperator;
|
||||||
|
@ -340,7 +340,7 @@ public class LoaderSelectBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( ModelPart restrictedPart : restrictedParts ) {
|
for ( ModelPart restrictedPart : restrictedParts ) {
|
||||||
if ( restrictedPart instanceof ForeignKeyDescriptor || restrictedPart instanceof NonAggregatedIdentifierMappingImpl ) {
|
if ( restrictedPart instanceof ForeignKeyDescriptor || restrictedPart instanceof NonAggregatedIdentifierMapping ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
|
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
import org.hibernate.sql.results.graph.FetchableContainer;
|
import org.hibernate.sql.results.graph.FetchableContainer;
|
||||||
|
|
||||||
|
@ -26,4 +27,9 @@ public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableC
|
||||||
|
|
||||||
EntityMappingType resolveDiscriminatorValue(Object discriminatorValue);
|
EntityMappingType resolveDiscriminatorValue(Object discriminatorValue);
|
||||||
Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType);
|
Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
return predicate == null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,8 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValueMapping {
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext);
|
SqlAstCreationContext creationContext);
|
||||||
|
|
||||||
|
boolean isSimpleJoinPredicate(Predicate predicate);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default String getPartName() {
|
default String getPartName() {
|
||||||
return PART_NAME;
|
return PART_NAME;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
|
||||||
* @see jakarta.persistence.IdClass
|
* @see jakarta.persistence.IdClass
|
||||||
* @see jakarta.persistence.MapsId
|
* @see jakarta.persistence.MapsId
|
||||||
*/
|
*/
|
||||||
public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMapping, EmbeddableValuedFetchable, FetchOptions {
|
public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMapping, EmbeddableValuedFetchable, FetchOptions, VirtualModelPart {
|
||||||
/**
|
/**
|
||||||
* The virtual-id representation of this id mapping
|
* The virtual-id representation of this id mapping
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class EmbeddedAttributeMapping
|
||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
tableExpression,
|
tableExpression,
|
||||||
attributeMetadataAccess,
|
attributeMetadataAccess,
|
||||||
getPropertyAccess(parentInjectionAttributeName, embeddableMappingType),
|
getPropertyAccess( parentInjectionAttributeName, embeddableMappingType ),
|
||||||
mappedFetchTiming,
|
mappedFetchTiming,
|
||||||
mappedFetchStyle,
|
mappedFetchStyle,
|
||||||
embeddableMappingType,
|
embeddableMappingType,
|
||||||
|
@ -132,7 +132,7 @@ public class EmbeddedAttributeMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor is only used for creating the inverse attribute mapping
|
// Constructor is only used for creating the inverse attribute mapping
|
||||||
private EmbeddedAttributeMapping(
|
EmbeddedAttributeMapping(
|
||||||
ManagedMappingType keyDeclaringType,
|
ManagedMappingType keyDeclaringType,
|
||||||
TableGroupProducer declaringTableGroupProducer,
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
SelectableMappings selectableMappings,
|
SelectableMappings selectableMappings,
|
||||||
|
@ -161,29 +161,6 @@ public class EmbeddedAttributeMapping
|
||||||
this.parentInjectionAttributePropertyAccess = null;
|
this.parentInjectionAttributePropertyAccess = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EmbeddableValuedModelPart createInverseModelPart(
|
|
||||||
EmbeddableValuedModelPart modelPart,
|
|
||||||
ManagedMappingType keyDeclaringType,
|
|
||||||
TableGroupProducer declaringTableGroupProducer,
|
|
||||||
SelectableMappings selectableMappings,
|
|
||||||
MappingModelCreationProcess creationProcess) {
|
|
||||||
final EmbeddableMappingType embeddableTypeDescriptor;
|
|
||||||
if ( modelPart instanceof CompositeIdentifierMapping ) {
|
|
||||||
embeddableTypeDescriptor = ( (CompositeIdentifierMapping) modelPart ).getMappedIdEmbeddableTypeDescriptor();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
embeddableTypeDescriptor = modelPart.getEmbeddableTypeDescriptor();
|
|
||||||
}
|
|
||||||
return new EmbeddedAttributeMapping(
|
|
||||||
keyDeclaringType,
|
|
||||||
declaringTableGroupProducer,
|
|
||||||
selectableMappings,
|
|
||||||
modelPart,
|
|
||||||
embeddableTypeDescriptor,
|
|
||||||
creationProcess
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EmbeddableMappingType getMappedType() {
|
public EmbeddableMappingType getMappedType() {
|
||||||
return getEmbeddableTypeDescriptor();
|
return getEmbeddableTypeDescriptor();
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
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.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;
|
||||||
|
@ -115,7 +116,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
this.targetSide = original.targetSide;
|
this.targetSide = original.targetSide;
|
||||||
this.keySide = new EmbeddedForeignKeyDescriptorSide(
|
this.keySide = new EmbeddedForeignKeyDescriptorSide(
|
||||||
Nature.KEY,
|
Nature.KEY,
|
||||||
EmbeddedAttributeMapping.createInverseModelPart(
|
MappingModelCreationHelper.createInverseModelPart(
|
||||||
original.targetSide.getModelPart(),
|
original.targetSide.getModelPart(),
|
||||||
keyDeclaringType,
|
keyDeclaringType,
|
||||||
keyDeclaringTableGroupProducer,
|
keyDeclaringTableGroupProducer,
|
||||||
|
@ -377,6 +378,84 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
return getPredicate( targetSideReference, keySideReference, creationContext, targetSelectableMappings, keySelectableMappings );
|
return getPredicate( targetSideReference, keySideReference, creationContext, targetSelectableMappings, keySelectableMappings );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
if ( !( predicate instanceof Junction ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Junction junction = (Junction) predicate;
|
||||||
|
if ( junction.getNature() != Junction.Nature.CONJUNCTION ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final List<Predicate> predicates = junction.getPredicates();
|
||||||
|
if ( predicates.size() != keySelectableMappings.getJdbcTypeCount() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Boolean lhsIsKey = null;
|
||||||
|
for ( int i = 0; i < predicates.size(); i++ ) {
|
||||||
|
final Predicate p = predicates.get( i );
|
||||||
|
if ( !( p instanceof ComparisonPredicate ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ComparisonPredicate comparisonPredicate = (ComparisonPredicate) p;
|
||||||
|
if ( comparisonPredicate.getOperator() != ComparisonOperator.EQUAL ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Expression lhsExpr = comparisonPredicate.getLeftHandExpression();
|
||||||
|
final Expression rhsExpr = comparisonPredicate.getRightHandExpression();
|
||||||
|
if ( !( lhsExpr instanceof ColumnReference ) || !( rhsExpr instanceof ColumnReference ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ColumnReference lhs = (ColumnReference) lhsExpr;
|
||||||
|
final ColumnReference rhs = (ColumnReference) rhsExpr;
|
||||||
|
if ( lhsIsKey == null ) {
|
||||||
|
final String keyExpression = keySelectableMappings.getSelectable( i ).getSelectionExpression();
|
||||||
|
final String targetExpression = targetSelectableMappings.getSelectable( i ).getSelectionExpression();
|
||||||
|
if ( keyExpression.equals( targetExpression ) ) {
|
||||||
|
if ( !lhs.getColumnExpression().equals( keyExpression )
|
||||||
|
|| !rhs.getColumnExpression().equals( keyExpression ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( keyExpression.equals( lhs.getColumnExpression() ) ) {
|
||||||
|
if ( !targetExpression.equals( rhs.getColumnExpression() ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lhsIsKey = true;
|
||||||
|
}
|
||||||
|
else if ( keyExpression.equals( rhs.getColumnExpression() ) ) {
|
||||||
|
if ( !targetExpression.equals( lhs.getColumnExpression() ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lhsIsKey = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final String lhsSelectionExpression;
|
||||||
|
final String rhsSelectionExpression;
|
||||||
|
if ( lhsIsKey ) {
|
||||||
|
lhsSelectionExpression = keySelectableMappings.getSelectable( i ).getSelectionExpression();
|
||||||
|
rhsSelectionExpression = targetSelectableMappings.getSelectable( i ).getSelectionExpression();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lhsSelectionExpression = targetSelectableMappings.getSelectable( i ).getSelectionExpression();
|
||||||
|
rhsSelectionExpression = keySelectableMappings.getSelectable( i ).getSelectionExpression();
|
||||||
|
}
|
||||||
|
if ( !lhs.getColumnExpression().equals( lhsSelectionExpression )
|
||||||
|
|| !rhs.getColumnExpression().equals( rhsSelectionExpression ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private Predicate getPredicate(
|
private Predicate getPredicate(
|
||||||
TableReference lhs,
|
TableReference lhs,
|
||||||
TableReference rhs,
|
TableReference rhs,
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||||
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.VirtualModelPart;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -168,7 +169,14 @@ public class EntityCollectionPart
|
||||||
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 ) {
|
||||||
this.targetKeyPropertyNames = Collections.singleton( compositeType.getPropertyNames()[0] );
|
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||||
|
ToOneAttributeMapping.addPrefixedPropertyNames(
|
||||||
|
targetKeyPropertyNames,
|
||||||
|
compositeType.getPropertyNames()[0],
|
||||||
|
compositeType.getSubtypes()[0],
|
||||||
|
creationProcess.getCreationContext().getSessionFactory()
|
||||||
|
);
|
||||||
|
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final String mapsIdAttributeName;
|
final String mapsIdAttributeName;
|
||||||
|
@ -327,6 +335,11 @@ public class EntityCollectionPart
|
||||||
return SqlAstJoinType.INNER;
|
return SqlAstJoinType.INNER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
return fkDescriptor.isSimpleJoinPredicate( predicate );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Nature getNature() {
|
public Nature getNature() {
|
||||||
return nature;
|
return nature;
|
||||||
|
@ -391,13 +404,14 @@ public class EntityCollectionPart
|
||||||
// This is not possible for one-to-many associations because we need to create the target table group eagerly,
|
// This is not possible for one-to-many associations because we need to create the target table group eagerly,
|
||||||
// to preserve the cardinality. Also, the OneToManyTableGroup has no reference to the parent table group
|
// to preserve the cardinality. Also, the OneToManyTableGroup has no reference to the parent table group
|
||||||
if ( !collectionDescriptor.isOneToMany() && targetKeyPropertyNames.contains( name ) ) {
|
if ( !collectionDescriptor.isOneToMany() && targetKeyPropertyNames.contains( name ) ) {
|
||||||
if ( fkDescriptor.getTargetPart() instanceof NonAggregatedIdentifierMappingImpl ) {
|
|
||||||
return ( (ModelPartContainer) fkDescriptor.getKeyPart() ).findSubPart( name, targetType );
|
|
||||||
}
|
|
||||||
if ( fkTargetModelPart instanceof ToOneAttributeMapping ) {
|
if ( fkTargetModelPart instanceof ToOneAttributeMapping ) {
|
||||||
return fkTargetModelPart;
|
return fkTargetModelPart;
|
||||||
}
|
}
|
||||||
return fkDescriptor.getKeyPart();
|
final ModelPart keyPart = fkDescriptor.getKeyPart();
|
||||||
|
if ( keyPart instanceof EmbeddableValuedModelPart && keyPart instanceof VirtualModelPart ) {
|
||||||
|
return ( (ModelPartContainer) keyPart ).findSubPart( name, targetType );
|
||||||
|
}
|
||||||
|
return keyPart;
|
||||||
}
|
}
|
||||||
return EntityValuedFetchable.super.findSubPart( name, targetType );
|
return EntityValuedFetchable.super.findSubPart( name, targetType );
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,6 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.GeneratedValueResolver;
|
import org.hibernate.metamodel.mapping.GeneratedValueResolver;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelCreationLogger;
|
|
||||||
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.NonTransientException;
|
import org.hibernate.metamodel.mapping.NonTransientException;
|
||||||
|
@ -71,6 +70,7 @@ import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableMappings;
|
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
|
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
||||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||||
|
@ -341,7 +341,9 @@ public class MappingModelCreationHelper {
|
||||||
attrType,
|
attrType,
|
||||||
tableExpression,
|
tableExpression,
|
||||||
rootTableKeyColumnNames,
|
rootTableKeyColumnNames,
|
||||||
attributeMappingType -> new EmbeddedAttributeMapping(
|
attributeMappingType -> {
|
||||||
|
if ( component.isEmbedded() ) {
|
||||||
|
return new VirtualEmbeddedAttributeMapping(
|
||||||
attrName,
|
attrName,
|
||||||
declaringType.getNavigableRole().append( attrName ),
|
declaringType.getNavigableRole().append( attrName ),
|
||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
|
@ -354,7 +356,25 @@ public class MappingModelCreationHelper {
|
||||||
declaringType,
|
declaringType,
|
||||||
propertyAccess,
|
propertyAccess,
|
||||||
bootProperty.getValueGenerationStrategy()
|
bootProperty.getValueGenerationStrategy()
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new EmbeddedAttributeMapping(
|
||||||
|
attrName,
|
||||||
|
declaringType.getNavigableRole().append( attrName ),
|
||||||
|
stateArrayPosition,
|
||||||
|
tableExpression,
|
||||||
|
attributeMetadataAccess,
|
||||||
|
component.getParentProperty(),
|
||||||
|
FetchTiming.IMMEDIATE,
|
||||||
|
FetchStyle.JOIN,
|
||||||
|
attributeMappingType,
|
||||||
|
declaringType,
|
||||||
|
propertyAccess,
|
||||||
|
bootProperty.getValueGenerationStrategy()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
creationProcess
|
creationProcess
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1172,7 +1192,7 @@ public class MappingModelCreationHelper {
|
||||||
if ( inverse ) {
|
if ( inverse ) {
|
||||||
return new EmbeddedForeignKeyDescriptor(
|
return new EmbeddedForeignKeyDescriptor(
|
||||||
embeddableValuedModelPart,
|
embeddableValuedModelPart,
|
||||||
EmbeddedAttributeMapping.createInverseModelPart(
|
createInverseModelPart(
|
||||||
embeddableValuedModelPart,
|
embeddableValuedModelPart,
|
||||||
keyDeclaringType,
|
keyDeclaringType,
|
||||||
keyDeclaringTableGroupProducer,
|
keyDeclaringTableGroupProducer,
|
||||||
|
@ -1189,7 +1209,7 @@ public class MappingModelCreationHelper {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new EmbeddedForeignKeyDescriptor(
|
return new EmbeddedForeignKeyDescriptor(
|
||||||
EmbeddedAttributeMapping.createInverseModelPart(
|
createInverseModelPart(
|
||||||
embeddableValuedModelPart,
|
embeddableValuedModelPart,
|
||||||
keyDeclaringType,
|
keyDeclaringType,
|
||||||
keyDeclaringTableGroupProducer,
|
keyDeclaringTableGroupProducer,
|
||||||
|
@ -1494,6 +1514,41 @@ public class MappingModelCreationHelper {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EmbeddableValuedModelPart createInverseModelPart(
|
||||||
|
EmbeddableValuedModelPart modelPart,
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
|
SelectableMappings selectableMappings,
|
||||||
|
MappingModelCreationProcess creationProcess) {
|
||||||
|
final EmbeddableMappingType embeddableTypeDescriptor;
|
||||||
|
if ( modelPart instanceof CompositeIdentifierMapping ) {
|
||||||
|
embeddableTypeDescriptor = ( (CompositeIdentifierMapping) modelPart ).getMappedIdEmbeddableTypeDescriptor();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
embeddableTypeDescriptor = modelPart.getEmbeddableTypeDescriptor();
|
||||||
|
}
|
||||||
|
if ( modelPart instanceof VirtualModelPart ) {
|
||||||
|
return new VirtualEmbeddedAttributeMapping(
|
||||||
|
keyDeclaringType,
|
||||||
|
declaringTableGroupProducer,
|
||||||
|
selectableMappings,
|
||||||
|
modelPart,
|
||||||
|
embeddableTypeDescriptor,
|
||||||
|
creationProcess
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new EmbeddedAttributeMapping(
|
||||||
|
keyDeclaringType,
|
||||||
|
declaringTableGroupProducer,
|
||||||
|
selectableMappings,
|
||||||
|
modelPart,
|
||||||
|
embeddableTypeDescriptor,
|
||||||
|
creationProcess
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static class CollectionMappingTypeImpl implements CollectionMappingType {
|
private static class CollectionMappingTypeImpl implements CollectionMappingType {
|
||||||
private final JavaType collectionJtd;
|
private final JavaType collectionJtd;
|
||||||
|
|
|
@ -517,6 +517,11 @@ public class PluralAttributeMappingImpl
|
||||||
return SqlAstJoinType.LEFT;
|
return SqlAstJoinType.LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
return fkDescriptor.isSimpleJoinPredicate( predicate );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TableGroupJoin createTableGroupJoin(
|
public TableGroupJoin createTableGroupJoin(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
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.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;
|
||||||
|
@ -289,6 +290,28 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
if ( !( predicate instanceof ComparisonPredicate ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ComparisonPredicate comparisonPredicate = (ComparisonPredicate) predicate;
|
||||||
|
if ( comparisonPredicate.getOperator() != ComparisonOperator.EQUAL ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Expression lhsExpr = comparisonPredicate.getLeftHandExpression();
|
||||||
|
final Expression rhsExpr = comparisonPredicate.getRightHandExpression();
|
||||||
|
if ( !( lhsExpr instanceof ColumnReference ) || !( rhsExpr instanceof ColumnReference ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String lhs = ( (ColumnReference) lhsExpr ).getColumnExpression();
|
||||||
|
final String rhs = ( (ColumnReference) rhsExpr ).getColumnExpression();
|
||||||
|
final String keyExpression = keySide.getModelPart().getSelectionExpression();
|
||||||
|
final String targetExpression = targetSide.getModelPart().getSelectionExpression();
|
||||||
|
return ( lhs.equals( keyExpression ) && rhs.equals( targetExpression ) )
|
||||||
|
|| ( lhs.equals( targetExpression ) && rhs.equals( keyExpression ) );
|
||||||
|
}
|
||||||
|
|
||||||
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
|
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
|
||||||
final NavigablePath navigablePath = lhs.getNavigablePath().append( getTargetPart().getFetchableName() );
|
final NavigablePath navigablePath = lhs.getNavigablePath().append( getTargetPart().getFetchableName() );
|
||||||
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {
|
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {
|
||||||
|
|
|
@ -15,7 +15,6 @@ import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
@ -30,7 +29,6 @@ import org.hibernate.mapping.OneToOne;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Selectable;
|
import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.Table;
|
|
||||||
import org.hibernate.mapping.ToOne;
|
import org.hibernate.mapping.ToOne;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||||
|
@ -47,6 +45,7 @@ import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
|
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.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||||
|
@ -96,6 +95,7 @@ import org.hibernate.tuple.IdentifierProperty;
|
||||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
import org.hibernate.type.ComponentType;
|
import org.hibernate.type.ComponentType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
import org.hibernate.type.EmbeddedComponentType;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
@ -440,8 +440,15 @@ public class ToOneAttributeMapping
|
||||||
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 ) {
|
||||||
|
final Set<String> targetKeyPropertyNames = new HashSet<>( 2 );
|
||||||
this.targetKeyPropertyName = compositeType.getPropertyNames()[0];
|
this.targetKeyPropertyName = compositeType.getPropertyNames()[0];
|
||||||
this.targetKeyPropertyNames = Collections.singleton( targetKeyPropertyName );
|
addPrefixedPropertyNames(
|
||||||
|
targetKeyPropertyNames,
|
||||||
|
targetKeyPropertyName,
|
||||||
|
compositeType.getSubtypes()[0],
|
||||||
|
declaringEntityPersister.getFactory()
|
||||||
|
);
|
||||||
|
this.targetKeyPropertyNames = targetKeyPropertyNames;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.targetKeyPropertyName = referencedPropertyName;
|
this.targetKeyPropertyName = referencedPropertyName;
|
||||||
|
@ -551,6 +558,9 @@ public class ToOneAttributeMapping
|
||||||
if ( entityType.isReferenceToPrimaryKey() ) {
|
if ( entityType.isReferenceToPrimaryKey() ) {
|
||||||
propertyName = entityType.getAssociatedEntityPersister( factory ).getIdentifierPropertyName();
|
propertyName = entityType.getAssociatedEntityPersister( factory ).getIdentifierPropertyName();
|
||||||
}
|
}
|
||||||
|
else if ( identifierOrUniqueKeyType instanceof EmbeddedComponentType ) {
|
||||||
|
propertyName = null;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
propertyName = entityType.getRHSUniqueKeyPropertyName();
|
propertyName = entityType.getRHSUniqueKeyPropertyName();
|
||||||
}
|
}
|
||||||
|
@ -651,20 +661,17 @@ public class ToOneAttributeMapping
|
||||||
// Prefer resolving the key part of the foreign key rather than the target part if possible
|
// Prefer resolving the key part of the foreign key rather than the target part if possible
|
||||||
// This way, we don't have to register table groups the target entity type
|
// This way, we don't have to register table groups the target entity type
|
||||||
if ( canUseParentTableGroup && targetKeyPropertyNames.contains( name ) ) {
|
if ( canUseParentTableGroup && targetKeyPropertyNames.contains( name ) ) {
|
||||||
final ModelPart fkSideModelPart;
|
final ModelPart fkPart;
|
||||||
final ModelPart fkTargetModelPart;
|
|
||||||
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
|
if ( sideNature == ForeignKeyDescriptor.Nature.KEY ) {
|
||||||
fkTargetModelPart = foreignKeyDescriptor.getTargetPart();
|
fkPart = foreignKeyDescriptor.getKeyPart();
|
||||||
fkSideModelPart = foreignKeyDescriptor.getKeyPart();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fkTargetModelPart = foreignKeyDescriptor.getKeyPart();
|
fkPart = foreignKeyDescriptor.getTargetPart();
|
||||||
fkSideModelPart = foreignKeyDescriptor.getTargetPart();
|
|
||||||
}
|
}
|
||||||
if ( fkTargetModelPart instanceof NonAggregatedIdentifierMappingImpl ) {
|
if ( fkPart instanceof EmbeddableValuedModelPart && fkPart instanceof VirtualModelPart ) {
|
||||||
return ( (ModelPartContainer) fkSideModelPart ).findSubPart( name, targetType );
|
return ( (ModelPartContainer) fkPart ).findSubPart( name, targetType );
|
||||||
}
|
}
|
||||||
return fkSideModelPart;
|
return fkPart;
|
||||||
}
|
}
|
||||||
return EntityValuedFetchable.super.findSubPart( name, targetType );
|
return EntityValuedFetchable.super.findSubPart( name, targetType );
|
||||||
}
|
}
|
||||||
|
@ -1223,6 +1230,11 @@ public class ToOneAttributeMapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
return foreignKeyDescriptor.isSimpleJoinPredicate( predicate );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumberOfFetchables() {
|
public int getNumberOfFetchables() {
|
||||||
return getEntityMappingType().getNumberOfFetchables();
|
return getEntityMappingType().getNumberOfFetchables();
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.FetchStyle;
|
||||||
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||||
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
|
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
||||||
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
|
||||||
|
import org.hibernate.tuple.ValueGeneration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Beikov
|
||||||
|
*/
|
||||||
|
public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping implements VirtualModelPart {
|
||||||
|
|
||||||
|
public VirtualEmbeddedAttributeMapping(
|
||||||
|
String name,
|
||||||
|
NavigableRole navigableRole,
|
||||||
|
int stateArrayPosition,
|
||||||
|
String tableExpression,
|
||||||
|
StateArrayContributorMetadataAccess attributeMetadataAccess,
|
||||||
|
String parentInjectionAttributeName,
|
||||||
|
FetchTiming mappedFetchTiming,
|
||||||
|
FetchStyle mappedFetchStyle,
|
||||||
|
EmbeddableMappingType embeddableMappingType,
|
||||||
|
ManagedMappingType declaringType,
|
||||||
|
PropertyAccess propertyAccess, ValueGeneration valueGeneration) {
|
||||||
|
super(
|
||||||
|
name,
|
||||||
|
navigableRole,
|
||||||
|
stateArrayPosition,
|
||||||
|
tableExpression,
|
||||||
|
attributeMetadataAccess,
|
||||||
|
parentInjectionAttributeName,
|
||||||
|
mappedFetchTiming,
|
||||||
|
mappedFetchStyle,
|
||||||
|
embeddableMappingType,
|
||||||
|
declaringType,
|
||||||
|
propertyAccess,
|
||||||
|
valueGeneration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualEmbeddedAttributeMapping(
|
||||||
|
String name,
|
||||||
|
NavigableRole navigableRole,
|
||||||
|
int stateArrayPosition,
|
||||||
|
String tableExpression,
|
||||||
|
StateArrayContributorMetadataAccess attributeMetadataAccess,
|
||||||
|
PropertyAccess parentInjectionAttributePropertyAccess,
|
||||||
|
FetchTiming mappedFetchTiming,
|
||||||
|
FetchStyle mappedFetchStyle,
|
||||||
|
EmbeddableMappingType embeddableMappingType,
|
||||||
|
ManagedMappingType declaringType,
|
||||||
|
PropertyAccess propertyAccess, ValueGeneration valueGeneration) {
|
||||||
|
super(
|
||||||
|
name,
|
||||||
|
navigableRole,
|
||||||
|
stateArrayPosition,
|
||||||
|
tableExpression,
|
||||||
|
attributeMetadataAccess,
|
||||||
|
parentInjectionAttributePropertyAccess,
|
||||||
|
mappedFetchTiming,
|
||||||
|
mappedFetchStyle,
|
||||||
|
embeddableMappingType,
|
||||||
|
declaringType,
|
||||||
|
propertyAccess,
|
||||||
|
valueGeneration
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor is only used for creating the inverse attribute mapping
|
||||||
|
VirtualEmbeddedAttributeMapping(
|
||||||
|
ManagedMappingType keyDeclaringType,
|
||||||
|
TableGroupProducer declaringTableGroupProducer,
|
||||||
|
SelectableMappings selectableMappings,
|
||||||
|
EmbeddableValuedModelPart inverseModelPart,
|
||||||
|
EmbeddableMappingType embeddableTypeDescriptor,
|
||||||
|
MappingModelCreationProcess creationProcess) {
|
||||||
|
super(
|
||||||
|
keyDeclaringType,
|
||||||
|
declaringTableGroupProducer,
|
||||||
|
selectableMappings,
|
||||||
|
inverseModelPart,
|
||||||
|
embeddableTypeDescriptor,
|
||||||
|
creationProcess
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AttributeMapping copy(ManagedMappingType declaringType) {
|
||||||
|
return new VirtualEmbeddedAttributeMapping(
|
||||||
|
getAttributeName(),
|
||||||
|
getNavigableRole(),
|
||||||
|
getStateArrayPosition(),
|
||||||
|
getContainingTableExpression(),
|
||||||
|
getAttributeMetadataAccess(),
|
||||||
|
getParentInjectionAttributePropertyAccess(),
|
||||||
|
getTiming(),
|
||||||
|
getStyle(),
|
||||||
|
getEmbeddableTypeDescriptor(),
|
||||||
|
declaringType,
|
||||||
|
getPropertyAccess(),
|
||||||
|
getValueGeneration()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -167,6 +167,7 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.Queryable;
|
import org.hibernate.metamodel.mapping.Queryable;
|
||||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
|
@ -184,7 +185,6 @@ import org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor;
|
||||||
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||||
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.SimpleNaturalIdMapping;
|
import org.hibernate.metamodel.mapping.internal.SimpleNaturalIdMapping;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.metamodel.spi.EntityInstantiator;
|
import org.hibernate.metamodel.spi.EntityInstantiator;
|
||||||
|
@ -5023,7 +5023,7 @@ public abstract class AbstractEntityPersister
|
||||||
baseValueType = (ManagedMappingType) attributeMapping.getMappedType();
|
baseValueType = (ManagedMappingType) attributeMapping.getMappedType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( identifierMapping instanceof NonAggregatedIdentifierMappingImpl ) {
|
else if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) {
|
||||||
final EmbeddedAttributeMapping embeddedAttributeMapping = (EmbeddedAttributeMapping) findAttributeMapping( NavigableRole.IDENTIFIER_MAPPER_PROPERTY );
|
final EmbeddedAttributeMapping embeddedAttributeMapping = (EmbeddedAttributeMapping) findAttributeMapping( NavigableRole.IDENTIFIER_MAPPER_PROPERTY );
|
||||||
final AttributeMapping mapping = embeddedAttributeMapping.getMappedType()
|
final AttributeMapping mapping = embeddedAttributeMapping.getMappedType()
|
||||||
.findAttributeMapping( basePropertyName );
|
.findAttributeMapping( basePropertyName );
|
||||||
|
@ -6386,8 +6386,8 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModelPart getIdentifierModelPart(String name, EntityMappingType treatTargetType) {
|
private ModelPart getIdentifierModelPart(String name, EntityMappingType treatTargetType) {
|
||||||
if ( identifierMapping instanceof NonAggregatedIdentifierMappingImpl ) {
|
if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) {
|
||||||
final ModelPart subPart = ( (NonAggregatedIdentifierMappingImpl) identifierMapping ).findSubPart(
|
final ModelPart subPart = ( (NonAggregatedIdentifierMapping) identifierMapping ).findSubPart(
|
||||||
name,
|
name,
|
||||||
treatTargetType
|
treatTargetType
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,8 +28,8 @@ import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
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.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
|
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
@ -428,7 +428,7 @@ public class DomainResultCreationStateImpl
|
||||||
if ( fetchableContainer instanceof EntityValuedModelPart ) {
|
if ( fetchableContainer instanceof EntityValuedModelPart ) {
|
||||||
final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer;
|
final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer;
|
||||||
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
|
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
|
||||||
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMappingImpl;
|
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMapping;
|
||||||
final String identifierAttributeName = attributeName( identifierMapping );
|
final String identifierAttributeName = attributeName( identifierMapping );
|
||||||
if ( idClass ) {
|
if ( idClass ) {
|
||||||
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
|
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
|
||||||
|
|
|
@ -2842,6 +2842,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
querySpec.getFromClause().addRoot( tableGroup );
|
querySpec.getFromClause().addRoot( tableGroup );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Check if we can reuse a table group join of the parent
|
||||||
|
final TableGroup compatibleTableGroup = findCompatibleJoinedGroup(
|
||||||
|
actualParentTableGroup,
|
||||||
|
joinProducer,
|
||||||
|
defaultSqlAstJoinType
|
||||||
|
);
|
||||||
|
if ( compatibleTableGroup == null ) {
|
||||||
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
|
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
|
||||||
joinedPath.getNavigablePath(),
|
joinedPath.getNavigablePath(),
|
||||||
actualParentTableGroup,
|
actualParentTableGroup,
|
||||||
|
@ -2865,6 +2872,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
tableGroup = tableGroupJoin.getJoinedGroup();
|
tableGroup = tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
tableGroup = compatibleTableGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fromClauseIndex.register( joinedPath, tableGroup );
|
fromClauseIndex.register( joinedPath, tableGroup );
|
||||||
registerPluralTableGroupParts( tableGroup );
|
registerPluralTableGroupParts( tableGroup );
|
||||||
|
@ -2875,6 +2886,31 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
return tableGroup;
|
return tableGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TableGroup findCompatibleJoinedGroup(
|
||||||
|
TableGroup parentTableGroup,
|
||||||
|
TableGroupJoinProducer joinProducer,
|
||||||
|
SqlAstJoinType requestedJoinType) {
|
||||||
|
// We don't look into nested table group joins as that wouldn't be "compatible"
|
||||||
|
for ( TableGroupJoin join : parentTableGroup.getTableGroupJoins() ) {
|
||||||
|
// Compatibility obviously requires the same model part but also join type compatibility
|
||||||
|
// Note that if the requested join type is left, we can also use an existing inner join
|
||||||
|
// The other case, when the requested join type is inner and there is an existing left join,
|
||||||
|
// is not compatible though because the cardinality is different.
|
||||||
|
// We could reuse the join though if we alter the join type to INNER, but that's an optimization for later
|
||||||
|
final SqlAstJoinType joinType = join.getJoinType();
|
||||||
|
if ( join.getJoinedGroup().getModelPart() == joinProducer
|
||||||
|
&& ( requestedJoinType == joinType || requestedJoinType == SqlAstJoinType.LEFT && joinType == SqlAstJoinType.INNER ) ) {
|
||||||
|
// If there is an existing inner join, we can always use that as a new join can never produce results
|
||||||
|
// regardless of the join type or predicate since the LHS is the same table group
|
||||||
|
// If this is a left join though, we have to check if the predicate is simply the association predicate
|
||||||
|
if ( joinType == SqlAstJoinType.INNER || joinProducer.isSimpleJoinPredicate( join.getPredicate() ) ) {
|
||||||
|
return join.getJoinedGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void registerPluralTableGroupParts(TableGroup tableGroup) {
|
private void registerPluralTableGroupParts(TableGroup tableGroup) {
|
||||||
if ( tableGroup instanceof PluralTableGroup ) {
|
if ( tableGroup instanceof PluralTableGroup ) {
|
||||||
final PluralTableGroup pluralTableGroup = (PluralTableGroup) tableGroup;
|
final PluralTableGroup pluralTableGroup = (PluralTableGroup) tableGroup;
|
||||||
|
|
|
@ -7,11 +7,10 @@
|
||||||
package org.hibernate.query.sqm.sql.internal;
|
package org.hibernate.query.sqm.sql.internal;
|
||||||
|
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||||
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
|
||||||
import org.hibernate.sql.ast.SqlAstWalker;
|
import org.hibernate.sql.ast.SqlAstWalker;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
|
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
|
||||||
|
@ -31,7 +30,7 @@ public class NonAggregatedCompositeValuedPathInterpretation<T>
|
||||||
final TableGroup tableGroup = sqlAstCreationState
|
final TableGroup tableGroup = sqlAstCreationState
|
||||||
.getFromClauseAccess()
|
.getFromClauseAccess()
|
||||||
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||||
final NonAggregatedIdentifierMappingImpl mapping = (NonAggregatedIdentifierMappingImpl) tableGroup.getModelPart()
|
final NonAggregatedIdentifierMapping mapping = (NonAggregatedIdentifierMapping) tableGroup.getModelPart()
|
||||||
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
|
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
|
||||||
|
|
||||||
return new NonAggregatedCompositeValuedPathInterpretation<>(
|
return new NonAggregatedCompositeValuedPathInterpretation<>(
|
||||||
|
|
|
@ -3912,6 +3912,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
||||||
tableGroupJoinCollector
|
tableGroupJoinCollector
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// A lazy table group, even if uninitialized, might contain table group joins
|
||||||
|
else if ( joinedGroup instanceof LazyTableGroup ) {
|
||||||
|
processNestedTableGroupJoins( joinedGroup, tableGroupJoinCollector );
|
||||||
|
if ( tableGroupJoinCollector != null ) {
|
||||||
|
tableGroupJoinCollector.addAll( joinedGroup.getTableGroupJoins() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processTableGroupJoins( joinedGroup );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
|
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ast.tree.from;
|
package org.hibernate.sql.ast.tree.from;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
@ -36,6 +37,8 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
||||||
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 BiPredicate<NavigablePath, String> navigablePathChecker;
|
||||||
|
private List<TableGroupJoin> tableGroupJoins;
|
||||||
|
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||||
private Consumer<TableGroup> tableGroupConsumer;
|
private Consumer<TableGroup> tableGroupConsumer;
|
||||||
private TableGroup tableGroup;
|
private TableGroup tableGroup;
|
||||||
|
|
||||||
|
@ -72,6 +75,18 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
tableGroup = tableGroupSupplier.get();
|
tableGroup = tableGroupSupplier.get();
|
||||||
|
if ( tableGroupJoins != null ) {
|
||||||
|
for ( TableGroupJoin tableGroupJoin : tableGroupJoins ) {
|
||||||
|
tableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
}
|
||||||
|
tableGroupJoins = null;
|
||||||
|
}
|
||||||
|
if ( nestedTableGroupJoins != null ) {
|
||||||
|
for ( TableGroupJoin tableGroupJoin : nestedTableGroupJoins ) {
|
||||||
|
tableGroup.addNestedTableGroupJoin( tableGroupJoin );
|
||||||
|
}
|
||||||
|
nestedTableGroupJoins = null;
|
||||||
|
}
|
||||||
if ( tableGroupConsumer != null ) {
|
if ( tableGroupConsumer != null ) {
|
||||||
tableGroupConsumer.accept( tableGroup );
|
tableGroupConsumer.accept( tableGroup );
|
||||||
tableGroupConsumer = null;
|
tableGroupConsumer = null;
|
||||||
|
@ -102,24 +117,70 @@ public class LazyTableGroup extends DelegatingTableGroup {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TableGroupJoin> getTableGroupJoins() {
|
public List<TableGroupJoin> getTableGroupJoins() {
|
||||||
return tableGroup == null ? Collections.emptyList() : tableGroup.getTableGroupJoins();
|
if ( tableGroup == null ) {
|
||||||
|
return nestedTableGroupJoins == null ? Collections.emptyList() : nestedTableGroupJoins;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return tableGroup.getTableGroupJoins();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||||
return tableGroup == null ? Collections.emptyList() : tableGroup.getNestedTableGroupJoins();
|
if ( tableGroup == null ) {
|
||||||
|
return tableGroupJoins == null ? Collections.emptyList() : tableGroupJoins;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return tableGroup.getNestedTableGroupJoins();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTableGroupJoin(TableGroupJoin join) {
|
||||||
|
if ( tableGroup == null ) {
|
||||||
|
if ( tableGroupJoins == null ) {
|
||||||
|
tableGroupJoins = new ArrayList<>();
|
||||||
|
}
|
||||||
|
tableGroupJoins.add( join );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getTableGroup().addTableGroupJoin( join );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||||
|
if ( tableGroup == null ) {
|
||||||
|
if ( nestedTableGroupJoins == null ) {
|
||||||
|
nestedTableGroupJoins = new ArrayList<>();
|
||||||
|
}
|
||||||
|
nestedTableGroupJoins.add( join );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getTableGroup().addNestedTableGroupJoin( join );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||||
if ( tableGroup != null ) {
|
if ( tableGroup == null ) {
|
||||||
|
if ( tableGroupJoins != null ) {
|
||||||
|
tableGroupJoins.forEach( consumer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
tableGroup.visitTableGroupJoins( consumer );
|
tableGroup.visitTableGroupJoins( consumer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||||
if ( tableGroup != null ) {
|
if ( tableGroup == null ) {
|
||||||
|
if ( nestedTableGroupJoins != null ) {
|
||||||
|
nestedTableGroupJoins.forEach( consumer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
tableGroup.visitNestedTableGroupJoins( consumer );
|
tableGroup.visitNestedTableGroupJoins( consumer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
||||||
|
|
||||||
SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup);
|
SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup);
|
||||||
|
|
||||||
|
boolean isSimpleJoinPredicate(Predicate predicate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a TableGroupJoin as defined for this producer
|
* Create a TableGroupJoin as defined for this producer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
|
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.metamodel.EmbeddableRepresentationStrategy;
|
import org.hibernate.metamodel.EmbeddableRepresentationStrategy;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
|
@ -34,8 +35,6 @@ import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
import org.hibernate.sql.results.internal.NullValueAssembler;
|
import org.hibernate.sql.results.internal.NullValueAssembler;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
import org.hibernate.type.descriptor.java.spi.EntityJavaTypeDescriptor;
|
|
||||||
|
|
||||||
import static java.lang.Boolean.FALSE;
|
import static java.lang.Boolean.FALSE;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
@ -231,17 +230,12 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling for non-aggregated attributes which use the actual entity instance as container,
|
// Virtual model parts use the owning entity as container which the fetch parent access provides.
|
||||||
// which we access through the fetch parent access.
|
// For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
|
||||||
// If this model part is an identifier, we must construct the instance as this is called during resolveKey
|
// so we can't use the fetch parent access in that case.
|
||||||
final EmbeddableMappingType embeddableTypeDescriptor = embedded.getEmbeddableTypeDescriptor();
|
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart
|
||||||
final JavaType<?> embeddableJtd = embeddableTypeDescriptor.getMappedJavaTypeDescriptor();
|
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() )
|
||||||
|
&& !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) ) {
|
||||||
if ( fetchParentAccess != null &&
|
|
||||||
embeddableJtd.getJavaTypeClass().isAssignableFrom( fetchParentAccess.getInitializedPart().getJavaTypeDescriptor().getJavaTypeClass() )
|
|
||||||
&& embeddableJtd instanceof EntityJavaTypeDescriptor<?>
|
|
||||||
&& !( embedded instanceof CompositeIdentifierMapping )
|
|
||||||
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() ) ) {
|
|
||||||
fetchParentAccess.resolveInstance( processingState );
|
fetchParentAccess.resolveInstance( processingState );
|
||||||
compositeInstance = fetchParentAccess.getInitializedInstance();
|
compositeInstance = fetchParentAccess.getInitializedInstance();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph.embeddable;
|
||||||
|
|
||||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
|
|
||||||
|
@ -19,4 +20,9 @@ public interface EmbeddableValuedFetchable extends EmbeddableValuedModelPart, Fe
|
||||||
default SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
default SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
||||||
return SqlAstJoinType.LEFT;
|
return SqlAstJoinType.LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean isSimpleJoinPredicate(Predicate predicate) {
|
||||||
|
return predicate == null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,8 +112,11 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
|
||||||
public NavigablePath resolveNavigablePath(Fetchable fetchable) {
|
public NavigablePath resolveNavigablePath(Fetchable fetchable) {
|
||||||
if ( fetchable instanceof TableGroupProducer ) {
|
if ( fetchable instanceof TableGroupProducer ) {
|
||||||
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
|
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
|
||||||
if ( tableGroupJoin.getJoinedGroup().isFetched() && tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
|
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
|
||||||
return tableGroupJoin.getNavigablePath();
|
if ( tableGroupJoin.getJoinedGroup().isFetched()
|
||||||
|
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() )
|
||||||
|
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
|
||||||
|
return navigablePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,11 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E
|
||||||
if ( fetchable instanceof TableGroupProducer &&
|
if ( fetchable instanceof TableGroupProducer &&
|
||||||
!getNavigablePath().getUnaliasedLocalName().equals( getNavigablePath().getLocalName() ) ) {
|
!getNavigablePath().getUnaliasedLocalName().equals( getNavigablePath().getLocalName() ) ) {
|
||||||
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
|
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
|
||||||
if ( tableGroupJoin.getJoinedGroup().isFetched() && tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
|
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
|
||||||
return tableGroupJoin.getNavigablePath();
|
if ( tableGroupJoin.getJoinedGroup().isFetched()
|
||||||
|
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() )
|
||||||
|
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
|
||||||
|
return navigablePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.hibernate.test.hql;
|
package org.hibernate.orm.test.hql;
|
||||||
|
|
||||||
import org.hibernate.annotations.NaturalId;
|
import org.hibernate.annotations.NaturalId;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
@ -15,6 +15,7 @@ import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -66,9 +67,21 @@ public class NaturalIdDereferenceTest {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void deleteData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from BookRefRef" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from BookRef" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Book" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void naturalIdDereferenceTest(SessionFactoryScope scope) {
|
public void naturalIdDereferenceTest(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r.normalBook.isbn FROM BookRef r" );
|
Query query = session.createQuery( "SELECT r.normalBook.isbn FROM BookRef r" );
|
||||||
|
@ -83,6 +96,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void normalIdDereferenceFromAlias(SessionFactoryScope scope) {
|
public void normalIdDereferenceFromAlias(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r.normalBook.id FROM BookRef r" );
|
Query query = session.createQuery( "SELECT r.normalBook.id FROM BookRef r" );
|
||||||
|
@ -97,6 +111,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void naturalIdDereferenceFromAlias(SessionFactoryScope scope) {
|
public void naturalIdDereferenceFromAlias(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r.naturalBook.isbn FROM BookRef r" );
|
Query query = session.createQuery( "SELECT r.naturalBook.isbn FROM BookRef r" );
|
||||||
|
@ -111,6 +126,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void normalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
|
public void normalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook.id FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook.id FROM BookRefRef r2" );
|
||||||
|
@ -124,6 +140,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void naturalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
|
public void naturalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.normalBookRef.naturalBook.isbn FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.normalBookRef.naturalBook.isbn FROM BookRefRef r2" );
|
||||||
|
@ -142,6 +159,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void nestedNaturalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
|
public void nestedNaturalIdDereferenceFromImplicitJoin(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook.isbn FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook.isbn FROM BookRefRef r2" );
|
||||||
|
@ -159,6 +177,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void nestedNaturalIdDereferenceFromImplicitJoin2(SessionFactoryScope scope) {
|
public void nestedNaturalIdDereferenceFromImplicitJoin2(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook.id FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook.id FROM BookRefRef r2" );
|
||||||
|
@ -172,6 +191,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void doNotDereferenceNaturalIdIfIsReferenceToPrimaryKey(SessionFactoryScope scope) {
|
public void doNotDereferenceNaturalIdIfIsReferenceToPrimaryKey(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook.isbn FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook.isbn FROM BookRefRef r2" );
|
||||||
|
@ -185,6 +205,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void selectedEntityIsNotDereferencedForPrimaryKey(SessionFactoryScope scope) {
|
public void selectedEntityIsNotDereferencedForPrimaryKey(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.normalBookRef.normalBook FROM BookRefRef r2" );
|
||||||
|
@ -209,6 +230,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void selectedEntityIsNotDereferencedForNaturalId(SessionFactoryScope scope) {
|
public void selectedEntityIsNotDereferencedForNaturalId(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook FROM BookRefRef r2" );
|
Query query = session.createQuery( "SELECT r2.naturalBookRef.naturalBook FROM BookRefRef r2" );
|
||||||
|
@ -228,6 +250,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void dereferenceNaturalIdInJoin(SessionFactoryScope scope) {
|
public void dereferenceNaturalIdInJoin(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery(
|
Query query = session.createQuery(
|
||||||
|
@ -251,6 +274,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void dereferenceNaturalIdInJoin2(SessionFactoryScope scope) {
|
public void dereferenceNaturalIdInJoin2(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery( "SELECT b.normalBook FROM BookRefRef a " +
|
Query query = session.createQuery( "SELECT b.normalBook FROM BookRefRef a " +
|
||||||
|
@ -271,6 +295,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void dereferenceNaturalIdInJoin3(SessionFactoryScope scope) {
|
public void dereferenceNaturalIdInJoin3(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery(
|
Query query = session.createQuery(
|
||||||
|
@ -292,6 +317,7 @@ public class NaturalIdDereferenceTest {
|
||||||
@Test
|
@Test
|
||||||
public void dereferenceNaturalIdInJoin4(SessionFactoryScope scope) {
|
public void dereferenceNaturalIdInJoin4(SessionFactoryScope scope) {
|
||||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
|
sqlStatementInterceptor.clear();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Query query = session.createQuery(
|
Query query = session.createQuery(
|
Loading…
Reference in New Issue