HHH-17202 Fix ArrayStoreException for single field id class entity collection batch loading

This commit is contained in:
Christian Beikov 2023-09-14 10:35:18 +02:00
parent a27d7994a6
commit 30687e0370
1 changed files with 33 additions and 18 deletions

View File

@ -19,7 +19,10 @@ import org.hibernate.loader.ast.spi.CollectionBatchLoader;
import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.ValuedModelPart;
import org.hibernate.metamodel.mapping.internal.IdClassEmbeddable;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.select.SelectStatement;
@ -43,7 +46,7 @@ import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LO
public class CollectionBatchLoaderArrayParam
extends AbstractCollectionBatchLoader
implements CollectionBatchLoader, SqlArrayMultiKeyLoader {
private final Class<?> arrayElementType;
private final Class<?> keyDomainType;
private final JdbcMapping arrayJdbcMapping;
private final JdbcParameter jdbcParameter;
private final SelectStatement sqlSelect;
@ -65,17 +68,18 @@ public class CollectionBatchLoaderArrayParam
}
final ForeignKeyDescriptor keyDescriptor = getLoadable().getKeyDescriptor();
arrayElementType = keyDescriptor.getJavaType().getJavaTypeClass();
Class<?> arrayClass = Array.newInstance( arrayElementType, 0 ).getClass();
final JdbcMapping jdbcMapping = keyDescriptor.getSingleJdbcMapping();
final Class<?> jdbcArrayClass = Array.newInstance( jdbcMapping.getJdbcJavaType().getJavaTypeClass(), 0 )
.getClass();
keyDomainType = getKeyType( keyDescriptor.getKeyPart() );
final BasicType<?> arrayBasicType = getSessionFactory().getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( arrayClass );
.getRegisteredType( jdbcArrayClass );
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping(
arrayBasicType,
keyDescriptor.getSingleJdbcMapping(),
arrayClass,
jdbcMapping,
jdbcArrayClass,
getSessionFactory()
);
@ -96,6 +100,16 @@ public class CollectionBatchLoaderArrayParam
.translate( JdbcParameterBindings.NO_BINDINGS, QueryOptions.NONE );
}
private Class<?> getKeyType(ValuedModelPart keyPart) {
if ( keyPart instanceof NonAggregatedIdentifierMapping ) {
final IdClassEmbeddable idClassEmbeddable = ( (NonAggregatedIdentifierMapping) keyPart ).getIdClassEmbeddable();
if ( idClassEmbeddable != null ) {
return idClassEmbeddable.getMappedJavaType().getJavaTypeClass();
}
}
return keyPart.getJavaType().getJavaTypeClass();
}
@Override
public PersistentCollection<?> load(Object key, SharedSessionContractImplementor session) {
if ( MULTI_KEY_LOAD_LOGGER.isDebugEnabled() ) {
@ -126,20 +140,21 @@ public class CollectionBatchLoaderArrayParam
ForeignKeyDescriptor keyDescriptor) {
final int length = getDomainBatchSize();
final Object[] keysToInitialize = (Object[]) Array.newInstance(
keyDescriptor.getSingleJdbcMapping().getJdbcJavaType().getJavaTypeClass(),
length
);
final Object[] embeddedKeys = (Object[]) Array.newInstance(
arrayElementType,
final Object[] jdbcKeysToInitialize = (Object[]) Array.newInstance(
jdbcParameter.getExpressionType()
.getSingleJdbcMapping()
.getJdbcJavaType()
.getJavaTypeClass()
.getComponentType(),
length
);
final Object[] embeddedKeys = (Object[]) Array.newInstance( keyDomainType, length );
session.getPersistenceContextInternal().getBatchFetchQueue()
.collectBatchLoadableCollectionKeys(
length,
(index, key) ->
keyDescriptor.forEachJdbcValue( key, (i, value, jdbcMapping) -> {
keysToInitialize[index] = value;
jdbcKeysToInitialize[index] = value;
embeddedKeys[index] = key;
}, session )
,
@ -147,21 +162,21 @@ public class CollectionBatchLoaderArrayParam
getLoadable()
);
initializeKeys( keysToInitialize, session );
initializeKeys( jdbcKeysToInitialize, session );
for ( Object initializedKey : embeddedKeys ) {
finishInitializingKey( initializedKey, session );
finishInitializingKey( initializedKey, session );
}
final CollectionKey collectionKey = new CollectionKey(
getLoadable().getCollectionDescriptor(),
keysToInitialize
keyBeingLoaded
);
return session.getPersistenceContext().getCollection( collectionKey );
}
private Object[] resolveKeysToInitialize(Object keyBeingLoaded, SharedSessionContractImplementor session) {
final Object[] keysToInitialize = (Object[]) Array.newInstance( arrayElementType, getDomainBatchSize() );
final Object[] keysToInitialize = (Object[]) Array.newInstance( keyDomainType, getDomainBatchSize() );
session.getPersistenceContextInternal().getBatchFetchQueue().collectBatchLoadableCollectionKeys(
getDomainBatchSize(),
(index, value) -> keysToInitialize[index] = value,