HHH-16750 ClassCastException when an Entity with an ElementCollection has an EmbeddableId with just one field and Batch is enabled

This commit is contained in:
Andrea Boriero 2023-06-09 13:11:47 +02:00 committed by Andrea Boriero
parent e6fbfad0b6
commit 0aa8f4c1bc
5 changed files with 69 additions and 8 deletions

View File

@ -17,6 +17,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.loader.ast.spi.CollectionBatchLoader; import org.hibernate.loader.ast.spi.CollectionBatchLoader;
import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader; import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor; import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
@ -65,7 +66,7 @@ public class CollectionBatchLoaderArrayParam
); );
} }
final SimpleForeignKeyDescriptor keyDescriptor = (SimpleForeignKeyDescriptor) getLoadable().getKeyDescriptor(); final ForeignKeyDescriptor keyDescriptor = getLoadable().getKeyDescriptor();
arrayElementType = keyDescriptor.getJavaType().getJavaTypeClass(); arrayElementType = keyDescriptor.getJavaType().getJavaTypeClass();
Class<?> arrayClass = Array.newInstance( arrayElementType, 0 ).getClass(); Class<?> arrayClass = Array.newInstance( arrayElementType, 0 ).getClass();
@ -75,7 +76,7 @@ public class CollectionBatchLoaderArrayParam
.getRegisteredType( arrayClass ); .getRegisteredType( arrayClass );
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping( arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping(
arrayBasicType, arrayBasicType,
keyDescriptor.getJdbcMapping(), keyDescriptor.getSingleJdbcMapping(),
arrayClass, arrayClass,
getSessionFactory() getSessionFactory()
); );
@ -102,15 +103,62 @@ public class CollectionBatchLoaderArrayParam
if ( MULTI_KEY_LOAD_DEBUG_ENABLED ) { if ( MULTI_KEY_LOAD_DEBUG_ENABLED ) {
MULTI_KEY_LOAD_LOGGER.debugf( "Batch loading entity `%s#%s`", getLoadable().getNavigableRole().getFullPath(), key ); MULTI_KEY_LOAD_LOGGER.debugf( "Batch loading entity `%s#%s`", getLoadable().getNavigableRole().getFullPath(), key );
} }
final ForeignKeyDescriptor keyDescriptor = getLoadable().getKeyDescriptor();
if ( keyDescriptor.isEmbedded() ) {
assert keyDescriptor.getJdbcTypeCount() == 1;
return loadEmbeddable( key, session, keyDescriptor );
}
else {
final Object[] keysToInitialize = resolveKeysToInitialize( key, session );
initializeKeys( keysToInitialize, session );
for ( int i = 0; i < keysToInitialize.length; i++ ) {
finishInitializingKey( keysToInitialize[i], session );
}
final CollectionKey collectionKey = new CollectionKey( getLoadable().getCollectionDescriptor(), key );
return session.getPersistenceContext().getCollection( collectionKey );
}
}
private PersistentCollection<?> loadEmbeddable(
Object keyBeingLoaded,
SharedSessionContractImplementor session,
ForeignKeyDescriptor keyDescriptor) {
final int length = getDomainBatchSize();
final Object[] keysToInitialize = (Object[]) Array.newInstance(
keyDescriptor.getSingleJdbcMapping().getJdbcJavaType().getJavaTypeClass(),
length
);
final Object[] embeddedKeys = (Object[]) Array.newInstance(
arrayElementType,
length
);
session.getPersistenceContextInternal().getBatchFetchQueue()
.collectBatchLoadableCollectionKeys(
length,
(index, key) ->
keyDescriptor.forEachJdbcValue( key, (i, value, jdbcMapping) -> {
keysToInitialize[index] = value;
embeddedKeys[index] = key;
}, session )
,
keyBeingLoaded,
getLoadable()
);
final Object[] keysToInitialize = resolveKeysToInitialize( key, session );
initializeKeys( keysToInitialize, session ); initializeKeys( keysToInitialize, session );
for ( int i = 0; i < keysToInitialize.length; i++ ) { for ( Object initializedKey : embeddedKeys ) {
finishInitializingKey( keysToInitialize[i], session ); finishInitializingKey( initializedKey, session );
} }
final CollectionKey collectionKey = new CollectionKey( getLoadable().getCollectionDescriptor(), key ); final CollectionKey collectionKey = new CollectionKey(
getLoadable().getCollectionDescriptor(),
keysToInitialize
);
return session.getPersistenceContext().getCollection( collectionKey ); return session.getPersistenceContext().getCollection( collectionKey );
} }

View File

@ -40,6 +40,7 @@ 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.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.ValuedModelPart;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor; import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
@ -142,7 +143,7 @@ public class LoaderSelectBuilder {
*/ */
public static SelectStatement createSelectBySingleArrayParameter( public static SelectStatement createSelectBySingleArrayParameter(
Loadable loadable, Loadable loadable,
BasicValuedModelPart restrictedPart, ValuedModelPart restrictedPart,
LoadQueryInfluencers influencers, LoadQueryInfluencers influencers,
LockOptions lockOptions, LockOptions lockOptions,
JdbcParameter jdbcArrayParameter, JdbcParameter jdbcArrayParameter,
@ -202,7 +203,7 @@ public class LoaderSelectBuilder {
QuerySpec rootQuerySpec, QuerySpec rootQuerySpec,
NavigablePath rootNavigablePath, NavigablePath rootNavigablePath,
TableGroup rootTableGroup, TableGroup rootTableGroup,
BasicValuedModelPart restrictedPart, ValuedModelPart restrictedPart,
JdbcParameter jdbcArrayParameter, JdbcParameter jdbcArrayParameter,
LoaderSqlAstCreationState sqlAstCreationState) { LoaderSqlAstCreationState sqlAstCreationState) {
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver(); final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();

View File

@ -199,4 +199,6 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValuedModelPart
ValuedModelPart getModelPart(); ValuedModelPart getModelPart();
} }
boolean isEmbedded();
} }

View File

@ -670,4 +670,9 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
public boolean hasPartitionedSelectionMapping() { public boolean hasPartitionedSelectionMapping() {
return keySide.getModelPart().hasPartitionedSelectionMapping(); return keySide.getModelPart().hasPartitionedSelectionMapping();
} }
@Override
public boolean isEmbedded() {
return true;
}
} }

View File

@ -726,4 +726,9 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
targetSide.getModelPart().getSelectionExpression() targetSide.getModelPart().getSelectionExpression()
); );
} }
@Override
public boolean isEmbedded() {
return false;
}
} }