finish big refactor of AbstractMultiIdEntityLoader and children
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
ae538102f9
commit
55255e9d4a
|
@ -262,7 +262,7 @@ public final class CollectionHelper {
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEmpty(Collection collection) {
|
public static boolean isEmpty(Collection<?> collection) {
|
||||||
return collection == null || collection.isEmpty();
|
return collection == null || collection.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.ast.internal;
|
package org.hibernate.loader.ast.internal;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
@ -20,10 +21,12 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||||
|
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
|
||||||
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
|
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
|
||||||
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
|
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
|
||||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
|
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
|
||||||
|
@ -37,11 +40,13 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
|
||||||
private final EntityMappingType entityDescriptor;
|
private final EntityMappingType entityDescriptor;
|
||||||
private final SessionFactoryImplementor sessionFactory;
|
private final SessionFactoryImplementor sessionFactory;
|
||||||
private final EntityIdentifierMapping identifierMapping;
|
private final EntityIdentifierMapping identifierMapping;
|
||||||
|
protected final Object[] idArray;
|
||||||
|
|
||||||
public AbstractMultiIdEntityLoader(EntityMappingType entityDescriptor, SessionFactoryImplementor sessionFactory) {
|
public AbstractMultiIdEntityLoader(EntityMappingType entityDescriptor, SessionFactoryImplementor sessionFactory) {
|
||||||
this.entityDescriptor = entityDescriptor;
|
this.entityDescriptor = entityDescriptor;
|
||||||
this.sessionFactory = sessionFactory;
|
this.sessionFactory = sessionFactory;
|
||||||
identifierMapping = getLoadable().getIdentifierMapping();
|
identifierMapping = getLoadable().getIdentifierMapping();
|
||||||
|
idArray = (Object[]) Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected EntityMappingType getEntityDescriptor() {
|
protected EntityMappingType getEntityDescriptor() {
|
||||||
|
@ -76,31 +81,43 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
|
||||||
@Override
|
@Override
|
||||||
public final <K> List<T> load(K[] ids, MultiIdLoadOptions loadOptions, EventSource session) {
|
public final <K> List<T> load(K[] ids, MultiIdLoadOptions loadOptions, EventSource session) {
|
||||||
assert ids != null;
|
assert ids != null;
|
||||||
if ( loadOptions.isOrderReturnEnabled() ) {
|
return loadOptions.isOrderReturnEnabled()
|
||||||
return performOrderedMultiLoad( ids, loadOptions, session );
|
? performOrderedMultiLoad( ids, loadOptions, session )
|
||||||
}
|
: performUnorderedMultiLoad( ids, loadOptions, session );
|
||||||
else {
|
}
|
||||||
return performUnorderedMultiLoad( ids, loadOptions, session );
|
|
||||||
|
private List<T> performUnorderedMultiLoad(
|
||||||
|
Object[] ids,
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
EventSource session) {
|
||||||
|
assert !loadOptions.isOrderReturnEnabled();
|
||||||
|
assert ids != null;
|
||||||
|
if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
|
||||||
|
MULTI_KEY_LOAD_LOGGER.tracef( "#performUnorderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() );
|
||||||
}
|
}
|
||||||
|
return unorderedMultiLoad( ids, loadOptions, lockOptions( loadOptions ), session );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<T> performOrderedMultiLoad(
|
protected List<T> performOrderedMultiLoad(
|
||||||
Object[] ids,
|
Object[] ids,
|
||||||
MultiIdLoadOptions loadOptions,
|
MultiIdLoadOptions loadOptions,
|
||||||
EventSource session) {
|
EventSource session) {
|
||||||
|
assert loadOptions.isOrderReturnEnabled();
|
||||||
|
assert ids != null;
|
||||||
if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
|
if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
|
||||||
MULTI_KEY_LOAD_LOGGER.tracef( "#performOrderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() );
|
MULTI_KEY_LOAD_LOGGER.tracef( "#performOrderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() );
|
||||||
}
|
}
|
||||||
|
return orderedMultiLoad( ids, loadOptions, lockOptions( loadOptions ), session );
|
||||||
|
}
|
||||||
|
|
||||||
assert loadOptions.isOrderReturnEnabled();
|
private List<T> orderedMultiLoad(
|
||||||
|
Object[] ids,
|
||||||
final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
|
MultiIdLoadOptions loadOptions,
|
||||||
|
LockOptions lockOptions,
|
||||||
|
EventSource session) {
|
||||||
|
final boolean idCoercionEnabled = isIdCoercionEnabled();
|
||||||
final JavaType<?> idType = getLoadable().getIdentifierMapping().getJavaType();
|
final JavaType<?> idType = getLoadable().getIdentifierMapping().getJavaType();
|
||||||
|
|
||||||
final LockOptions lockOptions = loadOptions.getLockOptions() == null
|
|
||||||
? new LockOptions( LockMode.NONE )
|
|
||||||
: loadOptions.getLockOptions();
|
|
||||||
|
|
||||||
final int maxBatchSize = maxBatchSize( ids, loadOptions );
|
final int maxBatchSize = maxBatchSize( ids, loadOptions );
|
||||||
|
|
||||||
final List<Object> result = arrayList( ids.length );
|
final List<Object> result = arrayList( ids.length );
|
||||||
|
@ -109,10 +126,10 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
|
||||||
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
|
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
|
||||||
|
|
||||||
for ( int i = 0; i < ids.length; i++ ) {
|
for ( int i = 0; i < ids.length; i++ ) {
|
||||||
final Object id = coerce ? idType.coerce( ids[i], session ) : ids[i];
|
final Object id = idCoercionEnabled ? idType.coerce( ids[i], session ) : ids[i];
|
||||||
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
|
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
|
||||||
|
|
||||||
if ( !loadFromCaches( loadOptions, session, id, lockOptions, entityKey, result, i ) ) {
|
if ( !loadFromEnabledCaches( loadOptions, session, id, lockOptions, entityKey, result, i ) ) {
|
||||||
// if we did not hit any of the continues above,
|
// if we did not hit any of the continues above,
|
||||||
// then we need to batch load the entity state.
|
// then we need to batch load the entity state.
|
||||||
idsInBatch.add( id );
|
idsInBatch.add( id );
|
||||||
|
@ -142,13 +159,27 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
|
||||||
return (List<T>) result;
|
return (List<T>) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static LockOptions lockOptions(MultiIdLoadOptions loadOptions) {
|
||||||
|
return loadOptions.getLockOptions() == null
|
||||||
|
? new LockOptions( LockMode.NONE )
|
||||||
|
: loadOptions.getLockOptions();
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions);
|
protected abstract int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions);
|
||||||
|
|
||||||
protected abstract void handleResults(MultiIdLoadOptions loadOptions, EventSource session, List<Integer> elementPositionsLoadedByBatch, List<Object> result);
|
protected abstract void handleResults(
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
EventSource session,
|
||||||
|
List<Integer> elementPositionsLoadedByBatch,
|
||||||
|
List<Object> result);
|
||||||
|
|
||||||
protected abstract void loadEntitiesById(List<Object> idsInBatch, LockOptions lockOptions, MultiIdLoadOptions loadOptions, EventSource session);
|
protected abstract void loadEntitiesById(
|
||||||
|
List<Object> idsInBatch,
|
||||||
|
LockOptions lockOptions,
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
EventSource session);
|
||||||
|
|
||||||
protected boolean loadFromCaches(
|
protected boolean loadFromEnabledCaches(
|
||||||
MultiIdLoadOptions loadOptions,
|
MultiIdLoadOptions loadOptions,
|
||||||
EventSource session,
|
EventSource session,
|
||||||
Object id,
|
Object id,
|
||||||
|
@ -157,48 +188,189 @@ public abstract class AbstractMultiIdEntityLoader<T> implements MultiIdEntityLoa
|
||||||
List<Object> result,
|
List<Object> result,
|
||||||
int i) {
|
int i) {
|
||||||
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
||||||
final LoadEvent loadEvent = new LoadEvent(
|
return loadFromCaches( loadOptions, entityKey, result, i,
|
||||||
id,
|
new LoadEvent(
|
||||||
getLoadable().getJavaType().getJavaTypeClass().getName(),
|
id,
|
||||||
lockOptions,
|
getLoadable().getJavaType().getJavaTypeClass().getName(),
|
||||||
session,
|
lockOptions,
|
||||||
getReadOnlyFromLoadQueryInfluencers( session )
|
session,
|
||||||
|
getReadOnlyFromLoadQueryInfluencers( session )
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Object managedEntity = null;
|
private boolean loadFromCaches(
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
EntityKey entityKey,
|
||||||
|
List<Object> result,
|
||||||
|
int i,
|
||||||
|
LoadEvent loadEvent) {
|
||||||
|
Object managedEntity = null;
|
||||||
|
|
||||||
if ( loadOptions.isSessionCheckingEnabled() ) {
|
if ( loadOptions.isSessionCheckingEnabled() ) {
|
||||||
// look for it in the Session first
|
// look for it in the Session first
|
||||||
final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry =
|
final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry =
|
||||||
loadFromSessionCacheStatic( loadEvent, entityKey, LoadEventListener.GET );
|
loadFromSessionCacheStatic( loadEvent, entityKey, LoadEventListener.GET );
|
||||||
managedEntity = persistenceContextEntry.getEntity();
|
managedEntity = persistenceContextEntry.getEntity();
|
||||||
|
|
||||||
if ( managedEntity != null
|
if ( managedEntity != null
|
||||||
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
|
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
|
||||||
&& !persistenceContextEntry.isManaged() ) {
|
&& !persistenceContextEntry.isManaged() ) {
|
||||||
// put a null in the result
|
// put a null in the result
|
||||||
result.add( i, null );
|
result.add( i, null );
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
|
||||||
// look for it in the SessionFactory
|
|
||||||
managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
|
|
||||||
loadEvent,
|
|
||||||
getLoadable().getEntityPersister(),
|
|
||||||
entityKey
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( managedEntity != null ) {
|
|
||||||
result.add( i, managedEntity );
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
if ( managedEntity == null
|
||||||
|
&& loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
||||||
|
// look for it in the SessionFactory
|
||||||
|
managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
|
||||||
|
loadEvent,
|
||||||
|
getLoadable().getEntityPersister(),
|
||||||
|
entityKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( managedEntity != null ) {
|
||||||
|
result.add( i, managedEntity );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract <K> List<T> performUnorderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session);
|
protected List<T> unorderedMultiLoad(
|
||||||
|
Object[] ids,
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
LockOptions lockOptions,
|
||||||
|
EventSource session) {
|
||||||
|
final List<T> result = arrayList( ids.length );
|
||||||
|
final Object[] unresolvableIds =
|
||||||
|
resolveInCachesIfEnabled( ids, loadOptions, lockOptions, session,
|
||||||
|
(position, entityKey, resolvedRef) -> result.add( (T) resolvedRef ) );
|
||||||
|
if ( !isEmpty( unresolvableIds ) ) {
|
||||||
|
loadEntitiesWithUnresolvedIds( loadOptions, lockOptions, session, unresolvableIds, result );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void loadEntitiesWithUnresolvedIds(
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
LockOptions lockOptions,
|
||||||
|
EventSource session,
|
||||||
|
Object[] unresolvableIds,
|
||||||
|
List<T> result);
|
||||||
|
|
||||||
|
protected final <R> Object[] resolveInCachesIfEnabled(
|
||||||
|
Object[] ids,
|
||||||
|
@NonNull MultiIdLoadOptions loadOptions,
|
||||||
|
@NonNull LockOptions lockOptions,
|
||||||
|
EventSource session,
|
||||||
|
ResolutionConsumer<R> resolutionConsumer) {
|
||||||
|
return loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled()
|
||||||
|
// the user requested that we exclude ids corresponding to already managed
|
||||||
|
// entities from the generated load SQL. So here we will iterate all
|
||||||
|
// incoming id values and see whether it corresponds to an existing
|
||||||
|
// entity associated with the PC - if it does we add it to the result
|
||||||
|
// list immediately and remove its id from the group of ids to load.
|
||||||
|
// we'll load all of them from the database
|
||||||
|
? resolveInCaches( ids, loadOptions, lockOptions, session, resolutionConsumer )
|
||||||
|
: ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final <R> Object[] resolveInCaches(
|
||||||
|
Object[] ids,
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
LockOptions lockOptions,
|
||||||
|
EventSource session,
|
||||||
|
ResolutionConsumer<R> resolutionConsumer) {
|
||||||
|
|
||||||
|
final boolean idCoercionEnabled = isIdCoercionEnabled();
|
||||||
|
final JavaType<?> idType = getLoadable().getIdentifierMapping().getJavaType();
|
||||||
|
|
||||||
|
List<Object> unresolvedIds = null;
|
||||||
|
for ( int i = 0; i < ids.length; i++ ) {
|
||||||
|
final Object id = idCoercionEnabled ? idType.coerce( ids[i], session ) : ids[i];
|
||||||
|
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
|
||||||
|
unresolvedIds = loadFromCaches( id, entityKey, i, unresolvedIds, loadOptions, resolutionConsumer,
|
||||||
|
new LoadEvent(
|
||||||
|
id,
|
||||||
|
getLoadable().getJavaType().getJavaTypeClass().getName(),
|
||||||
|
lockOptions,
|
||||||
|
session,
|
||||||
|
getReadOnlyFromLoadQueryInfluencers( session )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( isEmpty( unresolvedIds ) ) {
|
||||||
|
// all the given ids were already associated with the Session
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if ( unresolvedIds.size() == ids.length ) {
|
||||||
|
// we need to load all the ids
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we need to load only some the ids
|
||||||
|
return unresolvedIds.toArray( idArray );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIdCoercionEnabled() {
|
||||||
|
return !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResolutionConsumer<T> {
|
||||||
|
void consume(int position, EntityKey entityKey, T resolvedRef);
|
||||||
|
}
|
||||||
|
private <R, K> List<K> loadFromCaches(
|
||||||
|
K id, EntityKey entityKey, int i,
|
||||||
|
List<K> unresolvedIds,
|
||||||
|
MultiIdLoadOptions loadOptions,
|
||||||
|
ResolutionConsumer<R> resolutionConsumer,
|
||||||
|
LoadEvent loadEvent) {
|
||||||
|
Object cachedEntity = null;
|
||||||
|
|
||||||
|
// look for it in the Session first
|
||||||
|
final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry =
|
||||||
|
loadFromSessionCacheStatic( loadEvent, entityKey, LoadEventListener.GET );
|
||||||
|
if ( loadOptions.isSessionCheckingEnabled() ) {
|
||||||
|
cachedEntity = persistenceContextEntry.getEntity();
|
||||||
|
|
||||||
|
if ( cachedEntity != null
|
||||||
|
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
|
||||||
|
&& !persistenceContextEntry.isManaged() ) {
|
||||||
|
resolutionConsumer.consume( i, entityKey, null );
|
||||||
|
return unresolvedIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cachedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
||||||
|
cachedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
|
||||||
|
loadEvent,
|
||||||
|
getLoadable().getEntityPersister(),
|
||||||
|
entityKey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cachedEntity != null ) {
|
||||||
|
//noinspection unchecked
|
||||||
|
resolutionConsumer.consume( i, entityKey, (R) cachedEntity);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( unresolvedIds == null ) {
|
||||||
|
unresolvedIds = new ArrayList<>();
|
||||||
|
}
|
||||||
|
unresolvedIds.add( id );
|
||||||
|
}
|
||||||
|
return unresolvedIds;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,29 +4,20 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.ast.internal;
|
package org.hibernate.loader.ast.internal;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.event.spi.LoadEvent;
|
|
||||||
import org.hibernate.event.spi.LoadEventListener;
|
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
|
||||||
import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry;
|
|
||||||
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
||||||
import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader;
|
import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader;
|
||||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
|
||||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
||||||
|
@ -35,19 +26,12 @@ import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||||
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
|
||||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||||
import org.hibernate.sql.results.spi.ManagedResultConsumer;
|
import org.hibernate.sql.results.spi.ManagedResultConsumer;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
|
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
import static org.hibernate.engine.internal.BatchFetchQueueHelper.removeBatchLoadableEntityKey;
|
import static org.hibernate.engine.internal.BatchFetchQueueHelper.removeBatchLoadableEntityKey;
|
||||||
import static org.hibernate.engine.spi.SubselectFetch.createRegistrationHandler;
|
import static org.hibernate.engine.spi.SubselectFetch.createRegistrationHandler;
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
|
|
||||||
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
|
|
||||||
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
|
|
||||||
import static org.hibernate.loader.ast.internal.LoaderHelper.loadByArrayParameter;
|
import static org.hibernate.loader.ast.internal.LoaderHelper.loadByArrayParameter;
|
||||||
import static org.hibernate.loader.ast.internal.LoaderSelectBuilder.createSelectBySingleArrayParameter;
|
import static org.hibernate.loader.ast.internal.LoaderSelectBuilder.createSelectBySingleArrayParameter;
|
||||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.resolveArrayJdbcMapping;
|
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.resolveArrayJdbcMapping;
|
||||||
|
@ -64,11 +48,11 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
||||||
EntityMappingType entityDescriptor,
|
EntityMappingType entityDescriptor,
|
||||||
SessionFactoryImplementor sessionFactory) {
|
SessionFactoryImplementor sessionFactory) {
|
||||||
super( entityDescriptor, sessionFactory );
|
super( entityDescriptor, sessionFactory );
|
||||||
final Class<?> arrayClass = createTypedArray( 0 ).getClass();
|
final Class<?> idArrayClass = idArray.getClass();
|
||||||
arrayJdbcMapping = resolveArrayJdbcMapping(
|
arrayJdbcMapping = resolveArrayJdbcMapping(
|
||||||
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ),
|
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( idArrayClass ),
|
||||||
getIdentifierMapping().getJdbcMapping(),
|
getIdentifierMapping().getJdbcMapping(),
|
||||||
arrayClass,
|
idArrayClass,
|
||||||
getSessionFactory()
|
getSessionFactory()
|
||||||
);
|
);
|
||||||
jdbcParameter = new JdbcParameterImpl( arrayJdbcMapping );
|
jdbcParameter = new JdbcParameterImpl( arrayJdbcMapping );
|
||||||
|
@ -133,7 +117,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
||||||
|
|
||||||
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(1);
|
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(1);
|
||||||
jdbcParameterBindings.addBinding( jdbcParameter,
|
jdbcParameterBindings.addBinding( jdbcParameter,
|
||||||
new JdbcParameterBindingImpl( arrayJdbcMapping, idsInBatch.toArray( createTypedArray(0) ) ) );
|
new JdbcParameterBindingImpl( arrayJdbcMapping, idsInBatch.toArray( idArray ) ) );
|
||||||
|
|
||||||
getJdbcSelectExecutor().executeQuery(
|
getJdbcSelectExecutor().executeQuery(
|
||||||
getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
|
getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
|
||||||
|
@ -156,36 +140,12 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <K> List<E> performUnorderedMultiLoad(
|
protected void loadEntitiesWithUnresolvedIds(
|
||||||
K[] ids,
|
|
||||||
MultiIdLoadOptions loadOptions,
|
MultiIdLoadOptions loadOptions,
|
||||||
EventSource session) {
|
LockOptions lockOptions,
|
||||||
if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
|
EventSource session,
|
||||||
MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef(
|
Object[] unresolvableIds,
|
||||||
"MultiIdEntityLoaderArrayParam#performUnorderedMultiLoad - %s",
|
List<E> result) {
|
||||||
getLoadable().getEntityName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<E> result = CollectionHelper.arrayList( ids.length );
|
|
||||||
final LockOptions lockOptions = loadOptions.getLockOptions() == null
|
|
||||||
? new LockOptions( LockMode.NONE )
|
|
||||||
: loadOptions.getLockOptions();
|
|
||||||
|
|
||||||
//noinspection unchecked
|
|
||||||
final K[] idsToLoadFromDatabase = processResolvableEntities(
|
|
||||||
ids,
|
|
||||||
(index, entityKey, resolvedEntity) -> result.add( (E) resolvedEntity ),
|
|
||||||
loadOptions,
|
|
||||||
lockOptions,
|
|
||||||
session
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( idsToLoadFromDatabase == null ) {
|
|
||||||
// all the given ids were already associated with the Session
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
final SelectStatement sqlAst = createSelectBySingleArrayParameter(
|
final SelectStatement sqlAst = createSelectBySingleArrayParameter(
|
||||||
getLoadable(),
|
getLoadable(),
|
||||||
getIdentifierMapping(),
|
getIdentifierMapping(),
|
||||||
|
@ -194,12 +154,13 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
||||||
jdbcParameter,
|
jdbcParameter,
|
||||||
getSessionFactory()
|
getSessionFactory()
|
||||||
);
|
);
|
||||||
|
|
||||||
final JdbcOperationQuerySelect jdbcSelectOperation =
|
final JdbcOperationQuerySelect jdbcSelectOperation =
|
||||||
getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
|
getSqlAstTranslatorFactory().buildSelectTranslator( getSessionFactory(), sqlAst )
|
||||||
.translate( NO_BINDINGS, QueryOptions.NONE );
|
.translate( NO_BINDINGS, QueryOptions.NONE );
|
||||||
|
|
||||||
final List<E> databaseResults = loadByArrayParameter(
|
final List<E> databaseResults = loadByArrayParameter(
|
||||||
idsToLoadFromDatabase,
|
unresolvableIds,
|
||||||
sqlAst,
|
sqlAst,
|
||||||
jdbcSelectOperation,
|
jdbcSelectOperation,
|
||||||
jdbcParameter,
|
jdbcParameter,
|
||||||
|
@ -213,108 +174,14 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
||||||
);
|
);
|
||||||
result.addAll( databaseResults );
|
result.addAll( databaseResults );
|
||||||
|
|
||||||
//noinspection ForLoopReplaceableByForEach
|
for ( Object id : unresolvableIds ) {
|
||||||
for ( int i = 0; i < idsToLoadFromDatabase.length; i++ ) {
|
// skip any of the null padded ids
|
||||||
final Object id = idsToLoadFromDatabase[i];
|
// (actually we could probably even break on the first null)
|
||||||
if ( id == null ) {
|
if ( id != null ) {
|
||||||
// skip any of the null padded ids
|
// found or not, remove the key from the batch-fetch queue
|
||||||
// - actually we could probably even break here
|
removeBatchLoadableEntityKey( id, getLoadable(), session );
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// found or not, remove the key from the batch-fetch queue
|
|
||||||
removeBatchLoadableEntityKey( id, getLoadable(), session );
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public interface ResolutionConsumer<T> {
|
|
||||||
void consume(int position, EntityKey entityKey, T resolvedRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final <R,K> K[] processResolvableEntities(
|
|
||||||
K[] ids,
|
|
||||||
ResolutionConsumer<R> resolutionConsumer,
|
|
||||||
@NonNull MultiIdLoadOptions loadOptions,
|
|
||||||
@NonNull LockOptions lockOptions,
|
|
||||||
EventSource session) {
|
|
||||||
if ( !loadOptions.isSessionCheckingEnabled()
|
|
||||||
&& !loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
|
||||||
// we'll load all of them from the database
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean foundAnyResolvedEntities = false;
|
|
||||||
List<K> nonResolvedIds = null;
|
|
||||||
|
|
||||||
final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
|
|
||||||
final JavaType<?> idType = getLoadable().getIdentifierMapping().getJavaType();
|
|
||||||
|
|
||||||
for ( int i = 0; i < ids.length; i++ ) {
|
|
||||||
final Object id = coerce ? idType.coerce( ids[i], session ) : ids[i];
|
|
||||||
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
|
|
||||||
|
|
||||||
final LoadEvent loadEvent = new LoadEvent(
|
|
||||||
id,
|
|
||||||
getLoadable().getJavaType().getJavaTypeClass().getName(),
|
|
||||||
lockOptions,
|
|
||||||
session,
|
|
||||||
getReadOnlyFromLoadQueryInfluencers( session )
|
|
||||||
);
|
|
||||||
|
|
||||||
Object managedEntity = null;
|
|
||||||
|
|
||||||
// look for it in the Session first
|
|
||||||
final PersistenceContextEntry persistenceContextEntry =
|
|
||||||
loadFromSessionCacheStatic( loadEvent, entityKey, LoadEventListener.GET );
|
|
||||||
if ( loadOptions.isSessionCheckingEnabled() ) {
|
|
||||||
managedEntity = persistenceContextEntry.getEntity();
|
|
||||||
|
|
||||||
if ( managedEntity != null
|
|
||||||
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
|
|
||||||
&& !persistenceContextEntry.isManaged() ) {
|
|
||||||
foundAnyResolvedEntities = true;
|
|
||||||
resolutionConsumer.consume( i, entityKey, null );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
|
||||||
managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
|
|
||||||
loadEvent,
|
|
||||||
getLoadable().getEntityPersister(),
|
|
||||||
entityKey
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( managedEntity != null ) {
|
|
||||||
foundAnyResolvedEntities = true;
|
|
||||||
|
|
||||||
//noinspection unchecked
|
|
||||||
resolutionConsumer.consume( i, entityKey, (R) managedEntity);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ( nonResolvedIds == null ) {
|
|
||||||
nonResolvedIds = new ArrayList<>();
|
|
||||||
}
|
|
||||||
//noinspection unchecked
|
|
||||||
nonResolvedIds.add( (K) id );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( foundAnyResolvedEntities ) {
|
|
||||||
if ( isEmpty( nonResolvedIds ) ) {
|
|
||||||
// all the given ids were already associated with the Session
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nonResolvedIds.toArray( createTypedArray(0) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <X> X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) {
|
|
||||||
//noinspection unchecked
|
|
||||||
return (X[]) Array.newInstance( getIdentifierMapping().getJavaType().getJavaTypeClass(), length );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.ast.internal;
|
package org.hibernate.loader.ast.internal;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.engine.spi.BatchFetchQueue;
|
import org.hibernate.engine.spi.BatchFetchQueue;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
|
@ -18,9 +15,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.engine.spi.SubselectFetch;
|
import org.hibernate.engine.spi.SubselectFetch;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.event.spi.LoadEvent;
|
|
||||||
import org.hibernate.event.spi.LoadEventListener;
|
|
||||||
import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry;
|
|
||||||
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
||||||
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
|
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -32,15 +26,11 @@ import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||||
|
|
||||||
import org.hibernate.type.descriptor.java.JavaType;
|
|
||||||
|
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static java.lang.System.arraycopy;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.hibernate.engine.spi.SubselectFetch.createRegistrationHandler;
|
import static org.hibernate.engine.spi.SubselectFetch.createRegistrationHandler;
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
|
||||||
import static org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.loadFromSessionCacheStatic;
|
|
||||||
import static org.hibernate.loader.ast.internal.LoaderHelper.getReadOnlyFromLoadQueryInfluencers;
|
|
||||||
import static org.hibernate.loader.ast.internal.LoaderSelectBuilder.createSelect;
|
import static org.hibernate.loader.ast.internal.LoaderSelectBuilder.createSelect;
|
||||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
|
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
|
||||||
|
|
||||||
|
@ -205,123 +195,22 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<T> performUnorderedMultiLoad(
|
protected void loadEntitiesWithUnresolvedIds(
|
||||||
Object[] ids,
|
|
||||||
MultiIdLoadOptions loadOptions,
|
MultiIdLoadOptions loadOptions,
|
||||||
EventSource session) {
|
LockOptions lockOptions,
|
||||||
assert !loadOptions.isOrderReturnEnabled();
|
EventSource session,
|
||||||
assert ids != null;
|
Object[] unresolvableIds,
|
||||||
|
List<T> result) {
|
||||||
if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
|
final int maxBatchSize = maxBatchSize( unresolvableIds, loadOptions );
|
||||||
MULTI_KEY_LOAD_LOGGER.tracef( "#performUnorderedMultiLoad(`%s`, ..)", getLoadable().getEntityName() );
|
int numberOfIdsLeft = unresolvableIds.length;
|
||||||
}
|
|
||||||
|
|
||||||
final List<T> result = arrayList( ids.length );
|
|
||||||
|
|
||||||
final LockOptions lockOptions = loadOptions.getLockOptions() == null
|
|
||||||
? new LockOptions( LockMode.NONE )
|
|
||||||
: loadOptions.getLockOptions();
|
|
||||||
|
|
||||||
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
|
||||||
// the user requested that we exclude ids corresponding to already managed
|
|
||||||
// entities from the generated load SQL. So here we will iterate all
|
|
||||||
// incoming id values and see whether it corresponds to an existing
|
|
||||||
// entity associated with the PC - if it does we add it to the result
|
|
||||||
// list immediately and remove its id from the group of ids to load.
|
|
||||||
boolean foundAnyManagedEntities = false;
|
|
||||||
final List<Object> nonManagedIds = new ArrayList<>();
|
|
||||||
|
|
||||||
final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
|
|
||||||
final JavaType<?> idType = getLoadable().getIdentifierMapping().getJavaType();
|
|
||||||
|
|
||||||
for ( int i = 0; i < ids.length; i++ ) {
|
|
||||||
final Object id = coerce ? idType.coerce( ids[i], session ) : ids[i];
|
|
||||||
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
|
|
||||||
|
|
||||||
final LoadEvent loadEvent = new LoadEvent(
|
|
||||||
id,
|
|
||||||
getLoadable().getJavaType().getJavaTypeClass().getName(),
|
|
||||||
lockOptions,
|
|
||||||
session,
|
|
||||||
getReadOnlyFromLoadQueryInfluencers( session )
|
|
||||||
);
|
|
||||||
|
|
||||||
Object managedEntity = null;
|
|
||||||
|
|
||||||
// look for it in the Session first
|
|
||||||
final PersistenceContextEntry persistenceContextEntry =
|
|
||||||
loadFromSessionCacheStatic( loadEvent, entityKey, LoadEventListener.GET );
|
|
||||||
if ( loadOptions.isSessionCheckingEnabled() ) {
|
|
||||||
managedEntity = persistenceContextEntry.getEntity();
|
|
||||||
|
|
||||||
if ( managedEntity != null
|
|
||||||
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
|
|
||||||
&& !persistenceContextEntry.isManaged() ) {
|
|
||||||
foundAnyManagedEntities = true;
|
|
||||||
result.add( null );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
|
|
||||||
managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
|
|
||||||
loadEvent,
|
|
||||||
getLoadable().getEntityPersister(),
|
|
||||||
entityKey
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( managedEntity != null ) {
|
|
||||||
foundAnyManagedEntities = true;
|
|
||||||
//noinspection unchecked
|
|
||||||
result.add( (T) managedEntity );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nonManagedIds.add( id );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( foundAnyManagedEntities ) {
|
|
||||||
if ( nonManagedIds.isEmpty() ) {
|
|
||||||
// all the given ids were already associated with the Session
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// over-write the ids to be loaded with the collection of
|
|
||||||
// just non-managed ones
|
|
||||||
ids = nonManagedIds.toArray(
|
|
||||||
(Object[]) Array.newInstance(
|
|
||||||
ids.getClass().getComponentType(),
|
|
||||||
nonManagedIds.size()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int numberOfIdsLeft = ids.length;
|
|
||||||
final int maxBatchSize;
|
|
||||||
if ( loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0 ) {
|
|
||||||
maxBatchSize = loadOptions.getBatchSize();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
maxBatchSize = getBatchLoadSizingStrategy().determineOptimalBatchLoadSize(
|
|
||||||
getIdentifierMapping().getJdbcTypeCount(),
|
|
||||||
numberOfIdsLeft,
|
|
||||||
isInClauseParameterPaddingEnabled()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
int idPosition = 0;
|
int idPosition = 0;
|
||||||
while ( numberOfIdsLeft > 0 ) {
|
while ( numberOfIdsLeft > 0 ) {
|
||||||
final int batchSize = Math.min( numberOfIdsLeft, maxBatchSize );
|
final int batchSize = Math.min( numberOfIdsLeft, maxBatchSize );
|
||||||
final Object[] idsInBatch = new Object[ batchSize ];
|
final Object[] idsInBatch = new Object[batchSize];
|
||||||
System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize );
|
arraycopy( unresolvableIds, idPosition, idsInBatch, 0, batchSize );
|
||||||
result.addAll( listEntitiesById( asList( idsInBatch ), lockOptions, loadOptions, session ) );
|
result.addAll( listEntitiesById( asList( idsInBatch ), lockOptions, loadOptions, session ) );
|
||||||
numberOfIdsLeft = numberOfIdsLeft - batchSize;
|
numberOfIdsLeft = numberOfIdsLeft - batchSize;
|
||||||
idPosition += batchSize;
|
idPosition += batchSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue