Fix DynamicBatch loading
This commit is contained in:
parent
29e22c68ac
commit
9b569932d2
|
@ -76,7 +76,7 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
||||||
if ( numberOfIds <= 1 ) {
|
if ( numberOfIds <= 1 ) {
|
||||||
initializeSingleIdLoaderIfNeeded( session );
|
initializeSingleIdLoaderIfNeeded( session );
|
||||||
|
|
||||||
final T result = singleIdLoader.load( pkValue, lockOptions, readOnly, session );
|
final T result = singleIdLoader.load( pkValue, entityInstance, lockOptions, readOnly, session );
|
||||||
if ( result == null ) {
|
if ( result == null ) {
|
||||||
// There was no entity with the specified ID. Make sure the EntityKey does not remain
|
// There was no entity with the specified ID. Make sure the EntityKey does not remain
|
||||||
// in the batch to avoid including it in future batches that get executed.
|
// in the batch to avoid including it in future batches that get executed.
|
||||||
|
@ -144,7 +144,14 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
||||||
JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
||||||
jdbcSelect,
|
jdbcSelect,
|
||||||
jdbcParameterBindings,
|
jdbcParameterBindings,
|
||||||
getExecutionContext( entityInstance, readOnly, session, subSelectFetchableKeysHandler ),
|
getExecutionContext(
|
||||||
|
pkValue,
|
||||||
|
entityInstance,
|
||||||
|
readOnly,
|
||||||
|
lockOptions,
|
||||||
|
session,
|
||||||
|
subSelectFetchableKeysHandler
|
||||||
|
),
|
||||||
RowTransformerPassThruImpl.instance(),
|
RowTransformerPassThruImpl.instance(),
|
||||||
ListResultsConsumer.UniqueSemantic.FILTER
|
ListResultsConsumer.UniqueSemantic.FILTER
|
||||||
);
|
);
|
||||||
|
@ -163,8 +170,10 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExecutionContext getExecutionContext(
|
private ExecutionContext getExecutionContext(
|
||||||
|
Object entityId,
|
||||||
Object entityInstance,
|
Object entityInstance,
|
||||||
Boolean readOnly,
|
Boolean readOnly,
|
||||||
|
LockOptions lockOptions,
|
||||||
SharedSessionContractImplementor session,
|
SharedSessionContractImplementor session,
|
||||||
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler) {
|
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler) {
|
||||||
return new ExecutionContext() {
|
return new ExecutionContext() {
|
||||||
|
@ -178,6 +187,11 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
||||||
return entityInstance;
|
return entityInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityId() {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryOptions getQueryOptions() {
|
public QueryOptions getQueryOptions() {
|
||||||
return new QueryOptionsAdapter() {
|
return new QueryOptionsAdapter() {
|
||||||
|
@ -185,6 +199,11 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
||||||
public Boolean isReadOnly() {
|
public Boolean isReadOnly() {
|
||||||
return readOnly;
|
return readOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LockOptions getLockOptions() {
|
||||||
|
return lockOptions;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
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.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
@ -604,6 +605,11 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement
|
||||||
return navigablePath;
|
return navigablePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityKey getEntityKey() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelPart getInitializedPart() {
|
public ModelPart getInitializedPart() {
|
||||||
return naturalIdMapping;
|
return naturalIdMapping;
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.results.graph;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +27,8 @@ public interface FetchParentAccess extends Initializer {
|
||||||
|
|
||||||
NavigablePath getNavigablePath();
|
NavigablePath getNavigablePath();
|
||||||
|
|
||||||
|
EntityKey getEntityKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a listener to be notified when the parent is "resolved"
|
* Register a listener to be notified when the parent is "resolved"
|
||||||
*
|
*
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.sql.results.graph.Fetch;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.Initializer;
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.AbstractEntityInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
import org.hibernate.sql.results.internal.NullValueAssembler;
|
import org.hibernate.sql.results.internal.NullValueAssembler;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
@ -165,8 +166,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
||||||
|
|
||||||
final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess();
|
final PropertyAccess parentInjectionPropertyAccess = embeddedModelPartDescriptor.getParentInjectionAttributePropertyAccess();
|
||||||
|
|
||||||
|
Initializer initializer = rowProcessingState.resolveInitializer( navigablePath.getParent() );
|
||||||
if ( parentInjectionPropertyAccess != null ) {
|
if ( parentInjectionPropertyAccess != null ) {
|
||||||
Initializer initializer = rowProcessingState.resolveInitializer( navigablePath.getParent() );
|
|
||||||
final Object owner;
|
final Object owner;
|
||||||
if ( initializer instanceof CollectionInitializer ) {
|
if ( initializer instanceof CollectionInitializer ) {
|
||||||
owner = ( (CollectionInitializer) initializer ).getCollectionInstance().getOwner();
|
owner = ( (CollectionInitializer) initializer ).getCollectionInstance().getOwner();
|
||||||
|
@ -214,15 +215,27 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
||||||
else {
|
else {
|
||||||
notifyParentResolutionListeners( compositeInstance );
|
notifyParentResolutionListeners( compositeInstance );
|
||||||
if ( compositeInstance instanceof HibernateProxy ) {
|
if ( compositeInstance instanceof HibernateProxy ) {
|
||||||
Object target = embeddedModelPartDescriptor.getEmbeddableTypeDescriptor()
|
if ( initializer != this ) {
|
||||||
.getRepresentationStrategy()
|
( (AbstractEntityInitializer) initializer ).registerResolutionListener(
|
||||||
.getInstantiator()
|
entityInstance -> {
|
||||||
.instantiate( VALUE_ACCESS, rowProcessingState.getSession().getFactory() );
|
embeddedModelPartDescriptor.getEmbeddableTypeDescriptor().setPropertyValues(
|
||||||
embeddedModelPartDescriptor.getEmbeddableTypeDescriptor().setPropertyValues(
|
entityInstance,
|
||||||
target,
|
resolvedValues
|
||||||
resolvedValues
|
);
|
||||||
);
|
}
|
||||||
( (HibernateProxy) compositeInstance ).getHibernateLazyInitializer().setImplementation( target );
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Object target = embeddedModelPartDescriptor.getEmbeddableTypeDescriptor()
|
||||||
|
.getRepresentationStrategy()
|
||||||
|
.getInstantiator()
|
||||||
|
.instantiate( VALUE_ACCESS, rowProcessingState.getSession().getFactory() );
|
||||||
|
embeddedModelPartDescriptor.getEmbeddableTypeDescriptor().setPropertyValues(
|
||||||
|
target,
|
||||||
|
resolvedValues
|
||||||
|
);
|
||||||
|
( (HibernateProxy) compositeInstance ).getHibernateLazyInitializer().setImplementation( target );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// At this point, createEmptyCompositesEnabled is always true.
|
// At this point, createEmptyCompositesEnabled is always true.
|
||||||
// We can only set the property values on the compositeInstance though if there is at least one non null value.
|
// We can only set the property values on the compositeInstance though if there is at least one non null value.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.results.graph.embeddable.internal;
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer;
|
import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer;
|
||||||
|
@ -25,6 +26,11 @@ public class EmbeddableFetchInitializer
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParentKey() {
|
public Object getParentKey() {
|
||||||
return getFetchParentAccess().getParentKey();
|
return findFirstEntityDescriptorAccess().getParentKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityKey getEntityKey() {
|
||||||
|
return findFirstEntityDescriptorAccess().getEntityKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.results.graph.embeddable.internal;
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer;
|
import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer;
|
||||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||||
|
@ -22,7 +23,12 @@ public class EmbeddableResultInitializer extends AbstractEmbeddableInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getParentKey() {
|
public Object getParentKey() {
|
||||||
return null;
|
return findFirstEntityDescriptorAccess().getParentKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityKey getEntityKey() {
|
||||||
|
return findFirstEntityDescriptorAccess().getEntityKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -581,6 +581,8 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
return existingLoadingEntry.getEntityInstance();
|
return existingLoadingEntry.getEntityInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert existingLoadingEntry == null || existingLoadingEntry.getEntityInstance() == null;
|
||||||
|
|
||||||
Object instance = null;
|
Object instance = null;
|
||||||
|
|
||||||
// this isEntityReturn bit is just for entity loaders, not hql/criteria
|
// this isEntityReturn bit is just for entity loaders, not hql/criteria
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
/*
|
||||||
|
* 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.results.graph.entity.internal;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
|
import org.hibernate.internal.log.LoggingHelper;
|
||||||
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
|
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.entity.UniqueKeyLoadable;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
|
import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.AbstractEntityInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.EntityLoadingLogger;
|
||||||
|
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||||
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
|
||||||
|
import static org.hibernate.internal.log.LoggingHelper.toLoggableString;
|
||||||
|
|
||||||
|
public class BatchEntitySelectFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
||||||
|
private static final String CONCRETE_NAME = BatchEntitySelectFetchInitializer.class.getSimpleName();
|
||||||
|
|
||||||
|
private FetchParentAccess parentAccess;
|
||||||
|
private final NavigablePath navigablePath;
|
||||||
|
|
||||||
|
protected final EntityPersister concreteDescriptor;
|
||||||
|
protected final DomainResultAssembler identifierAssembler;
|
||||||
|
private final ToOneAttributeMapping referencedModelPart;
|
||||||
|
|
||||||
|
protected Object entityInstance;
|
||||||
|
private EntityKey entityKey;
|
||||||
|
|
||||||
|
private Map<EntityKey, Object> toBatchLoad = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public BatchEntitySelectFetchInitializer(
|
||||||
|
FetchParentAccess parentAccess,
|
||||||
|
ToOneAttributeMapping referencedModelPart,
|
||||||
|
NavigablePath fetchedNavigable,
|
||||||
|
EntityPersister concreteDescriptor,
|
||||||
|
DomainResultAssembler identifierAssembler) {
|
||||||
|
this.parentAccess = parentAccess;
|
||||||
|
this.referencedModelPart = referencedModelPart;
|
||||||
|
this.navigablePath = fetchedNavigable;
|
||||||
|
this.concreteDescriptor = concreteDescriptor;
|
||||||
|
this.identifierAssembler = identifierAssembler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelPart getInitializedPart() {
|
||||||
|
return referencedModelPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NavigablePath getNavigablePath() {
|
||||||
|
return navigablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveKey(RowProcessingState rowProcessingState) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeInstance(RowProcessingState rowProcessingState) {
|
||||||
|
final Object entityIdentifier = identifierAssembler.assemble( rowProcessingState );
|
||||||
|
if ( entityIdentifier == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entityKey = new EntityKey( entityIdentifier, concreteDescriptor );
|
||||||
|
|
||||||
|
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal();
|
||||||
|
entityInstance = persistenceContext.getEntity( entityKey );
|
||||||
|
if ( entityInstance != null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Initializer initializer = rowProcessingState.getJdbcValuesSourceProcessingState()
|
||||||
|
.findInitializer( entityKey );
|
||||||
|
|
||||||
|
if ( initializer != null ) {
|
||||||
|
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
||||||
|
EntityLoadingLogger.LOGGER.debugf(
|
||||||
|
"(%s) Found an initializer for entity (%s) : %s",
|
||||||
|
CONCRETE_NAME,
|
||||||
|
toLoggableString( getNavigablePath(), entityIdentifier ),
|
||||||
|
entityIdentifier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
initializer.resolveInstance( rowProcessingState );
|
||||||
|
entityInstance = initializer.getInitializedInstance();
|
||||||
|
// EARLY EXIT!!!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LoadingEntityEntry existingLoadingEntry = rowProcessingState.getSession()
|
||||||
|
.getPersistenceContext()
|
||||||
|
.getLoadContexts()
|
||||||
|
.findLoadingEntityEntry( entityKey );
|
||||||
|
|
||||||
|
if ( existingLoadingEntry != null ) {
|
||||||
|
if ( existingLoadingEntry.getEntityInitializer() != this ) {
|
||||||
|
// the entity is already being loaded elsewhere
|
||||||
|
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
||||||
|
EntityLoadingLogger.LOGGER.debugf(
|
||||||
|
"(%s) Entity [%s] being loaded by another initializer [%s] - skipping processing",
|
||||||
|
CONCRETE_NAME,
|
||||||
|
toLoggableString( getNavigablePath(), entityIdentifier ),
|
||||||
|
existingLoadingEntry.getEntityInitializer()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.entityInstance = existingLoadingEntry.getEntityInstance();
|
||||||
|
|
||||||
|
// EARLY EXIT!!!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
|
||||||
|
toBatchLoad.put( entityKey, parentAccess.getInitializedInstance() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||||
|
entityInstance = null;
|
||||||
|
clearParentResolutionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityPersister getEntityDescriptor() {
|
||||||
|
return concreteDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityInstance() {
|
||||||
|
return entityInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityKey getEntityKey() {
|
||||||
|
return entityKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getParentKey() {
|
||||||
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerResolutionListener(Consumer<Object> listener) {
|
||||||
|
if ( entityInstance != null ) {
|
||||||
|
listener.accept( entityInstance );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
super.registerResolutionListener( listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityPersister getConcreteDescriptor() {
|
||||||
|
return concreteDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "EntitySelectFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endLoading(ExecutionContext context) {
|
||||||
|
toBatchLoad.forEach(
|
||||||
|
(entityKey, parentInstance) -> {
|
||||||
|
final Object instance = context.getSession().internalLoad(
|
||||||
|
entityKey.getEntityName(),
|
||||||
|
entityKey.getIdentifier(),
|
||||||
|
true,
|
||||||
|
referencedModelPart.isNullable()
|
||||||
|
);
|
||||||
|
if ( instance != null ) {
|
||||||
|
( (AbstractEntityPersister) referencedModelPart.getDeclaringType() ).setPropertyValue(
|
||||||
|
parentInstance,
|
||||||
|
referencedModelPart.getPartName(),
|
||||||
|
instance
|
||||||
|
);
|
||||||
|
final EntityEntry entry = context.getSession()
|
||||||
|
.getPersistenceContext()
|
||||||
|
.getEntry( parentInstance );
|
||||||
|
final int propertyIndex = ( (UniqueKeyLoadable) ( (AbstractEntityInitializer) parentAccess ).getEntityDescriptor() ).getPropertyIndex(
|
||||||
|
referencedModelPart.getPartName() );
|
||||||
|
if ( entry != null ) {
|
||||||
|
final Object[] loadedState = entry.getLoadedState();
|
||||||
|
if ( loadedState != null ) {
|
||||||
|
loadedState[propertyIndex] = instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
toBatchLoad = null;
|
||||||
|
parentAccess = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,13 +68,24 @@ public class EntityFetchSelectImpl extends AbstractNonJoinedEntityFetch {
|
||||||
result.createResultAssembler( creationState )
|
result.createResultAssembler( creationState )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new EntitySelectFetchInitializer(
|
if ( entityPersister.isBatchLoadable() ) {
|
||||||
parentAccess,
|
return new BatchEntitySelectFetchInitializer(
|
||||||
fetchedAttribute,
|
parentAccess,
|
||||||
getNavigablePath(),
|
fetchedAttribute,
|
||||||
entityPersister,
|
getNavigablePath(),
|
||||||
result.createResultAssembler( creationState )
|
entityPersister,
|
||||||
);
|
result.createResultAssembler( creationState )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new EntitySelectFetchInitializer(
|
||||||
|
parentAccess,
|
||||||
|
fetchedAttribute,
|
||||||
|
getNavigablePath(),
|
||||||
|
entityPersister,
|
||||||
|
result.createResultAssembler( creationState )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -126,8 +126,8 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Initializer initializer = rowProcessingState.getJdbcValuesSourceProcessingState().findInitializer(
|
Initializer initializer = rowProcessingState.getJdbcValuesSourceProcessingState()
|
||||||
entityKey );
|
.findInitializer( entityKey );
|
||||||
|
|
||||||
if ( initializer != null ) {
|
if ( initializer != null ) {
|
||||||
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
if ( EntityLoadingLogger.DEBUG_ENABLED ) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
import org.hibernate.sql.results.graph.BiDirectionalFetch;
|
import org.hibernate.sql.results.graph.BiDirectionalFetch;
|
||||||
|
@ -27,6 +28,7 @@ import org.hibernate.sql.results.graph.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.entity.internal.BatchEntitySelectFetchInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer;
|
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchByUniqueKeyInitializer;
|
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchByUniqueKeyInitializer;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer;
|
import org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer;
|
||||||
|
@ -116,13 +118,25 @@ public class CircularFetchImpl implements BiDirectionalFetch, Association {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( timing == FetchTiming.IMMEDIATE ) {
|
if ( timing == FetchTiming.IMMEDIATE ) {
|
||||||
return new EntitySelectFetchInitializer(
|
final EntityPersister entityPersister = entityMappingType.getEntityPersister();
|
||||||
parentAccess,
|
if ( entityPersister.isBatchLoadable() ) {
|
||||||
(ToOneAttributeMapping) referencedModelPart,
|
return new BatchEntitySelectFetchInitializer(
|
||||||
getReferencedPath(),
|
parentAccess,
|
||||||
entityMappingType.getEntityPersister(),
|
(ToOneAttributeMapping) referencedModelPart,
|
||||||
resultAssembler
|
getReferencedPath(),
|
||||||
);
|
entityPersister,
|
||||||
|
resultAssembler
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new EntitySelectFetchInitializer(
|
||||||
|
parentAccess,
|
||||||
|
(ToOneAttributeMapping) referencedModelPart,
|
||||||
|
getReferencedPath(),
|
||||||
|
entityPersister,
|
||||||
|
resultAssembler
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new EntityDelayedFetchInitializer(
|
return new EntityDelayedFetchInitializer(
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.FetchType;
|
import jakarta.persistence.FetchType;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import org.hibernate.annotations.BatchSize;
|
import org.hibernate.annotations.BatchSize;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@ -31,4 +31,8 @@ public class BId
|
||||||
this.idPart2 = idPart2;
|
this.idPart2 = idPart2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BId (" + idPart1 + ", " + idPart2 + ")";
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,16 @@
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.FetchType;
|
import jakarta.persistence.FetchType;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
@ -9,33 +18,20 @@ import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.ManyToMany;
|
import jakarta.persistence.ManyToMany;
|
||||||
import jakarta.persistence.MappedSuperclass;
|
import jakarta.persistence.MappedSuperclass;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
@DomainModel(
|
||||||
import org.junit.Test;
|
annotatedClasses = {
|
||||||
|
BatchFetchBootstrapTest.JafSid.class, BatchFetchBootstrapTest.UserGroup.class
|
||||||
public class BatchFetchBootstrapTest extends BaseCoreFunctionalTestCase {
|
}
|
||||||
|
)
|
||||||
@Override
|
@SessionFactory
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
@ServiceRegistry(
|
||||||
return new Class[] {
|
settings = @Setting( name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "30")
|
||||||
JafSid.class, UserGroup.class
|
)
|
||||||
};
|
public class BatchFetchBootstrapTest {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(Configuration configuration) {
|
|
||||||
configuration.setProperty(AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "30");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void buildSessionFactory() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
super.buildSessionFactory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,28 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.BatchSize;
|
||||||
|
import org.hibernate.annotations.NotFound;
|
||||||
|
import org.hibernate.annotations.NotFoundAction;
|
||||||
|
import org.hibernate.engine.spi.BatchFetchQueue;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.ForeignKey;
|
import jakarta.persistence.ForeignKey;
|
||||||
|
@ -15,74 +33,54 @@ import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.OneToOne;
|
import jakarta.persistence.OneToOne;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.annotations.BatchSize;
|
|
||||||
import org.hibernate.annotations.NotFound;
|
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.engine.spi.BatchFetchQueue;
|
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gail Badner
|
* @author Gail Badner
|
||||||
* @author Stephen Fikes
|
* @author Stephen Fikes
|
||||||
*/
|
*/
|
||||||
public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctionalTestCase {
|
@DomainModel(
|
||||||
private static final AStatementInspector statementInspector = new AStatementInspector();
|
annotatedClasses = {
|
||||||
|
BatchFetchNotFoundIgnoreDynamicStyleTest.Employee.class,
|
||||||
|
BatchFetchNotFoundIgnoreDynamicStyleTest.Task.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory(
|
||||||
|
statementInspectorClass = BatchFetchNotFoundIgnoreDynamicStyleTest.AStatementInspector.class
|
||||||
|
)
|
||||||
|
public class BatchFetchNotFoundIgnoreDynamicStyleTest {
|
||||||
private static final int NUMBER_OF_EMPLOYEES = 8;
|
private static final int NUMBER_OF_EMPLOYEES = 8;
|
||||||
|
|
||||||
private List<Task> tasks = new ArrayList<>();
|
private List<Task> tasks = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[] { Employee.class, Task.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@BeforeEach
|
||||||
protected void configure(Configuration configuration) {
|
public void createData(SessionFactoryScope scope) {
|
||||||
super.configure( configuration );
|
|
||||||
configuration.getProperties().put( Environment.STATEMENT_INSPECTOR, statementInspector );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void createData() {
|
|
||||||
tasks.clear();
|
tasks.clear();
|
||||||
tasks = doInHibernate(
|
tasks = scope.fromTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
for (int i = 0 ; i < NUMBER_OF_EMPLOYEES ; i++) {
|
for ( int i = 0; i < NUMBER_OF_EMPLOYEES; i++ ) {
|
||||||
Task task = new Task();
|
Task task = new Task();
|
||||||
task.id = i;
|
task.id = i;
|
||||||
tasks.add( task );
|
tasks.add( task );
|
||||||
session.persist( task );
|
session.persist( task );
|
||||||
Employee e = new Employee("employee0" + i);
|
Employee e = new Employee( "employee0" + i );
|
||||||
e.task = task;
|
e.task = task;
|
||||||
session.persist(e);
|
session.persist( e );
|
||||||
}
|
}
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void deleteData() {
|
public void deleteData(SessionFactoryScope scope) {
|
||||||
doInHibernate(
|
scope.inTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
session.createQuery( "delete from Task" ).executeUpdate();
|
session.createQuery( "delete from Task" ).executeUpdate();
|
||||||
session.createQuery( "delete from Employee" ).executeUpdate();
|
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||||
}
|
}
|
||||||
|
@ -90,10 +88,10 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSeveralNotFoundFromQuery() {
|
public void testSeveralNotFoundFromQuery(SessionFactoryScope scope) {
|
||||||
|
|
||||||
doInHibernate(
|
scope.inTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
// delete 2nd and 8th Task so that the non-found Task entities will be queried
|
// delete 2nd and 8th Task so that the non-found Task entities will be queried
|
||||||
// in 2 different batches.
|
// in 2 different batches.
|
||||||
session.delete( tasks.get( 1 ) );
|
session.delete( tasks.get( 1 ) );
|
||||||
|
@ -101,14 +99,15 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final AStatementInspector statementInspector = (AStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
|
||||||
final List<Employee> employees = doInHibernate(
|
final List<Employee> employees = scope.fromTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
List<Employee> results =
|
List<Employee> results =
|
||||||
session.createQuery( "from Employee e order by e.id", Employee.class ).getResultList();
|
session.createQuery( "from Employee e order by e.id", Employee.class ).getResultList();
|
||||||
for ( int i = 0 ; i < tasks.size() ; i++ ) {
|
for ( Task task : tasks ) {
|
||||||
checkInBatchFetchQueue( tasks.get( i ).id, session, false );
|
checkInBatchFetchQueue( task.id, session, false );
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
@ -145,7 +144,7 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
assertEquals( 1, paramterCounts.get( 3 ).intValue() );
|
assertEquals( 1, paramterCounts.get( 3 ).intValue() );
|
||||||
|
|
||||||
assertEquals( NUMBER_OF_EMPLOYEES, employees.size() );
|
assertEquals( NUMBER_OF_EMPLOYEES, employees.size() );
|
||||||
for ( int i = 0 ; i < NUMBER_OF_EMPLOYEES ; i++ ) {
|
for ( int i = 0; i < NUMBER_OF_EMPLOYEES; i++ ) {
|
||||||
if ( i == 1 || i == 7 ) {
|
if ( i == 1 || i == 7 ) {
|
||||||
assertNull( employees.get( i ).task );
|
assertNull( employees.get( i ).task );
|
||||||
}
|
}
|
||||||
|
@ -156,10 +155,10 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMostNotFoundFromQuery() {
|
public void testMostNotFoundFromQuery(SessionFactoryScope scope) {
|
||||||
|
|
||||||
doInHibernate(
|
scope.inTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
// delete all but last Task entity
|
// delete all but last Task entity
|
||||||
for ( int i = 0; i < 7; i++ ) {
|
for ( int i = 0; i < 7; i++ ) {
|
||||||
session.delete( tasks.get( i ) );
|
session.delete( tasks.get( i ) );
|
||||||
|
@ -167,14 +166,15 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final AStatementInspector statementInspector = (AStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
|
||||||
final List<Employee> employees = doInHibernate(
|
final List<Employee> employees = scope.fromTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
List<Employee> results =
|
List<Employee> results =
|
||||||
session.createQuery( "from Employee e order by e.id", Employee.class ).getResultList();
|
session.createQuery( "from Employee e order by e.id", Employee.class ).getResultList();
|
||||||
for ( int i = 0 ; i < tasks.size() ; i++ ) {
|
for ( Task task : tasks ) {
|
||||||
checkInBatchFetchQueue( tasks.get( i ).id, session, false );
|
checkInBatchFetchQueue( task.id, session, false );
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
|
|
||||||
assertEquals( NUMBER_OF_EMPLOYEES, employees.size() );
|
assertEquals( NUMBER_OF_EMPLOYEES, employees.size() );
|
||||||
|
|
||||||
for ( int i = 0 ; i < NUMBER_OF_EMPLOYEES ; i++ ) {
|
for ( int i = 0; i < NUMBER_OF_EMPLOYEES; i++ ) {
|
||||||
if ( i == 7 ) {
|
if ( i == 7 ) {
|
||||||
assertEquals( tasks.get( i ).id, employees.get( i ).task.id );
|
assertEquals( tasks.get( i ).id, employees.get( i ).task.id );
|
||||||
}
|
}
|
||||||
|
@ -244,19 +244,20 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotFoundFromGet() {
|
public void testNotFoundFromGet(SessionFactoryScope scope) {
|
||||||
|
|
||||||
doInHibernate(
|
scope.inTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
// delete task so it is not found later when getting the Employee.
|
// delete task so it is not found later when getting the Employee.
|
||||||
session.delete( tasks.get( 0 ) );
|
session.delete( tasks.get( 0 ) );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final AStatementInspector statementInspector = (AStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
|
||||||
doInHibernate(
|
scope.inTransaction(
|
||||||
this::sessionFactory, session -> {
|
session -> {
|
||||||
Employee employee = session.get( Employee.class, "employee00" );
|
Employee employee = session.get( Employee.class, "employee00" );
|
||||||
checkInBatchFetchQueue( tasks.get( 0 ).id, session, false );
|
checkInBatchFetchQueue( tasks.get( 0 ).id, session, false );
|
||||||
assertNotNull( employee );
|
assertNotNull( employee );
|
||||||
|
@ -266,18 +267,17 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
|
|
||||||
final List<Integer> paramterCounts = statementInspector.parameterCounts;
|
final List<Integer> paramterCounts = statementInspector.parameterCounts;
|
||||||
|
|
||||||
// there should be 2 SQL statements executed
|
// there should be 1 SQL statements executed, we select the tasks with a join
|
||||||
// 1) query to load Employee entity by ID (associated Tasks is registered for batch loading)
|
// 1) query to load Employee entity by ID and fetch the Tasks
|
||||||
// 2) batch will only contain the ID for the associated Task (which will not be found)
|
assertEquals( 1, paramterCounts.size() );
|
||||||
assertEquals( 2, paramterCounts.size() );
|
|
||||||
|
|
||||||
// query loading Employee entities shouldn't have any parameters
|
// query loading Employee entities shouldn't have any parameters
|
||||||
assertEquals( 1, paramterCounts.get( 0 ).intValue() );
|
assertEquals( 1, paramterCounts.get( 0 ).intValue() );
|
||||||
|
|
||||||
// Will result in just querying a single Task (because the batch is empty).
|
// // Will result in just querying a single Task (because the batch is empty).
|
||||||
// query should have 1 parameter;
|
// // query should have 1 parameter;
|
||||||
// Task won't be found.
|
// // Task won't be found.
|
||||||
assertEquals( 1, paramterCounts.get( 1 ).intValue() );
|
// assertEquals( 1, paramterCounts.get( 1 ).intValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkInBatchFetchQueue(long id, Session session, boolean expected) {
|
private static void checkInBatchFetchQueue(long id, Session session, boolean expected) {
|
||||||
|
@ -298,7 +298,7 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
@Id
|
@Id
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@OneToOne(optional = true)
|
@OneToOne
|
||||||
@JoinColumn(foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
|
||||||
@NotFound(action = NotFoundAction.IGNORE)
|
@NotFound(action = NotFoundAction.IGNORE)
|
||||||
private Task task;
|
private Task task;
|
||||||
|
@ -324,13 +324,18 @@ public class BatchFetchNotFoundIgnoreDefaultStyleTest extends BaseCoreFunctional
|
||||||
public static class AStatementInspector implements StatementInspector {
|
public static class AStatementInspector implements StatementInspector {
|
||||||
private List<Integer> parameterCounts = new ArrayList<>();
|
private List<Integer> parameterCounts = new ArrayList<>();
|
||||||
|
|
||||||
|
public AStatementInspector() {
|
||||||
|
}
|
||||||
|
|
||||||
public String inspect(String sql) {
|
public String inspect(String sql) {
|
||||||
parameterCounts.add( countParameters( sql ) );
|
parameterCounts.add( countParameters( sql ) );
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clear() {
|
private void clear() {
|
||||||
parameterCounts.clear();
|
parameterCounts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int countParameters(String sql) {
|
private int countParameters(String sql) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int parameterIndex = sql.indexOf( '?' );
|
int parameterIndex = sql.indexOf( '?' );
|
|
@ -4,13 +4,21 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
@ -21,34 +29,30 @@ import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.OrderBy;
|
import jakarta.persistence.OrderBy;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import org.hibernate.cfg.Configuration;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class BatchFetchReferencedColumnNameTest extends BaseCoreFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
@DomainModel(
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
annotatedClasses = {
|
||||||
return new Class<?>[]{ Child.class, Parent.class };
|
BatchFetchReferencedColumnNameTest.Child.class,
|
||||||
}
|
BatchFetchReferencedColumnNameTest.Parent.class
|
||||||
|
}
|
||||||
@Override
|
)
|
||||||
protected void configure(Configuration configuration) {
|
@SessionFactory
|
||||||
super.configure( configuration );
|
@ServiceRegistry(
|
||||||
|
settings = {
|
||||||
configuration.setProperty( AvailableSettings.SHOW_SQL, Boolean.TRUE.toString() );
|
@Setting(name = AvailableSettings.SHOW_SQL, value = "true"),
|
||||||
configuration.setProperty( AvailableSettings.FORMAT_SQL, Boolean.TRUE.toString() );
|
@Setting(name = AvailableSettings.FORMAT_SQL, value = "true"),
|
||||||
|
@Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "64")
|
||||||
configuration.setProperty( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "64" );
|
}
|
||||||
}
|
)
|
||||||
|
public class BatchFetchReferencedColumnNameTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-13059")
|
@TestForIssue(jiraKey = "HHH-13059")
|
||||||
public void test() throws Exception {
|
public void test(SessionFactoryScope scope) throws Exception {
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Parent p = new Parent();
|
Parent p = new Parent();
|
||||||
p.setId( 1L );
|
p.setId( 1L );
|
||||||
session.save( p );
|
session.save( p );
|
||||||
|
@ -66,11 +70,11 @@ public class BatchFetchReferencedColumnNameTest extends BaseCoreFunctionalTestCa
|
||||||
session.save( c2 );
|
session.save( c2 );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
Parent p = session.get( Parent.class, 1L );
|
Parent p = session.get( Parent.class, 1L );
|
||||||
Assert.assertNotNull( p );
|
assertNotNull( p );
|
||||||
|
|
||||||
Assert.assertEquals( 2, p.getChildren().size() );
|
assertEquals( 2, p.getChildren().size() );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,21 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.FetchType;
|
import jakarta.persistence.FetchType;
|
||||||
|
@ -18,26 +28,29 @@ import jakarta.persistence.LockModeType;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.*;
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
public class BatchFetchRefreshTest extends BaseNonConfigCoreFunctionalTestCase {
|
BatchFetchRefreshTest.Parent.class,
|
||||||
|
BatchFetchRefreshTest.Child.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@ServiceRegistry(
|
||||||
|
settings = @Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "8")
|
||||||
|
)
|
||||||
|
public class BatchFetchRefreshTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
public void testRefreshWithBatch(SessionFactoryScope scope) {
|
||||||
public void testRefreshWithBatch() {
|
scope.inTransaction( session -> {
|
||||||
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
|
||||||
|
|
||||||
// Retrieve one of the parents into the session.
|
// Retrieve one of the parents into the session.
|
||||||
Parent parent = session.find(Parent.class, 1);
|
Parent parent = session.find( Parent.class, 1 );
|
||||||
Assert.assertNotNull(parent);
|
assertNotNull( parent );
|
||||||
|
|
||||||
// Retrieve children but keep their parents lazy!
|
// Retrieve children but keep their parents lazy!
|
||||||
// This allows batch fetching to do its thing when we refresh below.
|
// This allows batch fetching to do its thing when we refresh below.
|
||||||
|
@ -50,16 +63,16 @@ public class BatchFetchRefreshTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
parent.getChildren().size();
|
parent.getChildren().size();
|
||||||
|
|
||||||
// Another interesting thing to note - em.getLockMode returns an incorrect value after the above refresh
|
// Another interesting thing to note - em.getLockMode returns an incorrect value after the above refresh
|
||||||
Assert.assertEquals( LockModeType.PESSIMISTIC_WRITE, session.getLockMode( parent ) );
|
assertEquals( LockModeType.PESSIMISTIC_WRITE, session.getLockMode( parent ) );
|
||||||
});
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setupData() {
|
public void setupData(SessionFactoryScope scope) {
|
||||||
final int numParents = 5;
|
final int numParents = 5;
|
||||||
final int childrenPerParent = 2;
|
final int childrenPerParent = 2;
|
||||||
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
int k = 1;
|
int k = 1;
|
||||||
for ( int i = 1; i <= numParents; i++ ) {
|
for ( int i = 1; i <= numParents; i++ ) {
|
||||||
Parent parent = new Parent();
|
Parent parent = new Parent();
|
||||||
|
@ -69,7 +82,7 @@ public class BatchFetchRefreshTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
session.persist( parent );
|
session.persist( parent );
|
||||||
|
|
||||||
// Create some children for each parent...
|
// Create some children for each parent...
|
||||||
for ( int j = 0; j < childrenPerParent; j++,k++ ) {
|
for ( int j = 0; j < childrenPerParent; j++, k++ ) {
|
||||||
Child child = new Child();
|
Child child = new Child();
|
||||||
child.childId = k;
|
child.childId = k;
|
||||||
child.name = "Child_" + i + "_" + j;
|
child.name = "Child_" + i + "_" + j;
|
||||||
|
@ -79,24 +92,10 @@ public class BatchFetchRefreshTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
session.persist( child );
|
session.persist( child );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
} );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class[] getAnnotatedClasses() {
|
|
||||||
return new Class[] {
|
|
||||||
Parent.class,
|
|
||||||
Child.class
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void addSettings(Map settings) {
|
|
||||||
super.addSettings( settings );
|
|
||||||
settings.put( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "8" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Parent")
|
@Entity(name = "Parent")
|
||||||
public static class Parent {
|
public static class Parent {
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.batchfetch;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
xmlMappings = "org/hibernate/orm/test/batchfetch/ProductLine.hbm.xml",
|
||||||
|
annotatedClasses = BatchLoadableEntity.class
|
||||||
|
)
|
||||||
|
@SessionFactory(
|
||||||
|
generateStatistics = true
|
||||||
|
)
|
||||||
|
@ServiceRegistry(
|
||||||
|
settings = {
|
||||||
|
@Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public class BatchFetchTest {
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
@Test
|
||||||
|
public void testBatchFetch(SessionFactoryScope scope) {
|
||||||
|
ProductLine ossProductLine = new ProductLine();
|
||||||
|
Model hibernateModel = new Model( ossProductLine );
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
ProductLine cars = new ProductLine();
|
||||||
|
cars.setDescription( "Cars" );
|
||||||
|
Model monaro = new Model( cars );
|
||||||
|
monaro.setName( "monaro" );
|
||||||
|
monaro.setDescription( "Holden Monaro" );
|
||||||
|
Model hsv = new Model( cars );
|
||||||
|
hsv.setName( "hsv" );
|
||||||
|
hsv.setDescription( "Holden Commodore HSV" );
|
||||||
|
session.save( cars );
|
||||||
|
|
||||||
|
ossProductLine.setDescription( "OSS" );
|
||||||
|
Model jboss = new Model( ossProductLine );
|
||||||
|
jboss.setName( "JBoss" );
|
||||||
|
jboss.setDescription( "JBoss Application Server" );
|
||||||
|
|
||||||
|
hibernateModel.setName( "Hibernate" );
|
||||||
|
hibernateModel.setDescription( "Hibernate" );
|
||||||
|
Model cache = new Model( ossProductLine );
|
||||||
|
cache.setName( "JBossCache" );
|
||||||
|
cache.setDescription( "JBoss TreeCache" );
|
||||||
|
session.save( ossProductLine );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.getSessionFactory().getCache().evictEntityRegion( Model.class );
|
||||||
|
scope.getSessionFactory().getCache().evictEntityRegion( ProductLine.class );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
List<ProductLine> list = session.createQuery( "from ProductLine pl order by pl.description" )
|
||||||
|
.list();
|
||||||
|
ProductLine cars = list.get( 0 );
|
||||||
|
ProductLine oss = list.get( 1 );
|
||||||
|
assertFalse( Hibernate.isInitialized( cars.getModels() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( oss.getModels() ) );
|
||||||
|
assertEquals( 2, cars.getModels().size() ); //fetch both collections
|
||||||
|
assertTrue( Hibernate.isInitialized( cars.getModels() ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( oss.getModels() ) );
|
||||||
|
|
||||||
|
session.clear();
|
||||||
|
|
||||||
|
List<Model> models = session.createQuery( "from Model m" ).list();
|
||||||
|
Model hibernate = session.get( Model.class, hibernateModel.getId() );
|
||||||
|
hibernate.getProductLine().getId();
|
||||||
|
for ( Model aList : models ) {
|
||||||
|
assertFalse( Hibernate.isInitialized( aList.getProductLine() ) );
|
||||||
|
}
|
||||||
|
assertEquals( hibernate.getProductLine().getDescription(), "OSS" ); //fetch both productlines
|
||||||
|
|
||||||
|
session.clear();
|
||||||
|
|
||||||
|
Iterator<Model> iter = session.createQuery( "from Model" ).list().iterator();
|
||||||
|
models = new ArrayList();
|
||||||
|
while ( iter.hasNext() ) {
|
||||||
|
models.add( iter.next() );
|
||||||
|
}
|
||||||
|
Model m = models.get( 0 );
|
||||||
|
m.getDescription(); //fetch a batch of 4
|
||||||
|
|
||||||
|
session.clear();
|
||||||
|
|
||||||
|
list = session.createQuery( "from ProductLine" ).list();
|
||||||
|
ProductLine pl = list.get( 0 );
|
||||||
|
ProductLine pl2 = list.get( 1 );
|
||||||
|
session.evict( pl2 );
|
||||||
|
pl.getModels().size(); //fetch just one collection! (how can we write an assertion for that??)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
List<ProductLine> list = session.createQuery( "from ProductLine pl order by pl.description" )
|
||||||
|
.list();
|
||||||
|
ProductLine cars = list.get( 0 );
|
||||||
|
ProductLine oss = list.get( 1 );
|
||||||
|
assertEquals( cars.getModels().size(), 2 );
|
||||||
|
assertEquals( oss.getModels().size(), 3 );
|
||||||
|
session.delete( cars );
|
||||||
|
session.delete( oss );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings({ "unchecked" })
|
||||||
|
public void testBatchFetch2(SessionFactoryScope scope) {
|
||||||
|
int size = 32 + 14;
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
for ( int i = 0; i < size; i++ ) {
|
||||||
|
session.save( new BatchLoadableEntity( i ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
// load them all as proxies
|
||||||
|
for ( int i = 0; i < size; i++ ) {
|
||||||
|
BatchLoadableEntity entity = session.load( BatchLoadableEntity.class, i );
|
||||||
|
assertFalse( Hibernate.isInitialized( entity ) );
|
||||||
|
}
|
||||||
|
scope.getSessionFactory().getStatistics().clear();
|
||||||
|
// now start initializing them...
|
||||||
|
for ( int i = 0; i < size; i++ ) {
|
||||||
|
BatchLoadableEntity entity = session.load( BatchLoadableEntity.class, i );
|
||||||
|
Hibernate.initialize( entity );
|
||||||
|
assertTrue( Hibernate.isInitialized( entity ) );
|
||||||
|
}
|
||||||
|
// so at this point, all entities are initialized. see how many fetches were performed.
|
||||||
|
final int expectedFetchCount;
|
||||||
|
// if ( sessionFactory().getSettings().getBatchFetchStyle() == BatchFetchStyle.LEGACY ) {
|
||||||
|
// expectedFetchCount = 3; // (32 + 10 + 4)
|
||||||
|
// }
|
||||||
|
// else if ( sessionFactory().getSettings().getBatchFetchStyle() == BatchFetchStyle.DYNAMIC ) {
|
||||||
|
// expectedFetchCount = 2; // (32 + 14) : because we limited batch-size to 32
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// PADDED
|
||||||
|
expectedFetchCount = 2; // (32 + 16*) with the 16 being padded
|
||||||
|
// }
|
||||||
|
assertEquals(
|
||||||
|
expectedFetchCount,
|
||||||
|
scope.getSessionFactory().getStatistics()
|
||||||
|
.getEntityStatistics( BatchLoadableEntity.class.getName() )
|
||||||
|
.getFetchCount()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete BatchLoadableEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Model" ).executeUpdate();
|
||||||
|
session.createQuery( "delete ProductLine" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
|
@ -1,9 +1,17 @@
|
||||||
package org.hibernate.orm.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
import org.hibernate.LockMode;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import org.hibernate.LockOptions;
|
||||||
|
import org.hibernate.annotations.Fetch;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
import java.util.Map;
|
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Jpa;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.FetchType;
|
import jakarta.persistence.FetchType;
|
||||||
|
@ -11,38 +19,23 @@ import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import org.hibernate.LockOptions;
|
|
||||||
import org.hibernate.annotations.Fetch;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
||||||
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
|
||||||
import org.hibernate.loader.BatchFetchStyle;
|
|
||||||
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class BatchingEntityLoaderInitializationWithNoLockModeTest extends BaseEntityManagerFunctionalTestCase {
|
@Jpa(
|
||||||
|
annotatedClasses = {
|
||||||
|
BatchingEntityLoaderInitializationWithNoLockModeTest.MainEntity.class,
|
||||||
|
BatchingEntityLoaderInitializationWithNoLockModeTest.SubEntity.class
|
||||||
|
},
|
||||||
|
properties = { @Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "5") }
|
||||||
|
)
|
||||||
|
public class BatchingEntityLoaderInitializationWithNoLockModeTest {
|
||||||
|
|
||||||
private Long mainId;
|
private Long mainId;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class<?>[] { MainEntity.class, SubEntity.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
@Override
|
|
||||||
protected Map buildSettings() {
|
|
||||||
Map settings = super.buildSettings();
|
|
||||||
settings.put( AvailableSettings.BATCH_FETCH_STYLE, BatchFetchStyle.LEGACY );
|
|
||||||
settings.put( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, 5 );
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJoin() {
|
public void testJoin(EntityManagerFactoryScope scope) {
|
||||||
doInJPA( this::entityManagerFactory, em -> {
|
scope.inTransaction( em -> {
|
||||||
SubEntity sub = new SubEntity();
|
SubEntity sub = new SubEntity();
|
||||||
em.persist( sub );
|
em.persist( sub );
|
||||||
|
|
||||||
|
@ -51,9 +44,9 @@ public class BatchingEntityLoaderInitializationWithNoLockModeTest extends BaseEn
|
||||||
em.persist( main );
|
em.persist( main );
|
||||||
|
|
||||||
this.mainId = main.getId();
|
this.mainId = main.getId();
|
||||||
});
|
} );
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, em -> {
|
scope.inTransaction( em -> {
|
||||||
EntityPersister entityPersister = ( (MetamodelImplementor) em.getMetamodel() )
|
EntityPersister entityPersister = ( (MetamodelImplementor) em.getMetamodel() )
|
||||||
.entityPersister( MainEntity.class );
|
.entityPersister( MainEntity.class );
|
||||||
|
|
||||||
|
@ -61,8 +54,9 @@ public class BatchingEntityLoaderInitializationWithNoLockModeTest extends BaseEn
|
||||||
LockOptions lockOptions = new LockOptions( LockMode.NONE );
|
LockOptions lockOptions = new LockOptions( LockMode.NONE );
|
||||||
lockOptions.setTimeOut( 10 );
|
lockOptions.setTimeOut( 10 );
|
||||||
|
|
||||||
MainEntity main = (MainEntity) entityPersister.load( this.mainId, null, lockOptions,
|
MainEntity main = (MainEntity) entityPersister.
|
||||||
(SharedSessionContractImplementor) em );
|
load( this.mainId, null, lockOptions, (SharedSessionContractImplementor) em );
|
||||||
|
|
||||||
assertNotNull( main.getSub() );
|
assertNotNull( main.getSub() );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.batchfetch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = { A.class, B.class }
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@ServiceRegistry(
|
||||||
|
settings = @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false")
|
||||||
|
)
|
||||||
|
public class DynamicBatchFetchTest {
|
||||||
|
private static int currentId = 1;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicBatchFetch(SessionFactoryScope scope) {
|
||||||
|
Integer aId1 = createAAndB( "foo_1", scope );
|
||||||
|
Integer aId2 = createAAndB( "foo_2", scope );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
List resultList = session.createQuery( "from A where id in (" + aId1 + "," + aId2 + ") order by id" )
|
||||||
|
.list();
|
||||||
|
A a1 = (A) resultList.get( 0 );
|
||||||
|
A a2 = (A) resultList.get( 1 );
|
||||||
|
assertEquals( aId1, a1.getId() );
|
||||||
|
assertEquals( aId2, a2.getId() );
|
||||||
|
assertFalse( Hibernate.isInitialized( a1.getB() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( a2.getB() ) );
|
||||||
|
B b = a1.getB();
|
||||||
|
assertFalse( Hibernate.isInitialized( b ) );
|
||||||
|
assertEquals( "foo_1", b.getOtherProperty() );
|
||||||
|
assertTrue( Hibernate.isInitialized( a1.getB() ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( a2.getB() ) );
|
||||||
|
assertEquals( "foo_2", a2.getB().getOtherProperty() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int createAAndB(String otherProperty, SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
B b = new B();
|
||||||
|
b.setIdPart1( currentId );
|
||||||
|
b.setIdPart2( currentId );
|
||||||
|
b.setOtherProperty( otherProperty );
|
||||||
|
session.save( b );
|
||||||
|
|
||||||
|
A a = new A();
|
||||||
|
a.setId( currentId );
|
||||||
|
a.setB( b );
|
||||||
|
|
||||||
|
session.save( a );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
currentId++;
|
||||||
|
|
||||||
|
return currentId - 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,43 +4,40 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.loader.BatchFetchStyle;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.junit.Test;
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class PaddedBatchFetchTestCase extends BaseCoreFunctionalTestCase {
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
@Override
|
@DomainModel(
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
annotatedClasses = { Country.class, City.class }
|
||||||
return new Class<?>[]{ Country.class, City.class };
|
)
|
||||||
}
|
@SessionFactory
|
||||||
|
@ServiceRegistry(
|
||||||
@Override
|
settings = {
|
||||||
protected void configure(Configuration configuration) {
|
@Setting(name = AvailableSettings.SHOW_SQL, value = "true"),
|
||||||
super.configure( configuration );
|
@Setting(name = AvailableSettings.FORMAT_SQL, value = "true"),
|
||||||
|
@Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "15")
|
||||||
configuration.setProperty( AvailableSettings.SHOW_SQL, Boolean.TRUE.toString() );
|
}
|
||||||
configuration.setProperty( AvailableSettings.FORMAT_SQL, Boolean.TRUE.toString() );
|
)
|
||||||
|
public class DynamicBatchFetchTestCase {
|
||||||
configuration.setProperty( AvailableSettings.BATCH_FETCH_STYLE, BatchFetchStyle.PADDED.name() );
|
|
||||||
configuration.setProperty( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "15" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-12835")
|
@TestForIssue(jiraKey = "HHH-12835")
|
||||||
public void paddedBatchFetchTest() throws Exception {
|
public void batchFetchTest(SessionFactoryScope scope) {
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
// Having DEFAULT_BATCH_FETCH_SIZE=15
|
// Having DEFAULT_BATCH_FETCH_SIZE=15
|
||||||
// results in batchSizes = [15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
|
// results in batchSizes = [15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
|
||||||
// Let's create 11 countries so batch size 15 will be used with padded values,
|
// Let's create 11 countries so batch size 15 will be used with padded values,
|
||||||
|
@ -54,7 +51,7 @@ public class PaddedBatchFetchTestCase extends BaseCoreFunctionalTestCase {
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
scope.inTransaction( session -> {
|
||||||
List<City> allCities = session.createQuery( "from City", City.class ).list();
|
List<City> allCities = session.createQuery( "from City", City.class ).list();
|
||||||
|
|
||||||
// this triggers countries to be fetched in batch
|
// this triggers countries to be fetched in batch
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//$Id: Model.java 4460 2004-08-29 12:04:14Z oneovthafew $
|
//$Id: Model.java 4460 2004-08-29 12:04:14Z oneovthafew $
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -9,7 +9,7 @@
|
||||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
<hibernate-mapping package="org.hibernate.test.batchfetch">
|
<hibernate-mapping package="org.hibernate.orm.test.batchfetch">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//$Id: ProductLine.java 4460 2004-08-29 12:04:14Z oneovthafew $
|
//$Id: ProductLine.java 4460 2004-08-29 12:04:14Z oneovthafew $
|
||||||
package org.hibernate.test.batchfetch;
|
package org.hibernate.orm.test.batchfetch;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
|
@ -1,23 +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.test.batchfetch;
|
|
||||||
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.loader.BatchFetchStyle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Gail Badner
|
|
||||||
*/
|
|
||||||
public class BatchFetchNotFoundIgnoreDynamicStyleTest extends BatchFetchNotFoundIgnoreDefaultStyleTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(Configuration configuration) {
|
|
||||||
super.configure( configuration );
|
|
||||||
configuration.getProperties().put( Environment.BATCH_FETCH_STYLE, BatchFetchStyle.DYNAMIC );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +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.test.batchfetch;
|
|
||||||
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.loader.BatchFetchStyle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Gail Badner
|
|
||||||
*/
|
|
||||||
public class BatchFetchNotFoundIgnorePaddedStyleTest extends BatchFetchNotFoundIgnoreDefaultStyleTest {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(Configuration configuration) {
|
|
||||||
super.configure( configuration );
|
|
||||||
configuration.getProperties().put( Environment.BATCH_FETCH_STYLE, BatchFetchStyle.PADDED );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,187 +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.test.batchfetch;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.loader.BatchFetchStyle;
|
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Gavin King
|
|
||||||
*/
|
|
||||||
public class BatchFetchTest extends BaseCoreFunctionalTestCase {
|
|
||||||
@Override
|
|
||||||
public String[] getMappings() {
|
|
||||||
return new String[] { "batchfetch/ProductLine.hbm.xml" };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[] { BatchLoadableEntity.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(Configuration configuration) {
|
|
||||||
super.configure( configuration );
|
|
||||||
configuration.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" );
|
|
||||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings( {"unchecked"})
|
|
||||||
@Test
|
|
||||||
public void testBatchFetch() {
|
|
||||||
Session s = openSession();
|
|
||||||
Transaction t = s.beginTransaction();
|
|
||||||
ProductLine cars = new ProductLine();
|
|
||||||
cars.setDescription( "Cars" );
|
|
||||||
Model monaro = new Model( cars );
|
|
||||||
monaro.setName( "monaro" );
|
|
||||||
monaro.setDescription( "Holden Monaro" );
|
|
||||||
Model hsv = new Model( cars );
|
|
||||||
hsv.setName( "hsv" );
|
|
||||||
hsv.setDescription( "Holden Commodore HSV" );
|
|
||||||
s.save( cars );
|
|
||||||
|
|
||||||
ProductLine oss = new ProductLine();
|
|
||||||
oss.setDescription( "OSS" );
|
|
||||||
Model jboss = new Model( oss );
|
|
||||||
jboss.setName( "JBoss" );
|
|
||||||
jboss.setDescription( "JBoss Application Server" );
|
|
||||||
Model hibernate = new Model( oss );
|
|
||||||
hibernate.setName( "Hibernate" );
|
|
||||||
hibernate.setDescription( "Hibernate" );
|
|
||||||
Model cache = new Model( oss );
|
|
||||||
cache.setName( "JBossCache" );
|
|
||||||
cache.setDescription( "JBoss TreeCache" );
|
|
||||||
s.save( oss );
|
|
||||||
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s.getSessionFactory().getCache().evictEntityRegion( Model.class );
|
|
||||||
s.getSessionFactory().getCache().evictEntityRegion( ProductLine.class );
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
t = s.beginTransaction();
|
|
||||||
|
|
||||||
List list = s.createQuery( "from ProductLine pl order by pl.description" ).list();
|
|
||||||
cars = ( ProductLine ) list.get( 0 );
|
|
||||||
oss = ( ProductLine ) list.get( 1 );
|
|
||||||
assertFalse( Hibernate.isInitialized( cars.getModels() ) );
|
|
||||||
assertFalse( Hibernate.isInitialized( oss.getModels() ) );
|
|
||||||
assertEquals( cars.getModels().size(), 2 ); //fetch both collections
|
|
||||||
assertTrue( Hibernate.isInitialized( cars.getModels() ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( oss.getModels() ) );
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
|
|
||||||
list = s.createQuery( "from Model m" ).list();
|
|
||||||
hibernate = ( Model ) s.get( Model.class, hibernate.getId() );
|
|
||||||
hibernate.getProductLine().getId();
|
|
||||||
for ( Object aList : list ) {
|
|
||||||
assertFalse( Hibernate.isInitialized( ((Model) aList).getProductLine() ) );
|
|
||||||
}
|
|
||||||
assertEquals( hibernate.getProductLine().getDescription(), "OSS" ); //fetch both productlines
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
|
|
||||||
Iterator iter = s.createQuery( "from Model" ).list().iterator();
|
|
||||||
list = new ArrayList();
|
|
||||||
while ( iter.hasNext() ) {
|
|
||||||
list.add( iter.next() );
|
|
||||||
}
|
|
||||||
Model m = ( Model ) list.get( 0 );
|
|
||||||
m.getDescription(); //fetch a batch of 4
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
|
|
||||||
list = s.createQuery( "from ProductLine" ).list();
|
|
||||||
ProductLine pl = ( ProductLine ) list.get( 0 );
|
|
||||||
ProductLine pl2 = ( ProductLine ) list.get( 1 );
|
|
||||||
s.evict( pl2 );
|
|
||||||
pl.getModels().size(); //fetch just one collection! (how can we write an assertion for that??)
|
|
||||||
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
t = s.beginTransaction();
|
|
||||||
list = s.createQuery( "from ProductLine pl order by pl.description" ).list();
|
|
||||||
cars = ( ProductLine ) list.get( 0 );
|
|
||||||
oss = ( ProductLine ) list.get( 1 );
|
|
||||||
assertEquals( cars.getModels().size(), 2 );
|
|
||||||
assertEquals( oss.getModels().size(), 3 );
|
|
||||||
s.delete( cars );
|
|
||||||
s.delete( oss );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings( {"unchecked"})
|
|
||||||
public void testBatchFetch2() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
int size = 32+14;
|
|
||||||
for ( int i = 0; i < size; i++ ) {
|
|
||||||
s.save( new BatchLoadableEntity( i ) );
|
|
||||||
}
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
// load them all as proxies
|
|
||||||
for ( int i = 0; i < size; i++ ) {
|
|
||||||
BatchLoadableEntity entity = (BatchLoadableEntity) s.load( BatchLoadableEntity.class, i );
|
|
||||||
assertFalse( Hibernate.isInitialized( entity ) );
|
|
||||||
}
|
|
||||||
sessionFactory().getStatistics().clear();
|
|
||||||
// now start initializing them...
|
|
||||||
for ( int i = 0; i < size; i++ ) {
|
|
||||||
BatchLoadableEntity entity = (BatchLoadableEntity) s.load( BatchLoadableEntity.class, i );
|
|
||||||
Hibernate.initialize( entity );
|
|
||||||
assertTrue( Hibernate.isInitialized( entity ) );
|
|
||||||
}
|
|
||||||
// so at this point, all entities are initialized. see how many fetches were performed.
|
|
||||||
final int expectedFetchCount;
|
|
||||||
if ( sessionFactory().getSettings().getBatchFetchStyle() == BatchFetchStyle.LEGACY ) {
|
|
||||||
expectedFetchCount = 3; // (32 + 10 + 4)
|
|
||||||
}
|
|
||||||
else if ( sessionFactory().getSettings().getBatchFetchStyle() == BatchFetchStyle.DYNAMIC ) {
|
|
||||||
expectedFetchCount = 2; // (32 + 14) : because we limited batch-size to 32
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// PADDED
|
|
||||||
expectedFetchCount = 2; // (32 + 16*) with the 16 being padded
|
|
||||||
}
|
|
||||||
assertEquals( expectedFetchCount, sessionFactory().getStatistics().getEntityStatistics( BatchLoadableEntity.class.getName() ).getFetchCount() );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
s.createQuery( "delete BatchLoadableEntity" ).executeUpdate();
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,98 +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.test.batchfetch;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class DynamicBatchFetchTest extends BaseCoreFunctionalTestCase {
|
|
||||||
private static int currentId = 1;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(Configuration configuration) {
|
|
||||||
super.configure( configuration );
|
|
||||||
configuration.setProperty( AvailableSettings.BATCH_FETCH_STYLE, "DYNAMIC" );
|
|
||||||
super.configure( configuration );
|
|
||||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[] { A.class, B.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDynamicBatchFetch() {
|
|
||||||
Integer aId1 = createAAndB();
|
|
||||||
Integer aId2 = createAAndB();
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
List resultList = s.createQuery("from A where id in (" + aId1 + "," + aId2 + ") order by id" ).list();
|
|
||||||
A a1 = (A) resultList.get(0);
|
|
||||||
A a2 = (A) resultList.get( 1 );
|
|
||||||
assertEquals( aId1, a1.getId() );
|
|
||||||
assertEquals( aId2, a2.getId() );
|
|
||||||
assertFalse( Hibernate.isInitialized( a1.getB() ) );
|
|
||||||
assertFalse( Hibernate.isInitialized( a2.getB() ) );
|
|
||||||
assertEquals( "foo", a1.getB().getOtherProperty() );
|
|
||||||
assertTrue( Hibernate.isInitialized( a1.getB() ) );
|
|
||||||
// a2.getB() is still uninitialized
|
|
||||||
assertFalse( Hibernate.isInitialized( a2.getB() ) );
|
|
||||||
// the B entity has been loaded, but is has not been made the target of a2.getB() yet.
|
|
||||||
assertTrue( ( (SessionImplementor) session ).getPersistenceContext().containsEntity(
|
|
||||||
new EntityKey(
|
|
||||||
( (SessionImplementor) session ).getContextEntityIdentifier( a2.getB() ),
|
|
||||||
( (SessionImplementor) session ).getFactory().getEntityPersister( B.class.getName() )
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// a2.getB() is still uninitialized; getting the ID for a2.getB() did not initialize it.
|
|
||||||
assertFalse( Hibernate.isInitialized( a2.getB() ) );
|
|
||||||
assertEquals( "foo", a2.getB().getOtherProperty() );
|
|
||||||
// now it's initialized.
|
|
||||||
assertTrue( Hibernate.isInitialized( a2.getB() ) );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private int createAAndB() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
B b = new B();
|
|
||||||
b.setIdPart1( currentId );
|
|
||||||
b.setIdPart2( currentId);
|
|
||||||
b.setOtherProperty("foo");
|
|
||||||
s.save( b );
|
|
||||||
|
|
||||||
A a = new A();
|
|
||||||
a.setId( currentId );
|
|
||||||
a.setB( b );
|
|
||||||
|
|
||||||
s.save( a );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
currentId++;
|
|
||||||
|
|
||||||
return currentId - 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -214,7 +214,7 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
||||||
"/org/hibernate/test/hql/ComponentContainer.hbm.xml",
|
"/org/hibernate/test/hql/ComponentContainer.hbm.xml",
|
||||||
"/org/hibernate/test/hql/VariousKeywordPropertyEntity.hbm.xml",
|
"/org/hibernate/test/hql/VariousKeywordPropertyEntity.hbm.xml",
|
||||||
"/org/hibernate/test/hql/Constructor.hbm.xml",
|
"/org/hibernate/test/hql/Constructor.hbm.xml",
|
||||||
"batchfetch/ProductLine.hbm.xml",
|
"/org/hibernate/orm/test/batchfetch/ProductLine.hbm.xml",
|
||||||
"/org/hibernate/orm/test/cid/Customer.hbm.xml",
|
"/org/hibernate/orm/test/cid/Customer.hbm.xml",
|
||||||
"/org/hibernate/orm/test/cid/Order.hbm.xml",
|
"/org/hibernate/orm/test/cid/Order.hbm.xml",
|
||||||
"/org/hibernate/orm/test/cid/LineItem.hbm.xml",
|
"/org/hibernate/orm/test/cid/LineItem.hbm.xml",
|
||||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.dialect.AbstractHANADialect;
|
||||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||||
|
|
||||||
import org.hibernate.testing.DialectChecks;
|
import org.hibernate.testing.DialectChecks;
|
||||||
import org.hibernate.testing.FailureExpected;
|
|
||||||
import org.hibernate.testing.RequiresDialectFeature;
|
import org.hibernate.testing.RequiresDialectFeature;
|
||||||
import org.hibernate.testing.SkipForDialect;
|
import org.hibernate.testing.SkipForDialect;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
@ -35,7 +34,6 @@ import static org.junit.Assert.fail;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@FailureExpected( jiraKey = "none", message = "Support for scrolling collection fetches not yet implemented" )
|
|
||||||
public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase {
|
public class ScrollableCollectionFetchingTest extends BaseCoreFunctionalTestCase {
|
||||||
public String[] getMappings() {
|
public String[] getMappings() {
|
||||||
return new String[] { "hql/Animal.hbm.xml" };
|
return new String[] { "hql/Animal.hbm.xml" };
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class EJBQLTest extends BaseCoreFunctionalTestCase {
|
||||||
public String[] getMappings() {
|
public String[] getMappings() {
|
||||||
return new String[]{
|
return new String[]{
|
||||||
"hql/Animal.hbm.xml",
|
"hql/Animal.hbm.xml",
|
||||||
"batchfetch/ProductLine.hbm.xml",
|
"/org/hibernate/orm/test/batchfetch/ProductLine.hbm.xml",
|
||||||
"cid/Customer.hbm.xml",
|
"cid/Customer.hbm.xml",
|
||||||
"cid/Order.hbm.xml",
|
"cid/Order.hbm.xml",
|
||||||
"cid/LineItem.hbm.xml",
|
"cid/LineItem.hbm.xml",
|
||||||
|
|
|
@ -42,7 +42,7 @@ public abstract class QueryTranslatorTestCase extends BaseCoreFunctionalTestCase
|
||||||
"hql/CrazyIdFieldNames.hbm.xml",
|
"hql/CrazyIdFieldNames.hbm.xml",
|
||||||
"hql/SimpleEntityWithAssociation.hbm.xml",
|
"hql/SimpleEntityWithAssociation.hbm.xml",
|
||||||
"hql/ComponentContainer.hbm.xml",
|
"hql/ComponentContainer.hbm.xml",
|
||||||
"batchfetch/ProductLine.hbm.xml",
|
"/org/hibernate/orm/test/batchfetch/ProductLine.hbm.xml",
|
||||||
"cid/Customer.hbm.xml",
|
"cid/Customer.hbm.xml",
|
||||||
"cid/Order.hbm.xml",
|
"cid/Order.hbm.xml",
|
||||||
"cid/LineItem.hbm.xml",
|
"cid/LineItem.hbm.xml",
|
||||||
|
|
Loading…
Reference in New Issue