HHH-13769: Avoid unnecessary joins

better support for lazy TableReference handling for collections
This commit is contained in:
Steve Ebersole 2019-12-10 14:13:41 -06:00
parent becbaea172
commit dcbef8705c
18 changed files with 477 additions and 450 deletions

View File

@ -6,11 +6,6 @@
*/
package org.hibernate.metamodel.mapping;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.Fetchable;
/**
@ -67,6 +62,4 @@ public interface CollectionPart extends ModelPart, Fetchable {
default String getPartName() {
return getNature().getName();
}
void applyPrimaryTableReference(TableGroupBuilder tableGroupBuilder, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext);
}

View File

@ -19,21 +19,17 @@ import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.ResultsLogger;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -78,14 +74,6 @@ public class BasicValuedCollectionPart implements CollectionPart, BasicValuedMod
return mapper;
}
@Override
public void applyPrimaryTableReference(
TableGroupBuilder tableGroupBuilder,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
// nothing to do
}
@Override
public String getContainingTableExpression() {
return tableExpression;

View File

@ -23,13 +23,12 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -78,14 +77,6 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
return type;
}
@Override
public void applyPrimaryTableReference(
TableGroupBuilder tableGroupBuilder,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
// nothing to do
}
@Override
public JdbcMapping getJdbcMapping() {
return type;

View File

@ -34,7 +34,6 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
@ -198,13 +197,6 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
// nothing to do
}
@Override
public void applyPrimaryTableReference(
TableGroupBuilder tableGroupBuilder,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
}
@Override
public TableReference createPrimaryTableReference(
SqlAliasBase sqlAliasBase,

View File

@ -10,22 +10,16 @@ import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchParent;
@ -42,7 +36,6 @@ public class EntityCollectionPart implements CollectionPart, EntityAssociationMa
private final Nature nature;
private final EntityMappingType entityMappingType;
private ForeignKeyDescriptor foreignKeyDescriptor;
private ModelPart fkTargetModelPart;
@SuppressWarnings("WeakerAccess")
@ -50,24 +43,20 @@ public class EntityCollectionPart implements CollectionPart, EntityAssociationMa
Nature nature,
Value bootModelValue,
EntityMappingType entityMappingType,
String fkTargetModelPartName,
MappingModelCreationProcess creationProcess) {
this.nature = nature;
this.entityMappingType = entityMappingType;
creationProcess.registerInitializationCallback(
() -> {
fkTargetModelPart = fkTargetModelPartName == null
? entityMappingType.getIdentifierMapping()
: entityMappingType.findSubPart( fkTargetModelPartName, entityMappingType );
assert fkTargetModelPart != null;
return true;
}
);
}
public void finishInitialization(
CollectionPersister collectionDescriptor,
Collection bootValueMapping,
String fkTargetModelPartName,
MappingModelCreationProcess creationProcess) {
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
}
@Override
public Nature getNature() {
return nature;
@ -78,24 +67,6 @@ public class EntityCollectionPart implements CollectionPart, EntityAssociationMa
return getEntityMappingType();
}
@Override
public void applyPrimaryTableReference(
TableGroupBuilder tableGroupBuilder,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
tableGroupBuilder.applySecondaryTableReferences(
getEntityMappingType().createPrimaryTableReference( tableGroupBuilder.getSqlAliasBase(), sqlExpressionResolver, creationContext ),
SqlAstJoinType.LEFT,
(lhs, rhs, sqlAstJoinType) -> foreignKeyDescriptor.generateJoinPredicate(
lhs,
rhs,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
);
}
@Override
public EntityMappingType getEntityMappingType() {
return entityMappingType;

View File

@ -719,6 +719,7 @@ public class MappingModelCreationHelper {
dialect,
creationProcess
);
final CollectionPart indexDescriptor;
CollectionIdentifierDescriptor identifierDescriptor = null;
@ -882,7 +883,7 @@ public class MappingModelCreationHelper {
sessionFactory
);
return new PluralAttributeMappingImpl(
final PluralAttributeMappingImpl pluralAttributeMapping = new PluralAttributeMappingImpl(
attrName,
bootValueMapping,
propertyAccess,
@ -905,6 +906,22 @@ public class MappingModelCreationHelper {
declaringType,
collectionDescriptor
);
creationProcess.registerInitializationCallback(
() -> {
try {
pluralAttributeMapping.finishInitialization( bootProperty, bootValueMapping, creationProcess );
return true;
}
catch (NotYetImplementedFor6Exception nye) {
throw nye;
}
catch (Exception wait) {
return false;
}
}
);
return pluralAttributeMapping;
}
private static ForeignKeyDescriptor interpretKeyDescriptor(
@ -1095,29 +1112,38 @@ public class MappingModelCreationHelper {
}
if ( bootMapKeyDescriptor instanceof OneToMany || bootMapKeyDescriptor instanceof ToOne ) {
final EntityPersister associatedEntity;
if ( bootMapKeyDescriptor instanceof OneToMany ) {
associatedEntity = creationProcess.getEntityPersister(
( (OneToMany) bootMapKeyDescriptor ).getReferencedEntityName()
);
}
else {
// many-to-many
associatedEntity = creationProcess.getEntityPersister(
( (ToOne) bootMapKeyDescriptor ).getReferencedEntityName()
);
}
final EntityType indexEntityType = (EntityType) collectionDescriptor.getIndexType();
final EntityPersister associatedEntity = creationProcess.getEntityPersister( indexEntityType.getAssociatedEntityName() );
return new EntityCollectionPart(
CollectionPart.Nature.ELEMENT,
bootValueMapping.getElement(),
final EntityCollectionPart indexDescriptor = new EntityCollectionPart(
CollectionPart.Nature.INDEX,
bootMapKeyDescriptor,
associatedEntity,
indexEntityType.getRHSUniqueKeyPropertyName(),
creationProcess
);
creationProcess.registerInitializationCallback(
() -> {
try {
indexDescriptor.finishInitialization(
collectionDescriptor,
bootValueMapping,
indexEntityType.getRHSUniqueKeyPropertyName(),
creationProcess
);
return true;
}
catch (NotYetImplementedFor6Exception nye) {
throw nye;
}
catch (Exception wait) {
return false;
}
}
);
return indexDescriptor;
}
throw new NotYetImplementedFor6Exception(
@ -1176,29 +1202,38 @@ public class MappingModelCreationHelper {
}
if ( element instanceof OneToMany || element instanceof ToOne ) {
final EntityPersister associatedEntity;
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
final EntityPersister associatedEntity = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );
if ( element instanceof OneToMany ) {
associatedEntity = creationProcess.getEntityPersister(
( (OneToMany) element ).getReferencedEntityName()
);
}
else {
// many-to-many
associatedEntity = creationProcess.getEntityPersister(
( (ToOne) element ).getReferencedEntityName()
);
}
final EntityType indexEntityType = (EntityType) collectionDescriptor.getElementType();
return new EntityCollectionPart(
final EntityCollectionPart elementDescriptor = new EntityCollectionPart(
CollectionPart.Nature.ELEMENT,
bootDescriptor.getElement(),
associatedEntity,
indexEntityType.getRHSUniqueKeyPropertyName(),
creationProcess
);
creationProcess.registerInitializationCallback(
() -> {
try {
elementDescriptor.finishInitialization(
collectionDescriptor,
bootDescriptor,
elementEntityType.getRHSUniqueKeyPropertyName(),
creationProcess
);
return true;
}
catch (NotYetImplementedFor6Exception nye) {
throw nye;
}
catch (Exception wait) {
return false;
}
}
);
return elementDescriptor;
}
throw new NotYetImplementedFor6Exception(

View File

@ -82,6 +82,11 @@ public class MappingModelCreationProcess {
postInitCallbacks.remove( callback );
}
}
if ( copy.size() == postInitCallbacks.size() ) {
// none of the processes could complete fully, this is an error
throw new IllegalStateException( "No post-init callbacks could complete" );
}
}
}

View File

@ -6,16 +6,22 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.List;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionMappingType;
import org.hibernate.metamodel.mapping.CollectionPart;
@ -26,6 +32,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
@ -36,8 +43,8 @@ import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
@ -50,11 +57,14 @@ import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResult;
import org.hibernate.sql.results.graph.collection.internal.DelayedCollectionFetch;
import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
/**
* @author Steve Ebersole
*/
public class PluralAttributeMappingImpl extends AbstractAttributeMapping implements PluralAttributeMapping {
public interface Aware {
void injectAttributeMapping(PluralAttributeMapping attributeMapping);
}
@ -78,6 +88,8 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
private final IndexMetadata indexMetadata;
private ForeignKeyDescriptor manyToManyFkDescriptor;
@SuppressWarnings("WeakerAccess")
public PluralAttributeMappingImpl(
String attributeName,
@ -152,6 +164,56 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
}
}
public void finishInitialization(
Property bootProperty,
Collection bootDescriptor,
MappingModelCreationProcess creationProcess) {
if ( collectionDescriptor.getElementType() instanceof EntityType
|| collectionDescriptor.getIndexType() instanceof EntityType ) {
final EntityPersister associatedEntityDescriptor;
final ModelPart fkTargetPart;
final Value fkBootDescriptorSource;
if ( collectionDescriptor.getElementType() instanceof EntityType ) {
final EntityType elementEntityType = (EntityType) collectionDescriptor.getElementType();
associatedEntityDescriptor = creationProcess.getEntityPersister( elementEntityType.getAssociatedEntityName() );
fkTargetPart = elementEntityType.isReferenceToPrimaryKey()
? associatedEntityDescriptor.getIdentifierMapping()
: associatedEntityDescriptor.findSubPart( elementEntityType.getRHSUniqueKeyPropertyName() );
fkBootDescriptorSource = bootDescriptor.getElement();
}
else {
assert collectionDescriptor.getIndexType() != null;
assert bootDescriptor instanceof IndexedCollection;
final EntityType indexEntityType = (EntityType) collectionDescriptor.getIndexType();
associatedEntityDescriptor = creationProcess.getEntityPersister( indexEntityType.getAssociatedEntityName() );
fkTargetPart = indexEntityType.isReferenceToPrimaryKey()
? associatedEntityDescriptor.getIdentifierMapping()
: associatedEntityDescriptor.findSubPart( indexEntityType.getRHSUniqueKeyPropertyName() );
fkBootDescriptorSource = ( (IndexedCollection) bootDescriptor ).getIndex();
}
if ( fkTargetPart instanceof BasicValuedModelPart ) {
final BasicValuedModelPart basicFkTargetPart = (BasicValuedModelPart) fkTargetPart;
final Joinable collectionDescriptorAsJoinable = (Joinable) collectionDescriptor;
manyToManyFkDescriptor = new SimpleForeignKeyDescriptor(
ForeignKeyDirection.TO_PARENT,
collectionDescriptorAsJoinable.getTableName(),
fkBootDescriptorSource.getColumnIterator().next().getText(),
basicFkTargetPart.getContainingTableExpression(),
basicFkTargetPart.getMappedColumnExpression(),
basicFkTargetPart.getJdbcMapping()
);
}
else {
throw new NotYetImplementedFor6Exception(
"Support for composite foreign keys not yet implemented : " + collectionDescriptor.getRole()
);
}
}
}
@Override
public CollectionMappingType getMappedTypeDescriptor() {
return (CollectionMappingType) super.getMappedTypeDescriptor();
@ -301,41 +363,51 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final String aliasRoot = explicitSourceAlias == null ? sqlAliasStem : explicitSourceAlias;
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( aliasRoot );
final TableGroupBuilder tableGroupBuilder = TableGroupBuilder.builder(
final CollectionPersister collectionDescriptor = getCollectionDescriptor();
if ( collectionDescriptor.isOneToMany() ) {
return createOneToManyTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
lockMode,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
else {
return createCollectionTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
lockMode,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
}
private TableGroupJoin createOneToManyTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = createOneToManyTableGroup(
navigablePath,
this,
sqlAstJoinType == SqlAstJoinType.INNER
&& ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
lockMode,
sqlAliasBase,
(tableExpression, tableGroup) -> createTableReferenceJoin(
tableExpression,
sqlAliasBase,
tableGroup.getPrimaryTableReference(),
sqlAstJoinType == SqlAstJoinType.INNER && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
sqlExpressionResolver,
creationContext
),
creationContext.getSessionFactory()
);
tableGroupBuilder.applyPrimaryReference(
// returns null when there is no "collection table"
getCollectionDescriptor().createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
)
);
elementDescriptor.applyPrimaryTableReference(
tableGroupBuilder,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroup tableGroup = tableGroupBuilder.build();
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
@ -354,19 +426,188 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
return tableGroupJoin;
}
private TableGroup createOneToManyTableGroup(
NavigablePath navigablePath,
boolean canUseInnerJoins,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final EntityCollectionPart entityPartDescriptor;
if ( elementDescriptor instanceof EntityCollectionPart ) {
entityPartDescriptor = (EntityCollectionPart) elementDescriptor;
}
else {
assert indexDescriptor instanceof EntityCollectionPart;
entityPartDescriptor = (EntityCollectionPart) indexDescriptor;
}
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
final TableReference primaryTableReference = entityPartDescriptor.getEntityMappingType().createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
return new StandardTableGroup(
navigablePath,
this,
lockMode,
primaryTableReference,
sqlAliasBase,
(tableExpression, tg) -> createTableReferenceJoin(
tableExpression,
sqlAliasBase,
primaryTableReference,
canUseInnerJoins,
sqlExpressionResolver,
creationContext
),
creationContext.getSessionFactory()
);
}
private TableGroupJoin createCollectionTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = createCollectionTableGroup(
navigablePath,
sqlAstJoinType == SqlAstJoinType.INNER
&& !getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
lockMode,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
tableGroup,
getKeyDescriptor().generateJoinPredicate(
lhs,
tableGroup,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
);
lhs.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin;
}
private TableGroup createCollectionTableGroup(
NavigablePath navigablePath,
boolean canUseInnerJoin,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
assert ! getCollectionDescriptor().isOneToMany();
final String collectionTableName = ( (Joinable) collectionDescriptor ).getTableName();
final TableReference collectionTableReference = new TableReference(
collectionTableName,
sqlAliasBase.generateNewAlias(),
true,
creationContext.getSessionFactory()
);
final Consumer<TableGroup> tableGroupFinalizer;
final BiFunction<String,TableGroup,TableReferenceJoin> tableReferenceJoinCreator;
if ( elementDescriptor instanceof EntityCollectionPart || indexDescriptor instanceof EntityCollectionPart ) {
final EntityCollectionPart entityPartDescriptor;
if ( elementDescriptor instanceof EntityCollectionPart ) {
entityPartDescriptor = (EntityCollectionPart) elementDescriptor;
}
else {
entityPartDescriptor = (EntityCollectionPart) indexDescriptor;
}
final EntityMappingType mappingType = entityPartDescriptor.getEntityMappingType();
final TableReference associatedPrimaryTable = mappingType.createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
tableReferenceJoinCreator = (tableExpression, tableGroup) -> createTableReferenceJoin(
tableExpression,
sqlAliasBase,
associatedPrimaryTable,
canUseInnerJoin && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
sqlExpressionResolver,
creationContext
);
tableGroupFinalizer = tableGroup -> {
final SqlAstJoinType joinType = canUseInnerJoin && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable()
? SqlAstJoinType.INNER
: SqlAstJoinType.LEFT;
final TableReferenceJoin associationJoin = new TableReferenceJoin(
joinType,
associatedPrimaryTable,
manyToManyFkDescriptor.generateJoinPredicate(
collectionTableReference,
associatedPrimaryTable,
joinType,
sqlExpressionResolver,
creationContext
)
);
( (StandardTableGroup) tableGroup ).addTableReferenceJoin( associationJoin );
};
}
else {
tableReferenceJoinCreator = (tableExpression, tableGroup) -> {
throw new UnsupportedOperationException(
"element-collection cannot contain joins : " + collectionTableReference.getTableExpression() + " -> " + tableExpression
);
};
tableGroupFinalizer = null;
}
final StandardTableGroup tableGroup = new StandardTableGroup(
navigablePath,
this,
lockMode,
collectionTableReference,
sqlAliasBase,
tableReferenceJoinCreator,
creationContext.getSessionFactory()
);
if ( tableGroupFinalizer != null ) {
tableGroupFinalizer.accept( tableGroup );
}
return tableGroup;
}
@Override
public TableReferenceJoin createTableReferenceJoin(
String joinTableExpression,
SqlAliasBase sqlAliasBase,
TableReference lhs,
boolean sqlAstJoinType,
boolean canUseInnerJoin,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return getCollectionDescriptor().createTableReferenceJoin(
joinTableExpression,
sqlAliasBase,
lhs,
sqlAstJoinType,
canUseInnerJoin,
sqlExpressionResolver,
creationContext
);
@ -410,62 +651,26 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
SqlExpressionResolver sqlExpressionResolver,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
final TableGroupBuilder tableGroupBuilder = TableGroupBuilder.builder(
navigablePath,
this,
lockMode,
sqlAliasBase,
(tableExpression, tableGroup) -> createTableReferenceJoin(
tableExpression,
sqlAliasBase,
tableGroup.getPrimaryTableReference(),
canUseInnerJoins && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
sqlExpressionResolver,
creationContext
),
creationContext.getSessionFactory()
);
getElementDescriptor().applyPrimaryTableReference(
tableGroupBuilder,
sqlExpressionResolver,
creationContext
);
if ( getIndexDescriptor() != null ) {
getIndexDescriptor().applyPrimaryTableReference(
tableGroupBuilder,
if ( getCollectionDescriptor().isOneToMany() ) {
return createOneToManyTableGroup(
navigablePath,
canUseInnerJoins,
lockMode,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
final TableReference collectionTableReference = getCollectionDescriptor().createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
if ( collectionTableReference != null ) {
tableGroupBuilder.applySecondaryTableReferences(
collectionTableReference,
canUseInnerJoins && ! getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable()
? SqlAstJoinType.INNER
: SqlAstJoinType.LEFT,
(lhs, rhs, sqlAstJoinType) -> fkDescriptor.generateJoinPredicate(
lhs,
rhs,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
else {
return createCollectionTableGroup(
navigablePath,
canUseInnerJoins,
lockMode,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
return tableGroupBuilder.build();
}
@Override

View File

@ -28,8 +28,8 @@ import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
@ -207,15 +207,22 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
final String aliasRoot = explicitSourceAlias == null ? sqlAliasStem : explicitSourceAlias;
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( aliasRoot );
final TableGroupBuilder tableGroupBuilder = TableGroupBuilder.builder(
final TableReference primaryTableReference = createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
final TableGroup tableGroup = new StandardTableGroup(
navigablePath,
this,
lockMode,
primaryTableReference,
sqlAliasBase,
(tableExpression, tableGroup) -> createTableReferenceJoin(
(tableExpression, tg) -> createTableReferenceJoin(
tableExpression,
sqlAliasBase,
tableGroup.getPrimaryTableReference(),
primaryTableReference,
false,
sqlExpressionResolver,
creationContext
@ -223,25 +230,6 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
creationContext.getSessionFactory()
);
tableGroupBuilder.applyPrimaryReference(
getEntityMappingType().createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
)
);
// applyTableReferences(
// sqlAliasBase,
// joinType,
// tableGroupBuilder,
// sqlExpressionResolver,
// creationContext
// );
getMappedTypeDescriptor().getIdentifierMapping();
final TableGroup tableGroup = tableGroupBuilder.build();
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,

View File

@ -1882,6 +1882,10 @@ public abstract class AbstractCollectionPersister
return elementPersister;
}
protected EntityPersister getElementPersisterInternal() {
return elementPersister;
}
@Override
public boolean isCollection() {
return true;
@ -2468,65 +2472,6 @@ public abstract class AbstractCollectionPersister
return false;
}
@Override
public TableReference createPrimaryTableReference(
SqlAliasBase sqlAliasBase,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
if ( qualifiedTableName != null && ! isOneToMany() ) {
return new TableReference(
qualifiedTableName,
sqlAliasBase.generateNewAlias(),
false,
getFactory()
);
}
return null;
}
@Override
public TableReferenceJoin createTableReferenceJoin(
String joinTableExpression,
SqlAliasBase sqlAliasBase,
TableReference lhs,
boolean canUseInnerJoin,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
if ( elementPersister == null ) {
return null;
}
final String entityPrimaryTableName = ( (Joinable) elementPersister ).getTableName();
if ( entityPrimaryTableName.equals( joinTableExpression ) ) {
assert qualifiedTableName != null;
assert lhs.getTableExpression().equals( qualifiedTableName );
final TableReference tableReference = elementPersister.createPrimaryTableReference( sqlAliasBase, sqlExpressionResolver, creationContext );
final SqlAstJoinType sqlAstJoinType = canUseInnerJoin ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT;
return new TableReferenceJoin(
sqlAstJoinType,
tableReference,
generateEntityElementJoinPredicate(
lhs,
tableReference,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
);
}
return elementPersister.createTableReferenceJoin(
joinTableExpression,
sqlAliasBase,
lhs,
canUseInnerJoin,
sqlExpressionResolver,
creationContext
);
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
@ -2713,10 +2658,6 @@ public abstract class AbstractCollectionPersister
SqlAstCreationContext creationContext) {
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
// `lhs` should be the collection table
// `rhs` should be the primary element table
assert lhs.getTableExpression().equals( getTableName() );
final String fkTargetModelPartName = getCollectionType().getRHSUniqueKeyPropertyName();
final ModelPart fkTargetDescriptor;
if ( fkTargetModelPartName != null ) {

View File

@ -15,6 +15,7 @@ import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.collection.spi.PersistentCollection;
@ -26,6 +27,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.mapping.Collection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.pretty.MessageHelper;
@ -33,6 +35,12 @@ import org.hibernate.sql.Delete;
import org.hibernate.sql.Insert;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.Update;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.type.AssociationType;
/**

View File

@ -24,11 +24,17 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.mapping.Collection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Update;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
/**
* Collection persister for one-to-many associations.
@ -67,6 +73,43 @@ public class OneToManyPersister extends AbstractCollectionPersister {
keyIsUpdateable = collectionBinding.getKey().isUpdateable();
}
@Override
public TableReference createPrimaryTableReference(
SqlAliasBase sqlAliasBase,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
// for a one-to-many, the "primary table" is the primary table of the associated entity
final EntityPersister elementPersister = getElementPersister();
assert elementPersister != null;
return elementPersister.createPrimaryTableReference( sqlAliasBase, sqlExpressionResolver, creationContext );
}
@Override
public TableReferenceJoin createTableReferenceJoin(
String joinTableExpression,
SqlAliasBase sqlAliasBase,
TableReference lhs,
boolean canUseInnerJoin,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final EntityPersister elementPersister = getElementPersister();
assert elementPersister != null;
assert qualifiedTableName != null;
assert lhs.getTableExpression().equals( qualifiedTableName );
assert lhs.getTableExpression().equals( ( (Joinable) elementPersister ).getTableName() );
return elementPersister.createTableReferenceJoin(
joinTableExpression,
sqlAliasBase,
lhs,
canUseInnerJoin,
sqlExpressionResolver,
creationContext
);
}
/**
* Generate the SQL UPDATE that updates all the foreign keys to null
*/

View File

@ -181,8 +181,8 @@ import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
@ -1225,10 +1225,17 @@ public abstract class AbstractEntityPersister
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
final TableGroupBuilder builder = TableGroupBuilder.builder(
final TableReference primaryTableReference = createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
return new StandardTableGroup(
navigablePath,
this,
lockMode,
primaryTableReference,
sqlAliasBase,
(tableExpression, tableGroup) -> {
for ( int i = 0; i < getSubclassTableSpan(); i++ ) {
@ -1251,7 +1258,7 @@ public abstract class AbstractEntityPersister
),
joinedTableReference,
generateJoinPredicate(
tableGroup.getPrimaryTableReference(),
primaryTableReference,
joinedTableReference,
i,
sqlExpressionResolver
@ -1262,27 +1269,8 @@ public abstract class AbstractEntityPersister
return null;
},
creationContext.getSessionFactory()
getFactory()
);
builder.applyPrimaryReference(
createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
)
);
// applyTableReferences(
// sqlAliasBase,
// tableReferenceJoinType,
// builder,
// sqlExpressionResolver,
// creationContext
// );
return builder.build();
}
@Override

View File

@ -166,7 +166,6 @@ public final class ExecuteWithIdTableHelper {
idTableReference,
Collections.emptyList(),
null,
null,
executionContext.getSession().getFactory()
);

View File

@ -47,7 +47,6 @@ public final class ExecuteWithoutIdTableHelper {
rootTableReference,
Collections.emptyList(),
null,
null,
sessionFactory
);

View File

@ -89,7 +89,6 @@ public class CteTable {
tableValueConstructorReference,
Collections.emptyList(),
null,
null,
sessionFactory
);

View File

@ -33,11 +33,24 @@ public class StandardTableGroup extends AbstractTableGroup {
TableReference primaryTableReference,
List<TableReferenceJoin> tableJoins,
SqlAliasBase sqlAliasBase,
BiFunction<String,TableGroup,TableReferenceJoin> tableReferenceJoinCreator,
SessionFactoryImplementor sessionFactory) {
super( navigablePath, tableGroupProducer, lockMode, sqlAliasBase, sessionFactory );
this.primaryTableReference = primaryTableReference;
this.tableJoins = tableJoins;
this.tableReferenceJoinCreator = null;
}
public StandardTableGroup(
NavigablePath navigablePath,
TableGroupProducer tableGroupProducer,
LockMode lockMode,
TableReference primaryTableReference,
SqlAliasBase sqlAliasBase,
BiFunction<String,TableGroup,TableReferenceJoin> tableReferenceJoinCreator,
SessionFactoryImplementor sessionFactory) {
super( navigablePath, tableGroupProducer, lockMode, sqlAliasBase, sessionFactory );
this.primaryTableReference = primaryTableReference;
this.tableJoins = null;
this.tableReferenceJoinCreator = tableReferenceJoinCreator;
}
@ -60,6 +73,14 @@ public class StandardTableGroup extends AbstractTableGroup {
return tableJoins == null ? Collections.emptyList() : tableJoins;
}
public void addTableReferenceJoin(TableReferenceJoin join) {
if ( tableJoins == null ) {
tableJoins = new ArrayList<>();
}
tableJoins.add( join );
}
@Override
public TableReference resolveTableReferenceInternal(String tableExpression) {
final TableReference tableReference = super.resolveTableReferenceInternal( tableExpression );

View File

@ -1,139 +0,0 @@
/*
* 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.sql.ast.tree.from;
import java.util.ArrayList;
import java.util.function.BiFunction;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
/**
* @author Steve Ebersole
*/
public class TableGroupBuilder implements TableReferenceCollector {
public static TableGroupBuilder builder(
NavigablePath path,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
BiFunction<String,TableGroup,TableReferenceJoin> tableReferenceJoinCreator,
SessionFactoryImplementor sessionFactory) {
return new TableGroupBuilder( path, producer, lockMode, sqlAliasBase, tableReferenceJoinCreator, sessionFactory );
}
private final NavigablePath path;
private final TableGroupProducer producer;
private final BiFunction<String, TableGroup, TableReferenceJoin> tableReferenceJoinCreator;
private final SessionFactoryImplementor sessionFactory;
private final SqlAliasBase sqlAliasBase;
private final LockMode lockMode;
private BiFunction<TableReference, TableReference,TableReferenceJoin> primaryJoinProducer;
private TableReference primaryTableReference;
private TableReference secondaryTableLhs;
private java.util.List<TableReferenceJoin> tableJoins;
private TableGroupBuilder(
NavigablePath path,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
BiFunction<String, TableGroup, TableReferenceJoin> tableReferenceJoinCreator,
SessionFactoryImplementor sessionFactory) {
this.path = path;
this.producer = producer;
this.lockMode = lockMode;
this.sqlAliasBase = sqlAliasBase;
this.tableReferenceJoinCreator = tableReferenceJoinCreator;
this.sessionFactory = sessionFactory;
}
public NavigablePath getPath() {
return path;
}
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
public SqlAliasBase getSqlAliasBase() {
return sqlAliasBase;
}
@Override
public void applyPrimaryJoinProducer(BiFunction<TableReference, TableReference, TableReferenceJoin> primaryJoinProducer) {
this.primaryJoinProducer = primaryJoinProducer;
}
public TableGroup build() {
if ( primaryTableReference == null ) {
throw new IllegalStateException( "Primary TableReference was not specified : " + path );
}
return new StandardTableGroup(
path,
producer,
lockMode,
primaryTableReference,
tableJoins,
sqlAliasBase,
tableReferenceJoinCreator,
sessionFactory
);
}
@Override
public void applyPrimaryReference(TableReference tableReference) {
if ( primaryTableReference != null ) {
assert primaryJoinProducer != null;
addTableReferenceJoin( primaryJoinProducer.apply( primaryTableReference, tableReference ) );
}
else {
primaryTableReference = tableReference;
}
secondaryTableLhs = tableReference;
}
@Override
public void applySecondaryTableReferences(
TableReference tableReference,
SqlAstJoinType tableReferenceSqlAstJoinType,
TableReferenceJoinPredicateProducer predicateProducer) {
if ( primaryTableReference == null ) {
primaryTableReference = tableReference;
secondaryTableLhs = primaryTableReference;
}
else {
addTableReferenceJoin(
new TableReferenceJoin(
tableReferenceSqlAstJoinType,
tableReference,
predicateProducer.producePredicate(
secondaryTableLhs,
tableReference,
tableReferenceSqlAstJoinType
)
)
);
}
}
public void addTableReferenceJoin(TableReferenceJoin join) {
if ( tableJoins == null ) {
tableJoins = new ArrayList<>();
}
tableJoins.add( join );
}
}