HHH-14877 - FetchMode.SUBSELECT ignored
This commit is contained in:
parent
b5558307a9
commit
e8e62c4d6c
|
@ -32,7 +32,6 @@ import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
|||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
* An {@link org.hibernate.engine.spi.ActionQueue} {@link Executable} for ensuring
|
||||
|
@ -148,11 +147,9 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
|
|||
this.affectedTableSpaces = spacesList.toArray( new String[ 0 ] );
|
||||
}
|
||||
|
||||
public static void schedule(ExecutionContext executionContext, SqmDmlStatement<?> statement) {
|
||||
public static void schedule(SharedSessionContractImplementor session, SqmDmlStatement<?> statement) {
|
||||
final List<EntityPersister> entityPersisters = new ArrayList<>( 1 );
|
||||
final MetamodelImplementor metamodel = executionContext.getSession()
|
||||
.getFactory()
|
||||
.getMetamodel();
|
||||
final MetamodelImplementor metamodel = session.getFactory().getMetamodel();
|
||||
if ( !( statement instanceof InsertStatement ) ) {
|
||||
entityPersisters.add( metamodel.entityPersister( statement.getTarget().getEntityName() ) );
|
||||
}
|
||||
|
@ -165,11 +162,10 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
schedule( executionContext, entityPersisters.toArray( new EntityPersister[0] ) );
|
||||
schedule( session, entityPersisters.toArray( new EntityPersister[0] ) );
|
||||
}
|
||||
|
||||
public static void schedule(ExecutionContext executionContext, EntityPersister... affectedQueryables) {
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
public static void schedule(SharedSessionContractImplementor session, EntityPersister... affectedQueryables) {
|
||||
final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, affectedQueryables );
|
||||
if ( session.isEventSource() ) {
|
||||
( (EventSource) session ).getActionQueue().addAction( action );
|
||||
|
@ -179,8 +175,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
public static void schedule(ExecutionContext executionContext, Set<String> affectedQueryables) {
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
public static void schedule(SharedSessionContractImplementor session, Set<String> affectedQueryables) {
|
||||
final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, affectedQueryables );
|
||||
if ( session.isEventSource() ) {
|
||||
( (EventSource) session ).getActionQueue().addAction( action );
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.function.Consumer;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
|
|
|
@ -458,4 +458,11 @@ public interface PersistentCollection<E> {
|
|||
default boolean isNewlyInstantiated() {
|
||||
return getKey() == null && !isDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #toString()} but without the silliness of rendering the elements
|
||||
*/
|
||||
default String render() {
|
||||
return getRole() + "#" + getKey() + "(initialized: " + wasInitialized() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.engine.spi;
|
||||
|
||||
|
@ -24,9 +24,10 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Tracks entity and collection keys that are available for batch
|
||||
* fetching, and the queries which were used to load entities, which
|
||||
* can be re-used as a subquery for loading owned collections.
|
||||
* Keeps track of:<ul>
|
||||
* <li>entity and collection keys that are available for batch fetching</li>
|
||||
* <li>details related to queries which load entities with sub-select-fetchable collections</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
|
@ -105,7 +106,15 @@ public class BatchFetchQueue {
|
|||
if ( subselectsByEntityKey == null ) {
|
||||
subselectsByEntityKey = CollectionHelper.mapOfSize( 12 );
|
||||
}
|
||||
subselectsByEntityKey.put( key, subquery );
|
||||
|
||||
final SubselectFetch previous = subselectsByEntityKey.put( key, subquery );
|
||||
if ( previous != null && LOG.isDebugEnabled() ) {
|
||||
LOG.debugf(
|
||||
"SubselectFetch previously registered with BatchFetchQueue for `%s#s`",
|
||||
key.getEntityName(),
|
||||
key.getIdentifier()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.engine.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* 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>.
|
||||
* 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.engine.spi;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -13,11 +14,13 @@ import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
|||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
* Encapsulates details related to entities which contain sub-select-fetchable
|
||||
* collections and which were loaded in a Session so that those collections may
|
||||
* be sub-select fetched later during initialization
|
||||
*/
|
||||
public class SubselectFetch {
|
||||
private final EntityValuedModelPart entityModelPart;
|
||||
|
@ -46,22 +49,39 @@ public class SubselectFetch {
|
|||
return entityModelPart;
|
||||
}
|
||||
|
||||
public List<JdbcParameter> getLoadingJdbcParameters() {
|
||||
// todo (6.0) : do not believe this is needed
|
||||
// - see org.hibernate.loader.ast.internal.LoaderSelectBuilder.generateSelect(org.hibernate.engine.spi.SubselectFetch)
|
||||
return loadingJdbcParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL AST select from which the owner was loaded
|
||||
*/
|
||||
public QuerySpec getLoadingSqlAst() {
|
||||
return loadingSqlAst;
|
||||
}
|
||||
|
||||
/**
|
||||
* The TableGroup for the owner within the {@link #getLoadingSqlAst()}
|
||||
*/
|
||||
public TableGroup getOwnerTableGroup() {
|
||||
return ownerTableGroup;
|
||||
}
|
||||
|
||||
public List<JdbcParameter> getLoadingJdbcParameters() {
|
||||
return loadingJdbcParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* The JDBC parameter bindings related to {@link #getLoadingSqlAst()} for
|
||||
* the specific execution that loaded the owners
|
||||
*/
|
||||
public JdbcParameterBindings getLoadingJdbcParameterBindings() {
|
||||
return loadingJdbcParameterBindings;
|
||||
}
|
||||
|
||||
/**
|
||||
*The entity-keys of all owners loaded from a particular execution
|
||||
*
|
||||
* Used for "empty collection" handling mostly
|
||||
*/
|
||||
public Set<EntityKey> getResultingEntityKeys() {
|
||||
return resultingEntityKeys;
|
||||
}
|
||||
|
@ -70,4 +90,61 @@ public class SubselectFetch {
|
|||
public String toString() {
|
||||
return "SubselectFetch(" + entityModelPart.getEntityMappingType().getEntityName() + ")";
|
||||
}
|
||||
|
||||
public static RegistrationHandler createRegistrationHandler(
|
||||
BatchFetchQueue batchFetchQueue,
|
||||
SelectStatement sqlAst,
|
||||
TableGroup tableGroup,
|
||||
List<JdbcParameter> jdbcParameters,
|
||||
JdbcParameterBindings jdbcParameterBindings) {
|
||||
final SubselectFetch subselectFetch = new SubselectFetch(
|
||||
null,
|
||||
sqlAst.getQuerySpec(),
|
||||
tableGroup,
|
||||
jdbcParameters,
|
||||
jdbcParameterBindings,
|
||||
new HashSet<>()
|
||||
);
|
||||
|
||||
return new StandardRegistrationHandler( batchFetchQueue, subselectFetch );
|
||||
}
|
||||
|
||||
public static RegistrationHandler createRegistrationHandler(
|
||||
BatchFetchQueue batchFetchQueue,
|
||||
SelectStatement sqlAst,
|
||||
List<JdbcParameter> jdbcParameters,
|
||||
JdbcParameterBindings jdbcParameterBindings) {
|
||||
final List<TableGroup> roots = sqlAst.getQuerySpec().getFromClause().getRoots();
|
||||
if ( roots.isEmpty() ) {
|
||||
// we allow this now
|
||||
return NO_OP_REG_HANDLER;
|
||||
}
|
||||
|
||||
return createRegistrationHandler( batchFetchQueue, sqlAst, roots.get( 0 ), jdbcParameters, jdbcParameterBindings );
|
||||
}
|
||||
|
||||
public interface RegistrationHandler {
|
||||
void addKey(EntityKey key);
|
||||
}
|
||||
|
||||
private static final RegistrationHandler NO_OP_REG_HANDLER = new RegistrationHandler() {
|
||||
@Override
|
||||
public void addKey(EntityKey key) {
|
||||
}
|
||||
} ;
|
||||
|
||||
public static class StandardRegistrationHandler implements RegistrationHandler {
|
||||
private final BatchFetchQueue batchFetchQueue;
|
||||
private final SubselectFetch subselectFetch;
|
||||
|
||||
private StandardRegistrationHandler(BatchFetchQueue batchFetchQueue, SubselectFetch subselectFetch) {
|
||||
this.batchFetchQueue = batchFetchQueue;
|
||||
this.subselectFetch = subselectFetch;
|
||||
}
|
||||
|
||||
public void addKey(EntityKey key) {
|
||||
subselectFetch.resultingEntityKeys.add( key );
|
||||
batchFetchQueue.addSubselect( key, subselectFetch );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.loader.ast.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
|
@ -14,13 +15,14 @@ import org.hibernate.collection.spi.PersistentCollection;
|
|||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.ast.spi.CollectionLoader;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
|
@ -32,6 +34,7 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
|
@ -167,7 +170,8 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
|
|||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory
|
||||
.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
.translate( null, QueryOptions.NONE );
|
||||
|
||||
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( keyJdbcCount * smallBatchLength );
|
||||
|
@ -185,6 +189,14 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
|
|||
session
|
||||
);
|
||||
}
|
||||
assert offset == jdbcParameters.size();
|
||||
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlAst,
|
||||
Collections.emptyList(),
|
||||
jdbcParameterBindings
|
||||
);
|
||||
|
||||
jdbcServices.getJdbcSelectExecutor().list(
|
||||
jdbcSelect,
|
||||
|
@ -205,6 +217,11 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
|
|||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryParameterBindings getQueryParameterBindings() {
|
||||
return QueryParameterBindings.NO_PARAM_BINDINGS;
|
||||
|
@ -220,9 +237,6 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
|
|||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
|
||||
assert offset == jdbcParameters.size();
|
||||
|
||||
// prepare for the next round...
|
||||
smallBatchStart += smallBatchLength;
|
||||
if ( smallBatchStart >= numberOfIds ) {
|
||||
|
@ -232,4 +246,5 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
|
|||
smallBatchLength = Math.min( numberOfIds - smallBatchStart, batchSize );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ import org.hibernate.collection.spi.PersistentCollection;
|
|||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.loader.ast.spi.CollectionLoader;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
|
@ -30,6 +32,7 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
|
@ -103,9 +106,18 @@ public class CollectionLoaderSingleKey implements CollectionLoader {
|
|||
session
|
||||
);
|
||||
assert offset == jdbcParameters.size();
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory
|
||||
.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
.translate( jdbcParameterBindings, QueryOptions.NONE );
|
||||
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlAst,
|
||||
jdbcParameters,
|
||||
jdbcParameterBindings
|
||||
);
|
||||
|
||||
jdbcServices.getJdbcSelectExecutor().list(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
|
@ -120,6 +132,11 @@ public class CollectionLoaderSingleKey implements CollectionLoader {
|
|||
return collectionKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return QueryOptions.NONE;
|
||||
|
|
|
@ -6,14 +6,23 @@
|
|||
*/
|
||||
package org.hibernate.loader.ast.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.BatchFetchQueue;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.loader.ast.spi.CollectionLoader;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
|
@ -24,6 +33,7 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
|
@ -63,18 +73,63 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection load(Object triggerKey, SharedSessionContractImplementor session) {
|
||||
public PersistentCollection<?> load(Object triggerKey, SharedSessionContractImplementor session) {
|
||||
final CollectionKey collectionKey = new CollectionKey( attributeMapping.getCollectionDescriptor(), triggerKey );
|
||||
|
||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
.translate( subselect.getLoadingJdbcParameterBindings(), QueryOptions.NONE );
|
||||
// try to find a registered SubselectFetch
|
||||
final PersistentCollection<?> collection = persistenceContext.getCollection( collectionKey );
|
||||
attributeMapping.getCollectionDescriptor().getCollectionType().getKeyOfOwner( collection.getOwner(), session );
|
||||
|
||||
final EntityEntry ownerEntry = persistenceContext.getEntry( collection.getOwner() );
|
||||
final BatchFetchQueue batchFetchQueue = persistenceContext.getBatchFetchQueue();
|
||||
final EntityKey triggerKeyOwnerKey = ownerEntry.getEntityKey();
|
||||
final SubselectFetch registeredFetch = batchFetchQueue.getSubselect( triggerKeyOwnerKey );
|
||||
List<PersistentCollection<?>> subSelectFetchedCollections = null;
|
||||
if ( registeredFetch != null ) {
|
||||
batchFetchQueue.removeSubselect( triggerKeyOwnerKey );
|
||||
subSelectFetchedCollections = CollectionHelper.arrayList( registeredFetch.getResultingEntityKeys().size() );
|
||||
|
||||
// there was one, so we want to make sure to prepare the corresponding collection
|
||||
// reference for reading
|
||||
final Iterator<EntityKey> itr = registeredFetch.getResultingEntityKeys().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final EntityKey key = itr.next();
|
||||
batchFetchQueue.removeSubselect( key );
|
||||
itr.remove();
|
||||
|
||||
final PersistentCollection<?> containedCollection = persistenceContext.getCollection(
|
||||
new CollectionKey( attributeMapping.getCollectionDescriptor(), key.getIdentifier() )
|
||||
);
|
||||
|
||||
if ( containedCollection != collection ) {
|
||||
containedCollection.beginRead();
|
||||
containedCollection.beforeInitialize( getLoadable().getCollectionDescriptor(), -1 );
|
||||
|
||||
subSelectFetchedCollections.add( containedCollection );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory
|
||||
.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
.translate( this.subselect.getLoadingJdbcParameterBindings(), QueryOptions.NONE );
|
||||
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
batchFetchQueue,
|
||||
sqlAst,
|
||||
this.subselect.getLoadingJdbcParameters(),
|
||||
this.subselect.getLoadingJdbcParameterBindings()
|
||||
);
|
||||
|
||||
jdbcServices.getJdbcSelectExecutor().list(
|
||||
jdbcSelect,
|
||||
subselect.getLoadingJdbcParameterBindings(),
|
||||
this.subselect.getLoadingJdbcParameterBindings(),
|
||||
new ExecutionContext() {
|
||||
@Override
|
||||
public SharedSessionContractImplementor getSession() {
|
||||
|
@ -91,6 +146,11 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
|
|||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryParameterBindings getQueryParameterBindings() {
|
||||
return QueryParameterBindings.NO_PARAM_BINDINGS;
|
||||
|
@ -106,7 +166,18 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
|
|||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
final CollectionKey collectionKey = new CollectionKey( attributeMapping.getCollectionDescriptor(), triggerKey );
|
||||
return session.getPersistenceContext().getCollection( collectionKey );
|
||||
if ( subSelectFetchedCollections != null && ! subSelectFetchedCollections.isEmpty() ) {
|
||||
subSelectFetchedCollections.forEach( (c) -> {
|
||||
if ( c.wasInitialized() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
c.initializeEmptyCollection( getLoadable().getCollectionDescriptor() );
|
||||
} );
|
||||
|
||||
subSelectFetchedCollections.clear();
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@ import org.hibernate.LockOptions;
|
|||
import org.hibernate.collection.spi.BagSemantics;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.engine.profile.FetchProfile;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.CascadingAction;
|
||||
import org.hibernate.engine.spi.EffectiveEntityGraph;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.graph.GraphSemantic;
|
||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||
import org.hibernate.internal.FilterHelper;
|
||||
|
@ -896,8 +896,23 @@ public class LoaderSelectBuilder {
|
|||
}
|
||||
|
||||
private SelectStatement generateSelect(SubselectFetch subselect) {
|
||||
// todo (6.0) : i think we may even be able to convert this to a join by piecing together
|
||||
// parts from the subselect-fetch sql-ast..
|
||||
|
||||
// todo (6.0) : we could even convert this to a join by piecing together
|
||||
// parts from the subselect-fetch sql-ast. e.g. today we do:
|
||||
// select ...
|
||||
// from collection_table c
|
||||
// where c.fk in (
|
||||
// select o.id
|
||||
// from owner_table o
|
||||
// where <original restriction>
|
||||
// )
|
||||
// but instead could do:
|
||||
// select ...
|
||||
// from owner_table o
|
||||
// left join collection_table c on c.fk = o.id
|
||||
// where <original restriction>
|
||||
|
||||
// just like with other load-paths, bag-mappings can potentially be problematic here
|
||||
|
||||
// todo (6.0) : ^^ another interesting idea is to use `partsToSelect` here relative to the owner
|
||||
// - so `loadable` is the owner entity-descriptor and the `partsToSelect` is the collection
|
||||
|
@ -920,9 +935,6 @@ public class LoaderSelectBuilder {
|
|||
creationContext
|
||||
);
|
||||
|
||||
// todo (6.0) : I think we want to continue to assign aliases to these table-references. we just want
|
||||
// to control how that gets rendered in the walker
|
||||
|
||||
final TableGroup rootTableGroup = loadable.createRootTableGroup(
|
||||
true,
|
||||
rootNavigablePath,
|
||||
|
@ -949,7 +961,9 @@ public class LoaderSelectBuilder {
|
|||
applyOrdering( rootTableGroup, attributeMapping );
|
||||
|
||||
// register the jdbc-parameters
|
||||
subselect.getLoadingJdbcParameters().forEach( jdbcParameterConsumer );
|
||||
// todo (6.0) : analyzing the call paths, it seems like `jdbcParameterConsumer`
|
||||
// never does anything for sub-select-fetch select building.
|
||||
//subselect.getLoadingJdbcParameters().forEach( jdbcParameterConsumer );
|
||||
|
||||
return new SelectStatement(
|
||||
rootQuerySpec,
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.engine.spi.PersistenceContext;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.LoadEvent;
|
||||
import org.hibernate.event.spi.LoadEventListener;
|
||||
|
@ -297,7 +298,14 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
|
|||
loadingEntityCollector = null;
|
||||
}
|
||||
|
||||
return JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlAst,
|
||||
jdbcParameters,
|
||||
jdbcParameterBindings
|
||||
);
|
||||
|
||||
List<T> list = JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
new ExecutionContext() {
|
||||
|
@ -328,14 +336,14 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
|
|||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
if ( loadingEntityCollector != null ) {
|
||||
loadingEntityCollector.collectLoadingEntityKey( entityKey );
|
||||
}
|
||||
subSelectFetchableKeysHandler.addKey( entityKey );
|
||||
}
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<T> performUnorderedMultiLoad(
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.engine.spi.EntityKey;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -145,6 +146,7 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
|
||||
private <E> List<E> performLoad(JdbcParameterBindings jdbcParamBindings, SharedSessionContractImplementor session) {
|
||||
final LoadingEntityCollector loadingEntityCollector;
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
|
||||
|
||||
if ( entityDescriptor.getEntityPersister().hasSubselectLoadableCollections() ) {
|
||||
loadingEntityCollector = new LoadingEntityCollector(
|
||||
|
@ -154,12 +156,23 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
jdbcParamBindings,
|
||||
session.getPersistenceContext().getBatchFetchQueue()
|
||||
);
|
||||
|
||||
subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlSelect,
|
||||
jdbcParameters,
|
||||
jdbcParamBindings
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
loadingEntityCollector = null;
|
||||
subSelectFetchableKeysHandler = null;
|
||||
}
|
||||
|
||||
return JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
||||
|
||||
final List<E> result = JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
||||
jdbcSelect,
|
||||
jdbcParamBindings,
|
||||
new ExecutionContext() {
|
||||
|
@ -190,13 +203,15 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
if ( loadingEntityCollector != null ) {
|
||||
loadingEntityCollector.collectLoadingEntityKey( entityKey );
|
||||
if ( subSelectFetchableKeysHandler != null ) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey );
|
||||
}
|
||||
}
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
|
@ -31,6 +32,7 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
|
@ -117,9 +119,18 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
|||
);
|
||||
}
|
||||
assert offset == jdbcParameters.size();
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
|
||||
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory
|
||||
.buildSelectTranslator( sessionFactory, sqlAst )
|
||||
.translate( jdbcParameterBindings, QueryOptions.NONE );
|
||||
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqlAst,
|
||||
jdbcParameters,
|
||||
jdbcParameterBindings
|
||||
);
|
||||
|
||||
JdbcSelectExecutorStandardImpl.INSTANCE.list(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
|
@ -144,6 +155,11 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
|||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryParameterBindings getQueryParameterBindings() {
|
||||
return QueryParameterBindings.NO_PARAM_BINDINGS;
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.hibernate.cache.spi.entry.UnstructuredCacheEntry;
|
|||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
|
@ -49,7 +50,6 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
|||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.exception.spi.SQLExceptionConverter;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.query.internal;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DelegatingDomainQueryExecutionContext implements DomainQueryExecutionContext {
|
||||
private final DomainQueryExecutionContext delegate;
|
||||
|
||||
public <R> DelegatingDomainQueryExecutionContext(DomainQueryExecutionContext delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return delegate.getQueryOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryParameterBindings getQueryParameterBindings() {
|
||||
return delegate.getQueryParameterBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback getCallback() {
|
||||
return delegate.getCallback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionContractImplementor getSession() {
|
||||
return delegate.getSession();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.query.spi;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
|
||||
/**
|
||||
* Context for execution of {@link org.hibernate.query.Query}"
|
||||
*/
|
||||
public interface DomainQueryExecutionContext {
|
||||
QueryOptions getQueryOptions();
|
||||
|
||||
QueryParameterBindings getQueryParameterBindings();
|
||||
|
||||
/**
|
||||
* The callback reference
|
||||
* @return
|
||||
*/
|
||||
Callback getCallback();
|
||||
|
||||
SharedSessionContractImplementor getSession();
|
||||
}
|
|
@ -6,11 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.query.spi;
|
||||
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface NonSelectQueryPlan extends QueryPlan {
|
||||
int executeUpdate(ExecutionContext executionContext);
|
||||
int executeUpdate(DomainQueryExecutionContext executionContext);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.List;
|
|||
import org.hibernate.Incubating;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
* General contract for performing execution of a query returning results. These
|
||||
|
@ -36,11 +35,11 @@ public interface SelectQueryPlan<R> extends QueryPlan {
|
|||
/**
|
||||
* Perform (execute) the query returning a List
|
||||
*/
|
||||
List<R> performList(ExecutionContext executionContext);
|
||||
List<R> performList(DomainQueryExecutionContext executionContext);
|
||||
|
||||
/**
|
||||
* Perform (execute) the query returning a ScrollableResults
|
||||
*/
|
||||
ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, ExecutionContext executionContext);
|
||||
ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext);
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@ package org.hibernate.query.spi;
|
|||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.query.Limit;
|
||||
import org.hibernate.sql.exec.internal.DelegatingExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
|
||||
/**
|
||||
|
@ -26,35 +24,31 @@ public class SqlOmittingQueryOptions extends DelegatingQueryOptions {
|
|||
this.omitLocks = omitLocks;
|
||||
}
|
||||
|
||||
public static ExecutionContext omitSqlQueryOptions(ExecutionContext context) {
|
||||
return omitSqlQueryOptions( context, true, true );
|
||||
public static QueryOptions omitSqlQueryOptions(QueryOptions originalOptions) {
|
||||
return omitSqlQueryOptions( originalOptions, true, true );
|
||||
}
|
||||
|
||||
public static ExecutionContext omitSqlQueryOptions(ExecutionContext context, JdbcSelect select) {
|
||||
return omitSqlQueryOptions( context, !select.usesLimitParameters(), false );
|
||||
public static QueryOptions omitSqlQueryOptions(QueryOptions originalOptions, JdbcSelect select) {
|
||||
return omitSqlQueryOptions( originalOptions, !select.usesLimitParameters(), false );
|
||||
}
|
||||
|
||||
public static ExecutionContext omitSqlQueryOptions(ExecutionContext context, boolean omitLimit, boolean omitLocks) {
|
||||
final QueryOptions originalQueryOptions = context.getQueryOptions();
|
||||
final Limit limit = originalQueryOptions.getLimit();
|
||||
public static QueryOptions omitSqlQueryOptions(QueryOptions originalOptions, boolean omitLimit, boolean omitLocks) {
|
||||
final Limit limit = originalOptions.getLimit();
|
||||
|
||||
// No need for a context when there are no options we use during SQL rendering
|
||||
if ( originalQueryOptions.getLockOptions().isEmpty() ) {
|
||||
if ( originalOptions.getLockOptions().isEmpty() ) {
|
||||
if ( !omitLimit || limit == null || limit.isEmpty() ) {
|
||||
return context;
|
||||
return originalOptions;
|
||||
}
|
||||
}
|
||||
else if ( !omitLocks ) {
|
||||
|
||||
if ( !omitLocks ) {
|
||||
if ( !omitLimit || limit == null || limit.isEmpty() ) {
|
||||
return context;
|
||||
return originalOptions;
|
||||
}
|
||||
}
|
||||
final QueryOptions queryOptions = new SqlOmittingQueryOptions( originalQueryOptions, omitLimit, omitLocks );
|
||||
return new DelegatingExecutionContext( context ) {
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return queryOptions;
|
||||
}
|
||||
};
|
||||
|
||||
return new SqlOmittingQueryOptions( originalOptions, omitLimit, omitLocks );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,15 +16,16 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcMutation;
|
||||
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
|
@ -50,9 +51,9 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
executionContext.getSession().autoFlushIfRequired( affectedTableNames );
|
||||
BulkOperationCleanupAction.schedule( executionContext, affectedTableNames );
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), affectedTableNames );
|
||||
final List<JdbcParameterBinder> jdbcParameterBinders;
|
||||
final JdbcParameterBindings jdbcParameterBindings;
|
||||
|
||||
|
@ -108,7 +109,7 @@ public class NativeNonSelectQueryPlanImpl implements NonSelectQueryPlan {
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
executionContext
|
||||
new SqmJdbcExecutionContextAdapter( executionContext )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,16 +21,6 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import jakarta.persistence.FlushModeType;
|
||||
import jakarta.persistence.LockModeType;
|
||||
import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import jakarta.persistence.Tuple;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
|
@ -53,7 +43,6 @@ import org.hibernate.jpa.internal.util.LockModeTypeHelper;
|
|||
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.query.Limit;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
import org.hibernate.query.ParameterMetadata;
|
||||
|
@ -74,6 +63,7 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
|||
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
|
||||
import org.hibernate.query.results.dynamic.DynamicResultBuilderInstantiation;
|
||||
import org.hibernate.query.spi.AbstractQuery;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.MutableQueryOptions;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
||||
|
@ -92,12 +82,22 @@ import org.hibernate.query.sql.spi.ParameterInterpretation;
|
|||
import org.hibernate.query.sql.spi.SelectInterpretationsKey;
|
||||
import org.hibernate.sql.exec.internal.CallbackImpl;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
|
||||
import org.hibernate.transform.ResultTransformer;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.BasicTypeReference;
|
||||
|
||||
import jakarta.persistence.AttributeConverter;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import jakarta.persistence.FlushModeType;
|
||||
import jakarta.persistence.LockModeType;
|
||||
import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import jakarta.persistence.Tuple;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import static org.hibernate.jpa.QueryHints.HINT_NATIVE_LOCKMODE;
|
||||
|
||||
/**
|
||||
|
@ -106,7 +106,7 @@ import static org.hibernate.jpa.QueryHints.HINT_NATIVE_LOCKMODE;
|
|||
@SuppressWarnings("WeakerAccess")
|
||||
public class NativeQueryImpl<R>
|
||||
extends AbstractQuery<R>
|
||||
implements NativeQueryImplementor<R>, ExecutionContext, ResultSetMappingResolutionContext {
|
||||
implements NativeQueryImplementor<R>, DomainQueryExecutionContext, ResultSetMappingResolutionContext {
|
||||
private final String sqlString;
|
||||
|
||||
private final ParameterMetadataImplementor parameterMetadata;
|
||||
|
@ -440,13 +440,6 @@ public class NativeQueryImpl<R>
|
|||
return callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) {
|
||||
if ( callback != null ) {
|
||||
callback.invokeAfterLoadActions( session, entity, persister );
|
||||
}
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return getSession().getFactory();
|
||||
}
|
||||
|
@ -504,11 +497,6 @@ public class NativeQueryImpl<R>
|
|||
throw new IllegalStateException( "Illegal attempt to set lock mode on a native-query" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryIdentifier(String sql) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<R> applyGraph(RootGraph graph, GraphSemantic semantic) {
|
||||
throw new HibernateException( "A native SQL query cannot use EntityGraphs" );
|
||||
|
|
|
@ -19,16 +19,17 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
|||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
|
@ -68,7 +69,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<R> performList(ExecutionContext executionContext) {
|
||||
public List<R> performList(DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -126,14 +127,14 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
return executor.list(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
executionContext,
|
||||
new SqmJdbcExecutionContextAdapter( executionContext, executionContext.getQueryOptions() ),
|
||||
null,
|
||||
ListResultsConsumer.UniqueSemantic.NONE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, ExecutionContext executionContext) {
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
return EmptyScrollableResults.INSTANCE;
|
||||
}
|
||||
|
@ -191,7 +192,7 @@ public class NativeSelectQueryPlanImpl<R> implements NativeSelectQueryPlan<R> {
|
|||
jdbcSelect,
|
||||
scrollMode,
|
||||
jdbcParameterBindings,
|
||||
executionContext,
|
||||
new SqmJdbcExecutionContextAdapter( executionContext, jdbcSelect ),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.internal.EmptyScrollableResults;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
|
@ -28,7 +29,7 @@ public class AggregatedSelectQueryPlanImpl<R> implements SelectQueryPlan<R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<R> performList(ExecutionContext executionContext) {
|
||||
public List<R> performList(DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -42,7 +43,7 @@ public class AggregatedSelectQueryPlanImpl<R> implements SelectQueryPlan<R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, ExecutionContext executionContext) {
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
return EmptyScrollableResults.INSTANCE;
|
||||
}
|
||||
|
|
|
@ -11,20 +11,20 @@ import java.util.Collections;
|
|||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jakarta.persistence.Tuple;
|
||||
import jakarta.persistence.TupleElement;
|
||||
import jakarta.persistence.criteria.CompoundSelection;
|
||||
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.internal.EmptyScrollableResults;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.criteria.JpaSelection;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
|
@ -42,9 +42,10 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerJpaTupleImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerSingularReturnImpl;
|
||||
|
@ -53,6 +54,12 @@ import org.hibernate.sql.results.internal.TupleMetadata;
|
|||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
import org.hibernate.sql.results.spi.RowTransformer;
|
||||
|
||||
import jakarta.persistence.Tuple;
|
||||
import jakarta.persistence.TupleElement;
|
||||
import jakarta.persistence.criteria.CompoundSelection;
|
||||
|
||||
import static org.hibernate.query.sqm.internal.QuerySqmImpl.CRITERIA_HQL_STRING;
|
||||
|
||||
/**
|
||||
* Standard Hibernate implementation of SelectQueryPlan for SQM-backed
|
||||
* {@link org.hibernate.query.Query} implementations, which means
|
||||
|
@ -62,6 +69,7 @@ import org.hibernate.sql.results.spi.RowTransformer;
|
|||
*/
|
||||
public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||
private final SqmSelectStatement sqm;
|
||||
private final String hql;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
private final RowTransformer<R> rowTransformer;
|
||||
private final SqmInterpreter<List<R>, Void> listInterpreter;
|
||||
|
@ -72,22 +80,51 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
@SuppressWarnings("WeakerAccess")
|
||||
public ConcreteSqmSelectQueryPlan(
|
||||
SqmSelectStatement sqm,
|
||||
String hql,
|
||||
DomainParameterXref domainParameterXref,
|
||||
Class<R> resultType,
|
||||
QueryOptions queryOptions) {
|
||||
this.sqm = sqm;
|
||||
this.hql = hql;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
|
||||
this.rowTransformer = determineRowTransformer( sqm, resultType, queryOptions );
|
||||
|
||||
this.listInterpreter = (unused, executionContext, sqmInterpretation, jdbcParameterBindings) -> {
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
final JdbcSelect jdbcSelect = sqmInterpretation.getJdbcSelect();
|
||||
try {
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchKeyHandler = SubselectFetch.createRegistrationHandler(
|
||||
session.getPersistenceContext().getBatchFetchQueue(),
|
||||
sqmInterpretation.selectStatement,
|
||||
Collections.emptyList(),
|
||||
jdbcParameterBindings
|
||||
);
|
||||
|
||||
session.autoFlushIfRequired( jdbcSelect.getAffectedTableNames() );
|
||||
|
||||
return session.getFactory().getJdbcServices().getJdbcSelectExecutor().list(
|
||||
jdbcSelect,
|
||||
jdbcParameterBindings,
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext, jdbcSelect ),
|
||||
new SqmJdbcExecutionContextAdapter( executionContext, jdbcSelect ) {
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchKeyHandler.addKey( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryIdentifier(String sql) {
|
||||
if ( CRITERIA_HQL_STRING.equals( hql ) ) {
|
||||
return "[CRITERIA] " + sql;
|
||||
}
|
||||
return hql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasQueryExecutionToBeAddedToStatistics() {
|
||||
return !CRITERIA_HQL_STRING.equals( hql );
|
||||
}
|
||||
},
|
||||
rowTransformer,
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
@ -96,15 +133,41 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
domainParameterXref.clearExpansions();
|
||||
}
|
||||
};
|
||||
|
||||
this.scrollInterpreter = (scrollMode, executionContext, sqmInterpretation, jdbcParameterBindings) -> {
|
||||
try {
|
||||
return executionContext.getSession().getFactory().getJdbcServices().getJdbcSelectExecutor().scroll(
|
||||
final SubselectFetch.RegistrationHandler subSelectFetchKeyHandler = SubselectFetch.createRegistrationHandler(
|
||||
executionContext.getSession().getPersistenceContext().getBatchFetchQueue(),
|
||||
sqmInterpretation.selectStatement,
|
||||
Collections.emptyList(),
|
||||
jdbcParameterBindings
|
||||
);
|
||||
|
||||
final JdbcSelectExecutor jdbcSelectExecutor = executionContext.getSession()
|
||||
.getFactory()
|
||||
.getJdbcServices()
|
||||
.getJdbcSelectExecutor();
|
||||
final ScrollableResultsImplementor<R> result = jdbcSelectExecutor.scroll(
|
||||
sqmInterpretation.getJdbcSelect(),
|
||||
scrollMode,
|
||||
jdbcParameterBindings,
|
||||
executionContext,
|
||||
new SqmJdbcExecutionContextAdapter( executionContext ) {
|
||||
final QueryOptions options = SqlOmittingQueryOptions.omitSqlQueryOptions( queryOptions, sqmInterpretation.jdbcSelect );
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchKeyHandler.addKey( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return options;
|
||||
}
|
||||
},
|
||||
rowTransformer
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
domainParameterXref.clearExpansions();
|
||||
|
@ -202,7 +265,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<R> performList(ExecutionContext executionContext) {
|
||||
public List<R> performList(DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -210,14 +273,14 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, ExecutionContext executionContext) {
|
||||
public ScrollableResultsImplementor<R> performScroll(ScrollMode scrollMode, DomainQueryExecutionContext executionContext) {
|
||||
if ( executionContext.getQueryOptions().getEffectiveLimit().getMaxRowsJpa() == 0 ) {
|
||||
return EmptyScrollableResults.INSTANCE;
|
||||
}
|
||||
return withCacheableSqmInterpretation( executionContext, scrollMode, scrollInterpreter );
|
||||
}
|
||||
|
||||
private <T, X> T withCacheableSqmInterpretation(ExecutionContext executionContext, X context, SqmInterpreter<T, X> interpreter) {
|
||||
private <T, X> T withCacheableSqmInterpretation(DomainQueryExecutionContext executionContext, X context, SqmInterpreter<T, X> interpreter) {
|
||||
// NOTE : VERY IMPORTANT - intentional double-lock checking
|
||||
// The other option would be to leverage `java.util.concurrent.locks.ReadWriteLock`
|
||||
// to protect access. However, synchronized is much simpler here. We will verify
|
||||
|
@ -260,13 +323,15 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
cacheableSqmInterpretation = localCopy;
|
||||
}
|
||||
}
|
||||
|
||||
if ( jdbcParameterBindings == null ) {
|
||||
jdbcParameterBindings = createJdbcParameterBindings( localCopy, executionContext );
|
||||
}
|
||||
|
||||
return interpreter.interpret( context, executionContext, localCopy, jdbcParameterBindings );
|
||||
}
|
||||
|
||||
private JdbcParameterBindings createJdbcParameterBindings(CacheableSqmInterpretation sqmInterpretation, ExecutionContext executionContext) {
|
||||
private JdbcParameterBindings createJdbcParameterBindings(CacheableSqmInterpretation sqmInterpretation, DomainQueryExecutionContext executionContext) {
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(
|
||||
executionContext.getQueryParameterBindings(),
|
||||
|
@ -284,7 +349,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
private static CacheableSqmInterpretation buildCacheableSqmInterpretation(
|
||||
SqmSelectStatement sqm,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext executionContext) {
|
||||
DomainQueryExecutionContext executionContext) {
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||
final QueryEngine queryEngine = sessionFactory.getQueryEngine();
|
||||
|
@ -296,7 +361,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
executionContext.getQueryOptions(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryParameterBindings(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
sessionFactory
|
||||
);
|
||||
|
||||
|
@ -328,6 +393,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
final JdbcSelect jdbcSelect = selectTranslator.translate( jdbcParameterBindings, executionContext.getQueryOptions() );
|
||||
|
||||
return new CacheableSqmInterpretation(
|
||||
sqmInterpretation.getSqlAst(),
|
||||
jdbcSelect,
|
||||
tableGroupAccess,
|
||||
jdbcParamsXref,
|
||||
|
@ -339,12 +405,13 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
private interface SqmInterpreter<T, X> {
|
||||
T interpret(
|
||||
X context,
|
||||
ExecutionContext executionContext,
|
||||
DomainQueryExecutionContext executionContext,
|
||||
CacheableSqmInterpretation sqmInterpretation,
|
||||
JdbcParameterBindings jdbcParameterBindings);
|
||||
}
|
||||
|
||||
private static class CacheableSqmInterpretation {
|
||||
private final SelectStatement selectStatement;
|
||||
private final JdbcSelect jdbcSelect;
|
||||
private final FromClauseAccess tableGroupAccess;
|
||||
private final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref;
|
||||
|
@ -352,11 +419,13 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
private transient JdbcParameterBindings firstParameterBindings;
|
||||
|
||||
CacheableSqmInterpretation(
|
||||
SelectStatement selectStatement,
|
||||
JdbcSelect jdbcSelect,
|
||||
FromClauseAccess tableGroupAccess,
|
||||
Map<QueryParameterImplementor<?>, Map<SqmParameter, List<List<JdbcParameter>>>> jdbcParamsXref,
|
||||
Map<SqmParameter,MappingModelExpressable> sqmParameterMappingModelTypes,
|
||||
JdbcParameterBindings firstParameterBindings) {
|
||||
this.selectStatement = selectStatement;
|
||||
this.jdbcSelect = jdbcSelect;
|
||||
this.tableGroupAccess = tableGroupAccess;
|
||||
this.jdbcParamsXref = jdbcParamsXref;
|
||||
|
@ -364,6 +433,10 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
this.firstParameterBindings = firstParameterBindings;
|
||||
}
|
||||
|
||||
SelectStatement getSelectStatement() {
|
||||
return selectStatement;
|
||||
}
|
||||
|
||||
JdbcSelect getJdbcSelect() {
|
||||
return jdbcSelect;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
|
@ -30,8 +31,8 @@ public class MultiTableDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext, sqmDelete );
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmDelete );
|
||||
return deleteStrategy.executeDelete( sqmDelete, domainParameterXref, executionContext );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
@ -30,8 +31,8 @@ public class MultiTableUpdateQueryPlan implements NonSelectQueryPlan {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext, sqmUpdate );
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmUpdate );
|
||||
return mutationStrategy.executeUpdate( sqmUpdate, domainParameterXref, executionContext );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import jakarta.persistence.LockModeType;
|
||||
import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.Tuple;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
|
@ -36,7 +32,6 @@ import org.hibernate.internal.util.collections.IdentitySet;
|
|||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.query.QueryTypeMismatchException;
|
||||
|
@ -44,10 +39,12 @@ import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
|
|||
import org.hibernate.query.hql.internal.QuerySplitter;
|
||||
import org.hibernate.query.hql.spi.HqlQueryImplementor;
|
||||
import org.hibernate.query.hql.spi.NamedHqlQueryMemento;
|
||||
import org.hibernate.query.internal.DelegatingDomainQueryExecutionContext;
|
||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||
import org.hibernate.query.internal.QueryOptionsImpl;
|
||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||
import org.hibernate.query.spi.AbstractQuery;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.HqlInterpretation;
|
||||
import org.hibernate.query.spi.MutableQueryOptions;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
|
@ -59,7 +56,6 @@ import org.hibernate.query.spi.QueryParameterBindings;
|
|||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
|
@ -79,10 +75,16 @@ import org.hibernate.query.sqm.tree.select.SqmSelection;
|
|||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.exec.internal.CallbackImpl;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
import jakarta.persistence.LockModeType;
|
||||
import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.Tuple;
|
||||
|
||||
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
|
||||
|
||||
/**
|
||||
* {@link Query} implementation based on an SQM
|
||||
*
|
||||
|
@ -90,7 +92,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|||
*/
|
||||
public class QuerySqmImpl<R>
|
||||
extends AbstractQuery<R>
|
||||
implements HqlQueryImplementor<R>, ExecutionContext {
|
||||
implements HqlQueryImplementor<R>, DomainQueryExecutionContext {
|
||||
|
||||
/**
|
||||
* The value used for {@link #getQueryString} for Criteria-based queries
|
||||
|
@ -604,7 +606,8 @@ public class QuerySqmImpl<R>
|
|||
queryOptions.getGraph() != null ||
|
||||
hasLimit
|
||||
);
|
||||
final ExecutionContext executionContextToUse;
|
||||
|
||||
final DomainQueryExecutionContext executionContextToUse;
|
||||
if ( hasLimit && containsCollectionFetches ) {
|
||||
boolean fail = getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled();
|
||||
if (fail) {
|
||||
|
@ -617,7 +620,15 @@ public class QuerySqmImpl<R>
|
|||
else {
|
||||
LOG.firstOrMaxResultsSpecifiedWithCollectionFetch();
|
||||
}
|
||||
executionContextToUse = SqlOmittingQueryOptions.omitSqlQueryOptions( this, true, false );
|
||||
|
||||
final MutableQueryOptions originalQueryOptions = getQueryOptions();
|
||||
final QueryOptions normalizedQueryOptions = omitSqlQueryOptions( originalQueryOptions, true, false );
|
||||
if ( originalQueryOptions == normalizedQueryOptions ) {
|
||||
executionContextToUse = this;
|
||||
}
|
||||
else {
|
||||
executionContextToUse = new DelegatingDomainQueryExecutionContext( this );
|
||||
}
|
||||
}
|
||||
else {
|
||||
executionContextToUse = this;
|
||||
|
@ -720,6 +731,7 @@ public class QuerySqmImpl<R>
|
|||
QueryOptions queryOptions) {
|
||||
return new ConcreteSqmSelectQueryPlan<>(
|
||||
concreteSqmStatement,
|
||||
hqlString,
|
||||
domainParameterXref,
|
||||
resultType,
|
||||
queryOptions
|
||||
|
@ -841,21 +853,6 @@ public class QuerySqmImpl<R>
|
|||
return callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) {
|
||||
if ( callback != null ) {
|
||||
callback.invokeAfterLoadActions( session, entity, persister );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryIdentifier(String sql) {
|
||||
if ( CRITERIA_HQL_STRING.equals( hqlString ) ) {
|
||||
return "[CRITERIA] " + sql;
|
||||
}
|
||||
return hqlString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedHqlQueryMemento toMemento(String name) {
|
||||
return new NamedHqlQueryMementoImpl(
|
||||
|
@ -877,9 +874,4 @@ public class QuerySqmImpl<R>
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasQueryExecutionToBeAddedToStatistics() {
|
||||
return !CRITERIA_HQL_STRING.equals( hqlString );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.MappingModelHelper;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslation;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
|
@ -34,7 +34,6 @@ import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
|||
import org.hibernate.sql.ast.tree.from.MutatingTableReferenceGroupWrapper;
|
||||
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
|
@ -62,7 +61,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
this.domainParameterXref = domainParameterXref;
|
||||
}
|
||||
|
||||
private SqlAstTranslator<JdbcDelete> createDeleteTranslator(ExecutionContext executionContext) {
|
||||
private SqlAstTranslator<JdbcDelete> createDeleteTranslator(DomainQueryExecutionContext executionContext) {
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
|
||||
|
@ -72,7 +71,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
executionContext.getQueryOptions(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryParameterBindings(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
factory
|
||||
);
|
||||
|
||||
|
@ -88,8 +87,8 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext, sqmDelete );
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmDelete );
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
final JdbcServices jdbcServices = factory.getJdbcServices();
|
||||
|
@ -127,6 +126,8 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
assert jdbcParamsXref.isEmpty();
|
||||
}
|
||||
|
||||
final SqmJdbcExecutionContextAdapter executionContextAdapter = new SqmJdbcExecutionContextAdapter( executionContext );
|
||||
|
||||
SqmMutationStrategyHelper.cleanUpCollectionTables(
|
||||
entityDescriptor,
|
||||
(tableReference, attributeMapping) -> {
|
||||
|
@ -162,8 +163,8 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
|
||||
return new InSubQueryPredicate( fkColumnExpression, matchingIdSubQuery, false );
|
||||
},
|
||||
missingRestriction ? JdbcParameterBindings.NO_BINDINGS : jdbcParameterBindings,
|
||||
executionContext
|
||||
( missingRestriction ? JdbcParameterBindings.NO_BINDINGS : jdbcParameterBindings ),
|
||||
executionContextAdapter
|
||||
);
|
||||
|
||||
return jdbcServices.getJdbcMutationExecutor().execute(
|
||||
|
@ -174,7 +175,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
executionContextAdapter
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslation;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
|
@ -27,7 +27,6 @@ import org.hibernate.sql.ast.SqlAstTranslator;
|
|||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcInsert;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
||||
|
@ -50,7 +49,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan {
|
|||
this.domainParameterXref = domainParameterXref;
|
||||
}
|
||||
|
||||
private SqlAstTranslator<JdbcInsert> createInsertTranslator(ExecutionContext executionContext) {
|
||||
private SqlAstTranslator<JdbcInsert> createInsertTranslator(DomainQueryExecutionContext executionContext) {
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
|
||||
|
@ -60,7 +59,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan {
|
|||
executionContext.getQueryOptions(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryParameterBindings(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
factory
|
||||
);
|
||||
|
||||
|
@ -75,13 +74,15 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan {
|
|||
|
||||
this.paramTypeResolutions = sqmInterpretation.getSqmParameterMappingModelTypeResolutions();
|
||||
|
||||
return factory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory()
|
||||
return factory.getJdbcServices()
|
||||
.getJdbcEnvironment()
|
||||
.getSqlAstTranslatorFactory()
|
||||
.buildInsertTranslator( factory, sqmInterpretation.getSqlAst() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext, sqmInsert );
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmInsert );
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
final JdbcServices jdbcServices = factory.getJdbcServices();
|
||||
|
@ -122,7 +123,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan {
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
new SqmJdbcExecutionContextAdapter( executionContext )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslation;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
|
@ -27,7 +27,6 @@ import org.hibernate.sql.ast.SqlAstTranslator;
|
|||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.update.UpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcUpdate;
|
||||
|
||||
|
@ -51,8 +50,8 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(ExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext, sqmUpdate );
|
||||
public int executeUpdate(DomainQueryExecutionContext executionContext) {
|
||||
BulkOperationCleanupAction.schedule( executionContext.getSession(), sqmUpdate );
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
final JdbcServices jdbcServices = factory.getJdbcServices();
|
||||
|
@ -93,11 +92,11 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan {
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
new SqmJdbcExecutionContextAdapter( executionContext )
|
||||
);
|
||||
}
|
||||
|
||||
private SqlAstTranslator<JdbcUpdate> createUpdateTranslator(ExecutionContext executionContext) {
|
||||
private SqlAstTranslator<JdbcUpdate> createUpdateTranslator(DomainQueryExecutionContext executionContext) {
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
|
||||
|
@ -107,7 +106,7 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan {
|
|||
executionContext.getQueryOptions(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryParameterBindings(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
factory
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.query.sqm.internal;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
|
||||
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmJdbcExecutionContextAdapter implements ExecutionContext {
|
||||
private final DomainQueryExecutionContext sqmExecutionContext;
|
||||
private final QueryOptions queryOptions;
|
||||
|
||||
public SqmJdbcExecutionContextAdapter(DomainQueryExecutionContext sqmExecutionContext) {
|
||||
this( sqmExecutionContext, omitSqlQueryOptions( sqmExecutionContext.getQueryOptions() ) );
|
||||
}
|
||||
|
||||
public SqmJdbcExecutionContextAdapter(DomainQueryExecutionContext sqmExecutionContext, JdbcSelect jdbcSelect) {
|
||||
this( sqmExecutionContext, omitSqlQueryOptions( sqmExecutionContext.getQueryOptions(), jdbcSelect ) );
|
||||
}
|
||||
|
||||
public SqmJdbcExecutionContextAdapter(DomainQueryExecutionContext sqmExecutionContext, QueryOptions queryOptions) {
|
||||
this.sqmExecutionContext = sqmExecutionContext;
|
||||
this.queryOptions = queryOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedSessionContractImplementor getSession() {
|
||||
return sqmExecutionContext.getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return queryOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryParameterBindings getQueryParameterBindings() {
|
||||
return sqmExecutionContext.getQueryParameterBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Callback getCallback() {
|
||||
return sqmExecutionContext.getCallback();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.mutation.internal;
|
||||
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
|
@ -26,5 +27,5 @@ public interface Handler {
|
|||
*
|
||||
* @return The "number of rows affected" count
|
||||
*/
|
||||
int execute(ExecutionContext executionContext);
|
||||
int execute(DomainQueryExecutionContext executionContext);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,9 @@ import org.hibernate.internal.FilterHelper;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
|
@ -39,7 +40,6 @@ import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
|
|||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -73,7 +73,7 @@ public class MatchingIdSelectionHelper {
|
|||
boolean queryRoot,
|
||||
Predicate restriction,
|
||||
MultiTableSqmMutationConverter sqmConverter,
|
||||
ExecutionContext executionContext,
|
||||
DomainQueryExecutionContext executionContext,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final EntityDomainType entityDomainType = sqmStatement.getTarget().getModel();
|
||||
if ( log.isTraceEnabled() ) {
|
||||
|
@ -119,7 +119,7 @@ public class MatchingIdSelectionHelper {
|
|||
);
|
||||
|
||||
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
(Joinable) targetEntityDescriptor.getEntityPersister(),
|
||||
mutatingTableGroup
|
||||
);
|
||||
|
@ -195,7 +195,7 @@ public class MatchingIdSelectionHelper {
|
|||
public static List<Object> selectMatchingIds(
|
||||
SqmDeleteOrUpdateStatement sqmMutationStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext executionContext) {
|
||||
DomainQueryExecutionContext executionContext) {
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
|
||||
final EntityMappingType entityDescriptor = factory.getDomainModel()
|
||||
|
@ -206,7 +206,7 @@ public class MatchingIdSelectionHelper {
|
|||
sqmMutationStatement.getTarget().getExplicitAlias(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryOptions(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
executionContext.getQueryParameterBindings(),
|
||||
factory
|
||||
);
|
||||
|
@ -275,7 +275,7 @@ public class MatchingIdSelectionHelper {
|
|||
return jdbcServices.getJdbcSelectExecutor().list(
|
||||
idSelectJdbcOperation,
|
||||
jdbcParameterBindings,
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext, idSelectJdbcOperation ),
|
||||
new SqmJdbcExecutionContextAdapter( executionContext ),
|
||||
row -> row,
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
|
|
@ -122,7 +122,7 @@ public class SqmMutationStrategyHelper {
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.SqlExpressable;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.mutation.internal.MatchingIdSelectionHelper;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
|
@ -53,7 +53,6 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
|
|||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -102,7 +101,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
|||
}
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
public int execute(DomainQueryExecutionContext executionContext) {
|
||||
final SqmDeleteOrUpdateStatement sqmMutationStatement = getSqmDeleteOrUpdateStatement();
|
||||
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
|
||||
final EntityMappingType entityDescriptor = getEntityDescriptor();
|
||||
|
@ -121,7 +120,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
|||
explicitDmlTargetAlias,
|
||||
domainParameterXref,
|
||||
executionContext.getQueryOptions(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
executionContext.getQueryParameterBindings(),
|
||||
factory
|
||||
);
|
||||
|
@ -207,7 +206,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
|
|||
List<Object> list = jdbcServices.getJdbcSelectExecutor().list(
|
||||
select,
|
||||
jdbcParameterBindings,
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext, select ),
|
||||
new SqmJdbcExecutionContextAdapter( executionContext ),
|
||||
row -> row[0],
|
||||
ListResultsConsumer.UniqueSemantic.NONE
|
||||
);
|
||||
|
|
|
@ -14,14 +14,13 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteTable;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteTable;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
* @asciidoc
|
||||
|
@ -97,7 +96,7 @@ public class CteStrategy implements SqmMultiTableMutationStrategy {
|
|||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
checkMatch( sqmDelete );
|
||||
return new CteDeleteHandler( cteTable, sqmDelete, domainParameterXref, this, sessionFactory ).execute( context );
|
||||
}
|
||||
|
@ -106,7 +105,7 @@ public class CteStrategy implements SqmMultiTableMutationStrategy {
|
|||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
checkMatch( sqmUpdate );
|
||||
return new CteUpdateHandler( cteTable, sqmUpdate, domainParameterXref, this, sessionFactory ).execute( context );
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
@ -154,7 +153,7 @@ public final class ExecuteWithIdTableHelper {
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,17 +11,16 @@ import java.sql.SQLException;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -64,7 +63,7 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
|
@ -84,7 +83,7 @@ public class GlobalTemporaryTableStrategy implements SqmMultiTableMutationStrate
|
|||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
|
|
|
@ -17,11 +17,11 @@ import org.hibernate.engine.config.spi.StandardConverters;
|
|||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -76,7 +76,7 @@ public class LocalTemporaryTableStrategy implements SqmMultiTableMutationStrateg
|
|||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
|
@ -96,7 +96,7 @@ public class LocalTemporaryTableStrategy implements SqmMultiTableMutationStrateg
|
|||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
|
|
|
@ -14,11 +14,11 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
|
|||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedUpdateHandler(
|
||||
sqmUpdate,
|
||||
domainParameterXref,
|
||||
|
@ -86,7 +86,7 @@ public class PersistentTableStrategy implements SqmMultiTableMutationStrategy {
|
|||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
return new TableBasedDeleteHandler(
|
||||
sqmDelete,
|
||||
domainParameterXref,
|
||||
|
|
|
@ -31,10 +31,12 @@ import org.hibernate.metamodel.mapping.MappingModelHelper;
|
|||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper;
|
||||
|
@ -118,8 +120,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
}
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
|
||||
public int execute(DomainQueryExecutionContext executionContext) {
|
||||
final EntityPersister entityDescriptor = sessionFactory.getDomainModel().getEntityDescriptor( sqmDelete.getTarget().getEntityName() );
|
||||
final String hierarchyRootTableName = ( (Joinable) entityDescriptor ).getTableName();
|
||||
|
||||
|
@ -166,7 +167,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
);
|
||||
|
||||
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
(Joinable) entityDescriptor,
|
||||
deletingTableGroup
|
||||
);
|
||||
|
@ -177,13 +178,15 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
|
||||
boolean needsIdTable = needsIdTableWrapper.get();
|
||||
|
||||
final SqmJdbcExecutionContextAdapter executionContextAdapter = new SqmJdbcExecutionContextAdapter( executionContext );
|
||||
|
||||
if ( needsIdTable ) {
|
||||
return executeWithIdTable(
|
||||
predicate,
|
||||
deletingTableGroup,
|
||||
parameterResolutions,
|
||||
paramTypeResolutions,
|
||||
executionContext
|
||||
executionContextAdapter
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -193,7 +196,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
parameterResolutions,
|
||||
paramTypeResolutions,
|
||||
converter.getSqlExpressionResolver(),
|
||||
executionContext
|
||||
executionContextAdapter
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +390,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ import java.util.function.Supplier;
|
|||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.DeleteHandler;
|
||||
import org.hibernate.query.sqm.mutation.spi.AbstractMutationHandler;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -29,7 +29,7 @@ public class TableBasedDeleteHandler
|
|||
private static final Logger log = Logger.getLogger( TableBasedDeleteHandler.class );
|
||||
|
||||
public interface ExecutionDelegate {
|
||||
int execute(ExecutionContext executionContext);
|
||||
int execute(DomainQueryExecutionContext executionContext);
|
||||
}
|
||||
|
||||
private final IdTable idTable;
|
||||
|
@ -66,7 +66,7 @@ public class TableBasedDeleteHandler
|
|||
}
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
public int execute(DomainQueryExecutionContext executionContext) {
|
||||
if ( log.isTraceEnabled() ) {
|
||||
log.tracef(
|
||||
"Starting multi-table delete execution - %s",
|
||||
|
@ -76,7 +76,7 @@ public class TableBasedDeleteHandler
|
|||
return resolveDelegate( executionContext ).execute( executionContext );
|
||||
}
|
||||
|
||||
private ExecutionDelegate resolveDelegate(ExecutionContext executionContext) {
|
||||
private ExecutionDelegate resolveDelegate(DomainQueryExecutionContext executionContext) {
|
||||
return new RestrictedDeleteExecutionDelegate(
|
||||
getEntityDescriptor(),
|
||||
idTable,
|
||||
|
@ -88,7 +88,7 @@ public class TableBasedDeleteHandler
|
|||
exporterSupplier,
|
||||
sessionUidAccess,
|
||||
executionContext.getQueryOptions(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
executionContext.getQueryParameterBindings(),
|
||||
getSessionFactory()
|
||||
);
|
||||
|
|
|
@ -25,7 +25,9 @@ import org.hibernate.metamodel.MappingMetamodel;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
import org.hibernate.query.sqm.mutation.internal.UpdateHandler;
|
||||
import org.hibernate.query.sqm.mutation.spi.AbstractMutationHandler;
|
||||
|
@ -100,7 +102,7 @@ public class TableBasedUpdateHandler
|
|||
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
public int execute(DomainQueryExecutionContext executionContext) {
|
||||
if ( log.isTraceEnabled() ) {
|
||||
log.tracef(
|
||||
"Starting multi-table update execution - %s",
|
||||
|
@ -108,10 +110,11 @@ public class TableBasedUpdateHandler
|
|||
);
|
||||
}
|
||||
|
||||
return resolveDelegate( executionContext ).execute( executionContext );
|
||||
final SqmJdbcExecutionContextAdapter executionContextAdapter = new SqmJdbcExecutionContextAdapter( executionContext );
|
||||
return resolveDelegate( executionContext ).execute( executionContextAdapter );
|
||||
}
|
||||
|
||||
private ExecutionDelegate resolveDelegate(ExecutionContext executionContext) {
|
||||
private ExecutionDelegate resolveDelegate(DomainQueryExecutionContext executionContext) {
|
||||
final SessionFactoryImplementor sessionFactory = getSessionFactory();
|
||||
final MappingMetamodel domainModel = sessionFactory.getDomainModel();
|
||||
final EntityPersister entityDescriptor = domainModel.getEntityDescriptor( getSqmDeleteOrUpdateStatement().getTarget().getEntityName() );
|
||||
|
@ -126,7 +129,7 @@ public class TableBasedUpdateHandler
|
|||
getSqmDeleteOrUpdateStatement().getTarget().getExplicitAlias(),
|
||||
domainParameterXref,
|
||||
executionContext.getQueryOptions(),
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
executionContext.getQueryParameterBindings(),
|
||||
sessionFactory
|
||||
);
|
||||
|
@ -193,7 +196,7 @@ public class TableBasedUpdateHandler
|
|||
}
|
||||
|
||||
final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate(
|
||||
executionContext.getLoadQueryInfluencers(),
|
||||
executionContext.getSession().getLoadQueryInfluencers(),
|
||||
(Joinable) rootEntityDescriptor,
|
||||
updatingTableGroup
|
||||
);
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter;
|
||||
|
@ -83,7 +83,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
|
|||
Predicate suppliedPredicate,
|
||||
Map<SqmParameter, List<List<JdbcParameter>>> parameterResolutions,
|
||||
Map<SqmParameter, MappingModelExpressable> paramTypeResolutions,
|
||||
ExecutionContext executionContext) {
|
||||
DomainQueryExecutionContext executionContext) {
|
||||
this.sqmUpdate = sqmUpdate;
|
||||
this.sqmConverter = sqmConverter;
|
||||
this.idTable = idTable;
|
||||
|
@ -292,7 +292,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
|
|||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,14 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.SqlOmittingQueryOptions;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter;
|
||||
import org.hibernate.query.sqm.mutation.internal.DeleteHandler;
|
||||
import org.hibernate.query.sqm.mutation.internal.MatchingIdSelectionHelper;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
|
@ -25,7 +28,6 @@ import org.hibernate.sql.ast.tree.delete.DeleteStatement;
|
|||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcDelete;
|
||||
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
|
@ -44,7 +46,7 @@ public class InlineDeleteHandler implements DeleteHandler {
|
|||
private final SqmDeleteStatement sqmDeleteStatement;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
|
||||
private final ExecutionContext executionContext;
|
||||
private final DomainQueryExecutionContext executionContext;
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final SqlAstTranslatorFactory sqlAstTranslatorFactory;
|
||||
|
@ -54,7 +56,7 @@ public class InlineDeleteHandler implements DeleteHandler {
|
|||
MatchingIdRestrictionProducer matchingIdsPredicateProducer,
|
||||
SqmDeleteStatement sqmDeleteStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
this.sqmDeleteStatement = sqmDeleteStatement;
|
||||
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
|
@ -68,7 +70,7 @@ public class InlineDeleteHandler implements DeleteHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
public int execute(DomainQueryExecutionContext executionContext) {
|
||||
final List<Object> ids = MatchingIdSelectionHelper.selectMatchingIds(
|
||||
sqmDeleteStatement,
|
||||
domainParameterXref,
|
||||
|
@ -140,7 +142,7 @@ public class InlineDeleteHandler implements DeleteHandler {
|
|||
Supplier<Consumer<SelectableConsumer>> tableKeyColumnsVisitationSupplier,
|
||||
List<Object> ids,
|
||||
JdbcParameterBindings jdbcParameterBindings,
|
||||
ExecutionContext executionContext) {
|
||||
DomainQueryExecutionContext executionContext) {
|
||||
final TableReference targetTableReference = new TableReference(
|
||||
targetTableExpression,
|
||||
null,
|
||||
|
@ -148,12 +150,21 @@ public class InlineDeleteHandler implements DeleteHandler {
|
|||
sessionFactory
|
||||
);
|
||||
|
||||
final QueryOptions queryOptions = SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext.getQueryOptions() );
|
||||
|
||||
final SqmJdbcExecutionContextAdapter executionContextAdapter = new SqmJdbcExecutionContextAdapter( executionContext ) {
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return queryOptions;
|
||||
}
|
||||
};
|
||||
|
||||
final Predicate matchingIdsPredicate = matchingIdsPredicateProducer.produceRestriction(
|
||||
ids,
|
||||
entityDescriptor,
|
||||
targetTableReference,
|
||||
tableKeyColumnsVisitationSupplier,
|
||||
executionContext
|
||||
executionContextAdapter
|
||||
);
|
||||
|
||||
final DeleteStatement deleteStatement = new DeleteStatement( targetTableReference, matchingIdsPredicate );
|
||||
|
@ -166,7 +177,7 @@ public class InlineDeleteHandler implements DeleteHandler {
|
|||
jdbcParameterBindings,
|
||||
this::prepareQueryStatement,
|
||||
(integer, preparedStatement) -> {},
|
||||
SqlOmittingQueryOptions.omitSqlQueryOptions( executionContext )
|
||||
executionContextAdapter
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,14 +8,13 @@ package org.hibernate.query.sqm.mutation.internal.inline;
|
|||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
/**
|
||||
* Support for multi-table SQM mutation operations which select the matching id values from the database back into
|
||||
|
@ -45,7 +44,7 @@ public class InlineStrategy implements SqmMultiTableMutationStrategy {
|
|||
public int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
final InlineUpdateHandler handler = new InlineUpdateHandler(
|
||||
matchingIdsStrategy.apply( sqmUpdate ),
|
||||
sqmUpdate,
|
||||
|
@ -59,7 +58,7 @@ public class InlineStrategy implements SqmMultiTableMutationStrategy {
|
|||
public int executeDelete(
|
||||
SqmDeleteStatement sqmDelete,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
final InlineDeleteHandler deleteHandler = new InlineDeleteHandler(
|
||||
matchingIdsStrategy.apply( sqmDelete ),
|
||||
sqmDelete,
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.query.sqm.mutation.internal.inline;
|
|||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.UpdateHandler;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
|
@ -23,7 +24,7 @@ public class InlineUpdateHandler implements UpdateHandler {
|
|||
private final DomainParameterXref domainParameterXref;
|
||||
private final MatchingIdRestrictionProducer matchingIdsPredicateProducer;
|
||||
|
||||
private final ExecutionContext executionContext;
|
||||
private final DomainQueryExecutionContext executionContext;
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final SqlAstTranslatorFactory sqlAstTranslatorFactory;
|
||||
|
@ -33,7 +34,7 @@ public class InlineUpdateHandler implements UpdateHandler {
|
|||
MatchingIdRestrictionProducer matchingIdsPredicateProducer,
|
||||
SqmUpdateStatement sqmUpdate,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context) {
|
||||
DomainQueryExecutionContext context) {
|
||||
this.matchingIdsPredicateProducer = matchingIdsPredicateProducer;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
this.sqmUpdate = sqmUpdate;
|
||||
|
@ -46,7 +47,7 @@ public class InlineUpdateHandler implements UpdateHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int execute(ExecutionContext executionContext) {
|
||||
public int execute(DomainQueryExecutionContext executionContext) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.query.sqm.mutation.spi;
|
|||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.SqmMutationStrategyHelper;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
|
@ -56,7 +57,7 @@ public interface SqmMultiTableMutationStrategy {
|
|||
int executeUpdate(
|
||||
SqmUpdateStatement sqmUpdateStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context);
|
||||
DomainQueryExecutionContext context);
|
||||
|
||||
/**
|
||||
* Execute the multi-table update indicated by the passed SqmUpdateStatement
|
||||
|
@ -66,5 +67,5 @@ public interface SqmMultiTableMutationStrategy {
|
|||
int executeDelete(
|
||||
SqmDeleteStatement sqmDeleteStatement,
|
||||
DomainParameterXref domainParameterXref,
|
||||
ExecutionContext context);
|
||||
DomainQueryExecutionContext context);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import jakarta.persistence.ParameterMode;
|
|||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
|
|
|
@ -17,7 +17,8 @@ import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
|||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
* A context for execution of SQL statements expressed via
|
||||
* SQL AST and JdbcOperation
|
||||
*/
|
||||
public interface ExecutionContext {
|
||||
|
||||
|
@ -34,7 +35,7 @@ public interface ExecutionContext {
|
|||
Callback getCallback();
|
||||
|
||||
default void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) {
|
||||
// No-op because by default there is callback
|
||||
// No-op because by default there is no callback
|
||||
}
|
||||
|
||||
default String getQueryIdentifier(String sql) {
|
||||
|
|
|
@ -22,7 +22,13 @@ public interface CollectionLoadingLogger extends BasicLogger {
|
|||
/**
|
||||
* Static access to the logging instance
|
||||
*/
|
||||
Logger INSTANCE = LoadingLogger.subLogger( LOCAL_NAME );
|
||||
Logger COLL_LOAD_LOGGER = LoadingLogger.subLogger( LOCAL_NAME );
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #COLL_LOAD_LOGGER}
|
||||
*/
|
||||
@Deprecated
|
||||
Logger INSTANCE = COLL_LOAD_LOGGER;
|
||||
|
||||
boolean TRACE_ENABLED = INSTANCE.isTraceEnabled();
|
||||
boolean DEBUG_ENABLED = INSTANCE.isDebugEnabled();
|
||||
|
|
|
@ -13,8 +13,8 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionLoadingLogger;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
|
@ -69,6 +69,7 @@ public abstract class AbstractCollectionInitializer implements CollectionInitial
|
|||
else {
|
||||
collectionKeyValue = collectionKeyResultAssembler.assemble( rowProcessingState );
|
||||
}
|
||||
|
||||
if ( collectionKeyValue != null ) {
|
||||
this.collectionKey = new CollectionKey(
|
||||
collectionAttributeMapping.getCollectionDescriptor(),
|
||||
|
|
|
@ -25,6 +25,8 @@ import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
|||
import org.hibernate.sql.results.internal.LoadingCollectionEntryImpl;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
|
||||
import static org.hibernate.sql.results.graph.collection.CollectionLoadingLogger.COLL_LOAD_LOGGER;
|
||||
|
||||
/**
|
||||
* Base support for CollectionInitializer implementations that represent
|
||||
* an immediate initialization of some sort (join, select, batch, sub-select)
|
||||
|
@ -70,7 +72,7 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
|
|||
}
|
||||
|
||||
if ( CollectionLoadingLogger.TRACE_ENABLED ) {
|
||||
CollectionLoadingLogger.INSTANCE.tracef(
|
||||
COLL_LOAD_LOGGER.tracef(
|
||||
"(%s) Beginning Initializer#resolveInstance for collection : %s",
|
||||
getSimpleConcreteImplName(),
|
||||
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() )
|
||||
|
@ -93,7 +95,7 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
|
|||
collectionInstance = existingLoadingEntry.getCollectionInstance();
|
||||
|
||||
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
|
||||
CollectionLoadingLogger.INSTANCE.debugf(
|
||||
COLL_LOAD_LOGGER.debugf(
|
||||
"(%s) Found existing loading collection entry [%s]; using loading collection instance - %s",
|
||||
getSimpleConcreteImplName(),
|
||||
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
|
||||
|
@ -108,7 +110,7 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
|
|||
else {
|
||||
// the entity is already being loaded elsewhere
|
||||
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
|
||||
CollectionLoadingLogger.INSTANCE.debugf(
|
||||
COLL_LOAD_LOGGER.debugf(
|
||||
"(%s) Collection [%s] being loaded by another initializer [%s] - skipping processing",
|
||||
getSimpleConcreteImplName(),
|
||||
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
|
||||
|
@ -130,7 +132,7 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
|
|||
|
||||
if ( collectionInstance.wasInitialized() ) {
|
||||
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
|
||||
CollectionLoadingLogger.INSTANCE.debugf(
|
||||
COLL_LOAD_LOGGER.debugf(
|
||||
"(%s) Found existing collection instance [%s] in Session; skipping processing - [%s]",
|
||||
getSimpleConcreteImplName(),
|
||||
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
|
||||
|
@ -184,7 +186,7 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
|
|||
);
|
||||
|
||||
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
|
||||
CollectionLoadingLogger.INSTANCE.debugf(
|
||||
COLL_LOAD_LOGGER.debugf(
|
||||
"(%s) Created new collection wrapper [%s] : %s",
|
||||
getSimpleConcreteImplName(),
|
||||
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
|
||||
|
@ -203,7 +205,7 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol
|
|||
|
||||
if ( responsibility != null ) {
|
||||
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
|
||||
CollectionLoadingLogger.INSTANCE.debugf(
|
||||
COLL_LOAD_LOGGER.debugf(
|
||||
"(%s) Responsible for loading collection [%s] : %s",
|
||||
getSimpleConcreteImplName(),
|
||||
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
|
||||
|
|
|
@ -35,6 +35,7 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
|
|||
private final PluralAttributeMapping loadingAttribute;
|
||||
|
||||
private final String resultVariable;
|
||||
private final TableGroup tableGroup;
|
||||
|
||||
private final DomainResult fkResult;
|
||||
|
||||
|
@ -49,6 +50,7 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
|
|||
this.loadingPath = loadingPath;
|
||||
this.loadingAttribute = loadingAttribute;
|
||||
this.resultVariable = resultVariable;
|
||||
this.tableGroup = tableGroup;
|
||||
|
||||
fkResult = loadingAttribute.getKeyDescriptor().createKeyDomainResult(
|
||||
loadingPath,
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.metamodel.CollectionClassification;
|
|||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
|
|
|
@ -8,13 +8,18 @@ package org.hibernate.sql.results.graph.collection.internal;
|
|||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionLoadingLogger;
|
||||
|
||||
import static org.hibernate.sql.results.graph.collection.CollectionLoadingLogger.COLL_LOAD_LOGGER;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -23,11 +28,15 @@ public class SetInitializerProducer implements CollectionInitializerProducer {
|
|||
private final PluralAttributeMapping setDescriptor;
|
||||
private final Fetch elementFetch;
|
||||
|
||||
private final boolean isSubSelectFetchable;
|
||||
|
||||
public SetInitializerProducer(
|
||||
PluralAttributeMapping setDescriptor,
|
||||
Fetch elementFetch) {
|
||||
this.setDescriptor = setDescriptor;
|
||||
this.elementFetch = elementFetch;
|
||||
|
||||
isSubSelectFetchable = setDescriptor.getMappedFetchOptions().getStyle() == FetchStyle.SUBSELECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,6 +50,10 @@ public class SetInitializerProducer implements CollectionInitializerProducer {
|
|||
AssemblerCreationState creationState) {
|
||||
final DomainResultAssembler<?> elementAssembler = elementFetch.createAssembler( parentAccess, creationState );
|
||||
|
||||
if ( isSubSelectFetchable && navigablePath.isRoot() ) {
|
||||
COLL_LOAD_LOGGER.debugf( "Creating sub-select-fetch initializer : `%`", navigablePath );
|
||||
}
|
||||
|
||||
return new SetInitializer(
|
||||
navigablePath,
|
||||
setDescriptor,
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.results.ResultsLogger;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.hibernate.query.spi.QueryOptions;
|
|||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.StatementOptions;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
||||
|
|
|
@ -93,7 +93,6 @@ public class FilterWitSubSelectFetchModeTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( reason = "subselect fetch mode not implemeneted correctly in v6" )
|
||||
void testFiltersAreApplied(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
session.enableFilter( "ID" ).setParameter( "id", 3L );
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
//$Id: Child.java 6095 2005-03-17 05:57:29Z oneovthafew $
|
||||
package org.hibernate.test.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
|
@ -4,7 +4,7 @@
|
|||
* 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.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
//$Id: Parent.java 6095 2005-03-17 05:57:29Z oneovthafew $
|
||||
package org.hibernate.test.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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.mapping.collections.subselectfetch;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
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.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(annotatedClasses = {
|
||||
SimpleEagerSubSelectFetchTests.Owner.class,
|
||||
SimpleEagerSubSelectFetchTests.Thing.class
|
||||
})
|
||||
@SessionFactory( statementInspectorClass = SQLStatementInspector.class )
|
||||
public class SimpleEagerSubSelectFetchTests {
|
||||
|
||||
@Test
|
||||
public void smokeTest(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final List<Owner> misspelled = session.createQuery( "from Owner o where o.name like 'Onwer%'", Owner.class ).list();
|
||||
assertThat( misspelled ).hasSize( 2 );
|
||||
|
||||
final Owner firstResult = misspelled.get( 0 );
|
||||
final Owner secondResult = misspelled.get( 1 );
|
||||
|
||||
// make sure we got the right owners
|
||||
assertThat( firstResult.getId() ).isLessThanOrEqualTo( 2 );
|
||||
assertThat( secondResult.getId() ).isLessThanOrEqualTo( 2 );
|
||||
|
||||
// check that the one-to-many was loaded
|
||||
assertThat( Hibernate.isInitialized( firstResult.getThings() ) ).isTrue();
|
||||
assertThat( Hibernate.isInitialized( secondResult.getThings() ) ).isTrue();
|
||||
|
||||
// the initial query + the "subselect" select
|
||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baselineJoinFetchTest(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final List<Owner> misspelled = session.createQuery( "from Owner o left join fetch o.things where o.name like 'Onwer%'", Owner.class ).list();
|
||||
assertThat( misspelled ).hasSize( 2 );
|
||||
|
||||
final Owner firstResult = misspelled.get( 0 );
|
||||
final Owner secondResult = misspelled.get( 1 );
|
||||
|
||||
// make sure we got the right owners
|
||||
assertThat( firstResult.getId() ).isLessThanOrEqualTo( 2 );
|
||||
assertThat( secondResult.getId() ).isLessThanOrEqualTo( 2 );
|
||||
|
||||
// both one-to-many should be initialized
|
||||
assertThat( Hibernate.isInitialized( firstResult.getThings() ) ).isTrue();
|
||||
assertThat( Hibernate.isInitialized( secondResult.getThings() ) ).isTrue();
|
||||
|
||||
assertThat( firstResult.getThings().size() + secondResult.getThings().size() ).isEqualTo( 3 );
|
||||
|
||||
// the initial query with join
|
||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||
assertThat( statementInspector.getNumberOfJoins( 0 ) ).isEqualTo( 1 );
|
||||
} );
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void prepareTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final Owner o1 = new Owner( 1, "Onwer 1" );
|
||||
final Owner o2 = new Owner( 2, "Onwer 2" );
|
||||
final Owner o3 = new Owner( 3, "Owner 3" );
|
||||
|
||||
final Thing thing1 = new Thing( 1, "first", o1 );
|
||||
final Thing thing2 = new Thing( 2, "second", o1 );
|
||||
final Thing thing3 = new Thing( 3, "third", o1 );
|
||||
final Thing thing4 = new Thing( 4, "fourth", o3 );
|
||||
final Thing thing5 = new Thing( 5, "fifth", o3 );
|
||||
|
||||
session.persist( o1 );
|
||||
session.persist( o2 );
|
||||
session.persist( o3 );
|
||||
|
||||
session.persist( thing1 );
|
||||
session.persist( thing2 );
|
||||
session.persist( thing3 );
|
||||
session.persist( thing4 );
|
||||
session.persist( thing5 );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createQuery( "delete Thing" ).executeUpdate();
|
||||
session.createQuery( "delete Owner" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Owner")
|
||||
@Table(name = "t_sub_fetch_owner")
|
||||
public static class Owner {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
private Set<Thing> things = new HashSet<>();
|
||||
|
||||
private Owner() {
|
||||
}
|
||||
|
||||
public Owner(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Set<Thing> getThings() {
|
||||
return things;
|
||||
}
|
||||
|
||||
public void setThings(Set<Thing> things) {
|
||||
this.things = things;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Thing")
|
||||
@Table(name = "t_sub_fetch_thing")
|
||||
public static class Thing {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
private Owner owner;
|
||||
|
||||
private Thing() {
|
||||
}
|
||||
|
||||
public Thing(Integer id, String name, Owner owner) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
owner.getThings().add( this );
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Owner getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(Owner owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* 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.mapping.collections.subselectfetch;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
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.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(annotatedClasses = {
|
||||
SimpleLazySubSelectFetchTests.Owner.class,
|
||||
SimpleLazySubSelectFetchTests.Thing.class
|
||||
})
|
||||
@SessionFactory( statementInspectorClass = SQLStatementInspector.class )
|
||||
public class SimpleLazySubSelectFetchTests {
|
||||
|
||||
@Test
|
||||
public void smokeTest(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final List<Owner> misspelled = session.createQuery( "from Owner o where o.name like 'Onwer%'", Owner.class ).list();
|
||||
assertThat( misspelled ).hasSize( 2 );
|
||||
|
||||
final Owner firstResult = misspelled.get( 0 );
|
||||
final Owner secondResult = misspelled.get( 1 );
|
||||
|
||||
final Owner o1;
|
||||
final Owner o2;
|
||||
if ( firstResult.id == 1 ) {
|
||||
o1 = firstResult;
|
||||
o2 = secondResult;
|
||||
}
|
||||
else {
|
||||
o1 = secondResult;
|
||||
o2 = firstResult;
|
||||
}
|
||||
|
||||
// make sure we got the right owners
|
||||
assertThat( o1.getId() ).isEqualTo( 1 );
|
||||
assertThat( o2.getId() ).isEqualTo( 2 );
|
||||
|
||||
// check that the one-to-many are not loaded (its lazy)
|
||||
assertThat( Hibernate.isInitialized( firstResult.getThings() ) ).isFalse();
|
||||
assertThat( Hibernate.isInitialized( secondResult.getThings() ) ).isFalse();
|
||||
|
||||
// now trigger the initialization of one of them
|
||||
// - the size() call should trigger the initialization
|
||||
assertThat( o1.getThings().size() ).isEqualTo( 3 );
|
||||
|
||||
// now both should be initialized
|
||||
assertThat( Hibernate.isInitialized( firstResult.getThings() ) ).isTrue();
|
||||
assertThat( Hibernate.isInitialized( secondResult.getThings() ) ).isTrue();
|
||||
|
||||
// the initial query + the "subselect" select
|
||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 2 );
|
||||
|
||||
// access the other
|
||||
assertThat( o2.getThings().size() ).isEqualTo( 0 );
|
||||
|
||||
// make sure we did not get any extra SQL
|
||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baselineJoinFetchTest(SessionFactoryScope scope) {
|
||||
final SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
||||
scope.inTransaction( (session) -> {
|
||||
final List<Owner> misspelled = session.createQuery( "from Owner o left join fetch o.things where o.name like 'Onwer%'", Owner.class ).list();
|
||||
assertThat( misspelled ).hasSize( 2 );
|
||||
|
||||
final Owner firstResult = misspelled.get( 0 );
|
||||
final Owner secondResult = misspelled.get( 1 );
|
||||
|
||||
// make sure we got the right owners
|
||||
assertThat( firstResult.getId() ).isLessThanOrEqualTo( 2 );
|
||||
assertThat( secondResult.getId() ).isLessThanOrEqualTo( 2 );
|
||||
|
||||
// both one-to-many should be initialized
|
||||
assertThat( Hibernate.isInitialized( firstResult.getThings() ) ).isTrue();
|
||||
assertThat( Hibernate.isInitialized( secondResult.getThings() ) ).isTrue();
|
||||
|
||||
assertThat( firstResult.getThings().size() + secondResult.getThings().size() ).isEqualTo( 3 );
|
||||
|
||||
// the initial query with join
|
||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
||||
assertThat( statementInspector.getNumberOfJoins( 0 ) ).isEqualTo( 1 );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void prepareTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final Owner o1 = new Owner( 1, "Onwer 1" );
|
||||
final Owner o2 = new Owner( 2, "Onwer 2" );
|
||||
final Owner o3 = new Owner( 3, "Owner 3" );
|
||||
|
||||
final Thing thing1 = new Thing( 1, "first", o1 );
|
||||
final Thing thing2 = new Thing( 2, "second", o1 );
|
||||
final Thing thing3 = new Thing( 3, "third", o1 );
|
||||
final Thing thing4 = new Thing( 4, "fourth", o3 );
|
||||
final Thing thing5 = new Thing( 5, "fifth", o3 );
|
||||
|
||||
session.persist( o1 );
|
||||
session.persist( o2 );
|
||||
session.persist( o3 );
|
||||
|
||||
session.persist( thing1 );
|
||||
session.persist( thing2 );
|
||||
session.persist( thing3 );
|
||||
session.persist( thing4 );
|
||||
session.persist( thing5 );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createQuery( "delete Thing" ).executeUpdate();
|
||||
session.createQuery( "delete Owner" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Owner")
|
||||
@Table(name = "t_sub_fetch_owner")
|
||||
public static class Owner {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "owner", fetch = FetchType.LAZY)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
private Set<Thing> things = new HashSet<>();
|
||||
|
||||
private Owner() {
|
||||
}
|
||||
|
||||
public Owner(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Set<Thing> getThings() {
|
||||
return things;
|
||||
}
|
||||
|
||||
public void setThings(Set<Thing> things) {
|
||||
this.things = things;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Thing")
|
||||
@Table(name = "t_sub_fetch_thing")
|
||||
public static class Thing {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
private Owner owner;
|
||||
|
||||
private Thing() {
|
||||
}
|
||||
|
||||
public Thing(Integer id, String name, Owner owner) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
owner.getThings().add( this );
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Owner getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(Owner owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2006-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.NotImplementedYet;
|
||||
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.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Stephen Fikes
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@ServiceRegistry( settings = @Setting( name = AvailableSettings.GENERATE_STATISTICS, value = "true" ) )
|
||||
@DomainModel( annotatedClasses = { SubselectFetchCollectionFromBatchTest.EmployeeGroup.class, SubselectFetchCollectionFromBatchTest.Employee.class } )
|
||||
@SessionFactory
|
||||
public class SubselectFetchCollectionFromBatchTest {
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10679")
|
||||
@NotImplementedYet( strict = false, reason = "Need to check why these fail" )
|
||||
public void testSubselectFetchFromEntityBatch(SessionFactoryScope scope) {
|
||||
final EmployeeGroup[] createdGroups = scope.fromTransaction( (s) -> {
|
||||
EmployeeGroup group1 = new EmployeeGroup();
|
||||
Employee employee1 = new Employee("Jane");
|
||||
Employee employee2 = new Employee("Jeff");
|
||||
group1.addEmployee(employee1);
|
||||
group1.addEmployee(employee2);
|
||||
EmployeeGroup group2 = new EmployeeGroup();
|
||||
Employee employee3 = new Employee("Joan");
|
||||
Employee employee4 = new Employee("John");
|
||||
group2.addEmployee(employee3);
|
||||
group2.addEmployee( employee4 );
|
||||
|
||||
s.save( group1 );
|
||||
s.save( group2 );
|
||||
|
||||
return new EmployeeGroup[] { group1, group2 };
|
||||
});
|
||||
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
scope.inTransaction( (s) -> {
|
||||
EmployeeGroup[] loadedGroups = new EmployeeGroup[] {
|
||||
s.load(EmployeeGroup.class, createdGroups[0].getId()),
|
||||
s.load(EmployeeGroup.class, createdGroups[1].getId())
|
||||
};
|
||||
|
||||
// loadedGroups should only contain proxies
|
||||
assertEquals( 0, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
for (EmployeeGroup group : loadedGroups) {
|
||||
assertFalse( Hibernate.isInitialized( group ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
for ( EmployeeGroup group : loadedGroups ) {
|
||||
// Both loadedGroups get initialized and are added to the PersistenceContext when i == 0;
|
||||
// Still need to call Hibernate.initialize( loadedGroups[i] ) for i > 0 so that the entity
|
||||
// in the PersistenceContext gets assigned to its respective proxy target (is this a
|
||||
// bug???)
|
||||
Hibernate.initialize( group );
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
// the collections should be uninitialized
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
// both Group proxies should have been loaded in the same batch;
|
||||
assertEquals( 1, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
for ( EmployeeGroup group : loadedGroups ) {
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize the collection in the first; collections in both loadedGroups
|
||||
// should get initialized
|
||||
Hibernate.initialize( loadedGroups[0].getEmployees() );
|
||||
|
||||
assertEquals( 1, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
// all collections should be initialized now
|
||||
for (EmployeeGroup group : loadedGroups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubselectFetchFromQueryList(SessionFactoryScope scope) {
|
||||
final Long[] createdIds = scope.fromTransaction( (s) -> {
|
||||
EmployeeGroup group1 = new EmployeeGroup();
|
||||
Employee employee1 = new Employee("Jane");
|
||||
Employee employee2 = new Employee("Jeff");
|
||||
group1.addEmployee(employee1);
|
||||
group1.addEmployee(employee2);
|
||||
EmployeeGroup group2 = new EmployeeGroup();
|
||||
Employee employee3 = new Employee("Joan");
|
||||
Employee employee4 = new Employee("John");
|
||||
group2.addEmployee(employee3);
|
||||
group2.addEmployee( employee4 );
|
||||
|
||||
s.save( group1 );
|
||||
s.save( group2 );
|
||||
|
||||
return new Long[] { group1.id, group2.id };
|
||||
} );
|
||||
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
scope.inTransaction( (s) -> {
|
||||
List<EmployeeGroup> results = s
|
||||
.createQuery( "from SubselectFetchCollectionFromBatchTest$EmployeeGroup where id in :groups" )
|
||||
.setParameterList( "groups", createdIds )
|
||||
.list();
|
||||
|
||||
assertEquals( 1, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
for (EmployeeGroup group : results) {
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize the collection in the first; collections in both groups
|
||||
// should get initialized
|
||||
Hibernate.initialize( results.get( 0 ).getEmployees() );
|
||||
|
||||
assertEquals( 1, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
// all collections should be initialized now
|
||||
for (EmployeeGroup group : results) {
|
||||
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10679")
|
||||
@NotImplementedYet( strict = false, reason = "Need to check why these fail" )
|
||||
public void testMultiSubselectFetchSamePersisterQueryList(SessionFactoryScope scope) {
|
||||
final Long[] createdIds = scope.fromTransaction( (s) -> {
|
||||
EmployeeGroup group1 = new EmployeeGroup();
|
||||
Employee employee1 = new Employee("Jane");
|
||||
Employee employee2 = new Employee("Jeff");
|
||||
group1.addEmployee( employee1 );
|
||||
group1.addEmployee( employee2 );
|
||||
group1.setManager( new Employee( "group1 manager" ) );
|
||||
group1.getManager().addCollaborator( new Employee( "group1 manager's collaborator#1" ) );
|
||||
group1.getManager().addCollaborator( new Employee( "group1 manager's collaborator#2" ) );
|
||||
group1.setLead( new Employee( "group1 lead" ) );
|
||||
group1.getLead().addCollaborator( new Employee( "group1 lead's collaborator#1" ) );
|
||||
EmployeeGroup group2 = new EmployeeGroup();
|
||||
Employee employee3 = new Employee("Joan");
|
||||
Employee employee4 = new Employee("John");
|
||||
group2.addEmployee( employee3 );
|
||||
group2.addEmployee( employee4 );
|
||||
group2.setManager( new Employee( "group2 manager" ) );
|
||||
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#1" ) );
|
||||
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#2" ) );
|
||||
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#3" ) );
|
||||
group2.setLead( new Employee( "group2 lead" ) );
|
||||
group2.getLead().addCollaborator( new Employee( "group2 lead's collaborator#1" ) );
|
||||
group2.getLead().addCollaborator( new Employee( "group2 lead's collaborator#2" ) );
|
||||
|
||||
s.save( group1 );
|
||||
s.save( group2 );
|
||||
|
||||
return new Long[] { group1.id, group2.id };
|
||||
} );
|
||||
|
||||
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
scope.inTransaction( (s) -> {
|
||||
EmployeeGroup[] loadedGroups = new EmployeeGroup[] {
|
||||
s.load(EmployeeGroup.class, createdIds[0]),
|
||||
s.load(EmployeeGroup.class, createdIds[1])
|
||||
};
|
||||
|
||||
// loadedGroups should only contain proxies
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
|
||||
for (EmployeeGroup group : loadedGroups) {
|
||||
assertFalse( Hibernate.isInitialized( group ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
|
||||
|
||||
for ( EmployeeGroup group : loadedGroups ) {
|
||||
// Both loadedGroups get initialized and are added to the PersistenceContext when i == 0;
|
||||
// Still need to call Hibernate.initialize( loadedGroups[i] ) for i > 0 so that the entity
|
||||
// in the PersistenceContext gets assigned to its respective proxy target (is this a
|
||||
// bug???)
|
||||
Hibernate.initialize( group );
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertTrue( Hibernate.isInitialized( group.getLead() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
|
||||
assertTrue( Hibernate.isInitialized( group.getManager() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
// the collections should be uninitialized
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
// both Group proxies should have been loaded in the same batch;
|
||||
assertEquals( 1, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
for ( EmployeeGroup group : loadedGroups ) {
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize the collection in the first; collections in both loadedGroups
|
||||
// should get initialized
|
||||
Hibernate.initialize( loadedGroups[0].getEmployees() );
|
||||
|
||||
assertEquals( 1, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
// all EmployeeGroup#employees should be initialized now
|
||||
for (EmployeeGroup group : loadedGroups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize loadedGroups[0].getLead().getCollaborators();
|
||||
// loadedGroups[1].getLead().getCollaborators() should also be initialized
|
||||
Hibernate.initialize( loadedGroups[0].getLead().getCollaborators() );
|
||||
|
||||
assertEquals( 1, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
for (EmployeeGroup group : loadedGroups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize loadedGroups[0].getManager().getCollaborators();
|
||||
// loadedGroups[1].getManager().getCollaborators() should also be initialized
|
||||
Hibernate.initialize( loadedGroups[0].getManager().getCollaborators() );
|
||||
|
||||
assertEquals( 1, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory.getStatistics().clear();
|
||||
|
||||
for (EmployeeGroup group : loadedGroups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
|
||||
assertEquals( loadedGroups[0].getLead().getCollaborators().size(), loadedGroups[0].getLead().getCollaborators().size() );
|
||||
assertEquals( loadedGroups[1].getLead().getCollaborators().size(), loadedGroups[1].getLead().getCollaborators().size() );
|
||||
assertEquals( loadedGroups[0].getManager().getCollaborators().size(), loadedGroups[0].getManager().getCollaborators().size() );
|
||||
assertEquals( loadedGroups[1].getManager().getCollaborators().size(), loadedGroups[1].getManager().getCollaborators().size() );
|
||||
|
||||
assertEquals( 0, sessionFactory.getStatistics().getPrepareStatementCount() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "EmployeeGroup")
|
||||
@BatchSize(size = 1000)
|
||||
public static class EmployeeGroup {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
private Employee manager;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
private Employee lead;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
@JoinTable(name="EmployeeGroup_employees")
|
||||
private List<Employee> employees = new ArrayList<Employee>();
|
||||
|
||||
public EmployeeGroup(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected EmployeeGroup() {
|
||||
}
|
||||
|
||||
public Employee getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public void setManager(Employee manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public Employee getLead() {
|
||||
return lead;
|
||||
}
|
||||
|
||||
public void setLead(Employee lead) {
|
||||
this.lead = lead;
|
||||
}
|
||||
|
||||
public boolean addEmployee(Employee employee) {
|
||||
return employees.add(employee);
|
||||
}
|
||||
|
||||
public List<Employee> getEmployees() {
|
||||
return employees;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "Employee")
|
||||
public static class Employee {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
private List<Employee> collaborators = new ArrayList<Employee>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Employee() {
|
||||
}
|
||||
|
||||
public Employee(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean addCollaborator(Employee employee) {
|
||||
return collaborators.add(employee);
|
||||
}
|
||||
|
||||
public List<Employee> getCollaborators() {
|
||||
return collaborators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,21 +4,25 @@
|
|||
* 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.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.NotImplementedYet;
|
||||
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.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
@ -27,21 +31,21 @@ import static org.junit.Assert.assertTrue;
|
|||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] { "subselectfetch/ParentChild.hbm.xml" };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
cfg.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
cfg.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
}
|
||||
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@Setting( name = AvailableSettings.GENERATE_STATISTICS, value = "true" ),
|
||||
@Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "false" )
|
||||
}
|
||||
)
|
||||
@DomainModel(
|
||||
xmlMappings = "/mappings/subselectfetch/ParentChild.hbm.xml"
|
||||
)
|
||||
@SessionFactory
|
||||
@NotImplementedYet( strict = false, reason = "Need to check why these fail" )
|
||||
public class SubselectFetchTest {
|
||||
@Test
|
||||
public void testSubselectFetchHql() {
|
||||
inTransaction(
|
||||
public void testSubselectFetchHql(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Parent p = new Parent( "foo" );
|
||||
p.getChildren().add( new Child( "foo1" ) );
|
||||
|
@ -55,9 +59,9 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
sessionFactory().getStatistics().clear();
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
List parents = s.createQuery( "from Parent where name between 'bar' and 'foo' order by name desc" )
|
||||
.list();
|
||||
|
@ -88,7 +92,7 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
|
||||
|
||||
assertEquals( 3, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
assertEquals( 3, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
Child c = (Child) p.getChildren().get( 0 );
|
||||
c.getFriends().size();
|
||||
|
@ -100,8 +104,8 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSubselectFetchNamedParam() {
|
||||
inTransaction(
|
||||
public void testSubselectFetchNamedParam(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Parent p = new Parent( "foo" );
|
||||
p.getChildren().add( new Child( "foo1" ) );
|
||||
|
@ -115,9 +119,9 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
sessionFactory().getStatistics().clear();
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
List parents = s.createQuery( "from Parent where name between :bar and :foo order by name desc" )
|
||||
.setParameter( "bar", "bar" )
|
||||
|
@ -150,7 +154,7 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
|
||||
|
||||
assertEquals( 3, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
assertEquals( 3, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
Child c = (Child) p.getChildren().get( 0 );
|
||||
c.getFriends().size();
|
||||
|
@ -162,8 +166,8 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSubselectFetchPosParam() {
|
||||
inTransaction(
|
||||
public void testSubselectFetchPosParam(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Parent p = new Parent( "foo" );
|
||||
p.getChildren().add( new Child( "foo1" ) );
|
||||
|
@ -177,9 +181,9 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
sessionFactory().getStatistics().clear();
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
List parents = s.createQuery( "from Parent where name between ?1 and ?2 order by name desc" )
|
||||
.setParameter( 1, "bar" )
|
||||
|
@ -212,7 +216,7 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
|
||||
|
||||
assertEquals( 3, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
assertEquals( 3, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
Child c = (Child) p.getChildren().get( 0 );
|
||||
c.getFriends().size();
|
||||
|
@ -224,12 +228,13 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSubselectFetchWithLimit() {
|
||||
public void testSubselectFetchWithLimit(SessionFactoryScope scope) {
|
||||
|
||||
Parent parent = new Parent( "foo" );
|
||||
Parent secondParent = new Parent( "bar" );
|
||||
Parent thirdParent = new Parent( "aaa" );
|
||||
inTransaction(
|
||||
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
parent.getChildren().add( new Child( "foo1" ) );
|
||||
parent.getChildren().add( new Child( "foo2" ) );
|
||||
|
@ -242,9 +247,9 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
sessionFactory().getStatistics().clear();
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
List parents = s.createQuery( "from Parent order by name desc" )
|
||||
.setMaxResults( 2 )
|
||||
|
@ -260,7 +265,7 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
assertTrue( Hibernate.isInitialized( q.getChildren() ) );
|
||||
assertTrue( Hibernate.isInitialized( q.getMoreChildren() ) );
|
||||
|
||||
assertEquals( 3, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
assertEquals( 3, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
Parent r = s.get( Parent.class, thirdParent.getName() );
|
||||
assertTrue( Hibernate.isInitialized( r.getChildren() ) );
|
||||
|
@ -276,8 +281,8 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testManyToManyCriteriaJoin() {
|
||||
inTransaction(
|
||||
public void testManyToManyCriteriaJoin(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Parent p = new Parent( "foo" );
|
||||
p.getChildren().add( new Child( "foo1" ) );
|
||||
|
@ -291,7 +296,7 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Parent> criteria = criteriaBuilder.createQuery( Parent.class );
|
||||
|
@ -329,8 +334,8 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSubselectFetchCriteria() {
|
||||
inTransaction(
|
||||
public void testSubselectFetchCriteria(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
Parent p = new Parent( "foo" );
|
||||
p.getChildren().add( new Child( "foo1" ) );
|
||||
|
@ -345,9 +350,9 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
);
|
||||
|
||||
|
||||
inTransaction(
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
sessionFactory().getStatistics().clear();
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Parent> criteria = criteriaBuilder.createQuery( Parent.class );
|
||||
|
@ -387,7 +392,7 @@ public class SubselectFetchTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
assertTrue( Hibernate.isInitialized( q.getMoreChildren().iterator().next() ) );
|
||||
|
||||
assertEquals( 3, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
assertEquals( 3, scope.getSessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
Child c = (Child) p.getChildren().get( 0 );
|
||||
c.getFriends().size();
|
|
@ -4,7 +4,7 @@
|
|||
* 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.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -35,8 +35,8 @@ public class SubselectFetchWithFormulaTest extends BaseNonConfigCoreFunctionalTe
|
|||
@Override
|
||||
protected String[] getMappings() {
|
||||
return new String[] {
|
||||
"org/hibernate/test/subselectfetch/Name.hbm.xml",
|
||||
"org/hibernate/test/subselectfetch/Value.hbm.xml"
|
||||
"mappings/subselectfetch/Name.hbm.xml",
|
||||
"mappings/subselectfetch/Value.hbm.xml"
|
||||
};
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
|
@ -33,8 +33,8 @@ public class SubselectFetchWithFormulaTransactSqlTest extends BaseNonConfigCoreF
|
|||
@Override
|
||||
protected String[] getMappings() {
|
||||
return new String[] {
|
||||
"org/hibernate/test/subselectfetch/NameTransactSql.hbm.xml",
|
||||
"org/hibernate/test/subselectfetch/Value.hbm.xml"
|
||||
"mappings/subselectfetch/NameTransactSql.hbm.xml",
|
||||
"mappings/subselectfetch/Value.hbm.xml"
|
||||
};
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.subselectfetch;
|
||||
package org.hibernate.orm.test.mapping.collections.subselectfetch;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
|
@ -21,6 +21,7 @@ import org.hibernate.Session;
|
|||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
|
@ -95,7 +96,7 @@ public class ParameterTests extends BaseSqmUnitTest {
|
|||
query.setParameter( "start", Date.from( Instant.now().minus( 7, ChronoUnit.DAYS ) ), TemporalType.TIMESTAMP );
|
||||
query.setParameter( "end", Date.from( Instant.now().plus( 7, ChronoUnit.DAYS ) ), TemporalType.TIMESTAMP );
|
||||
|
||||
final QueryParameterBindings bindings = ( (ExecutionContext) query ).getQueryParameterBindings();
|
||||
final QueryParameterBindings bindings = ( (DomainQueryExecutionContext) query ).getQueryParameterBindings();
|
||||
|
||||
final QueryParameterBinding<?> startBinding = bindings.getBinding( "start" );
|
||||
assertThat( startBinding.getExplicitTemporalPrecision(), equalTo( TemporalType.TIMESTAMP ) );
|
||||
|
@ -113,7 +114,7 @@ public class ParameterTests extends BaseSqmUnitTest {
|
|||
query.setParameter( "start", Instant.now().minus( 7, ChronoUnit.DAYS ), TemporalType.DATE );
|
||||
query.setParameter( "end", Instant.now().plus( 7, ChronoUnit.DAYS ), TemporalType.DATE );
|
||||
|
||||
final QueryParameterBindings bindings = ( (ExecutionContext) query ).getQueryParameterBindings();
|
||||
final QueryParameterBindings bindings = ( (DomainQueryExecutionContext) query ).getQueryParameterBindings();
|
||||
|
||||
final QueryParameterBinding<?> startBinding = bindings.getBinding( "start" );
|
||||
assertThat( startBinding.getExplicitTemporalPrecision(), equalTo( TemporalType.DATE ) );
|
||||
|
|
|
@ -12,13 +12,13 @@ import org.hibernate.orm.test.mapping.SecondaryTableTests;
|
|||
import org.hibernate.orm.test.mapping.inheritance.joined.JoinedInheritanceTest;
|
||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.MatchingIdSelectionHelper;
|
||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
@ -68,7 +68,7 @@ public class IdSelectionTests {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final ExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
final DomainQueryExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
|
||||
MatchingIdSelectionHelper.selectMatchingIds( sqm, domainParameterXref, executionContext );
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ public class IdSelectionTests {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final ExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
final DomainQueryExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
|
||||
MatchingIdSelectionHelper.selectMatchingIds( sqm, domainParameterXref, executionContext );
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ public class IdSelectionTests {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final ExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
final DomainQueryExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
|
||||
MatchingIdSelectionHelper.selectMatchingIds( sqm, domainParameterXref, executionContext );
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ public class IdSelectionTests {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final ExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
final DomainQueryExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
|
||||
MatchingIdSelectionHelper.selectMatchingIds( sqm, domainParameterXref, executionContext );
|
||||
}
|
||||
|
@ -168,14 +168,14 @@ public class IdSelectionTests {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final ExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
final DomainQueryExecutionContext executionContext = new TestExecutionContext( session, domainParamBindings );
|
||||
|
||||
MatchingIdSelectionHelper.selectMatchingIds( sqm, domainParameterXref, executionContext );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static class TestExecutionContext implements ExecutionContext {
|
||||
private static class TestExecutionContext implements DomainQueryExecutionContext {
|
||||
private final SessionImplementor session;
|
||||
private final QueryParameterBindingsImpl domainParamBindings;
|
||||
|
||||
|
|
|
@ -1,437 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2006-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.subselectfetch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Stephen Fikes
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class SubselectFetchCollectionFromBatchTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
cfg.setProperty( Environment.GENERATE_STATISTICS, "true");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10679")
|
||||
public void testSubselectFetchFromEntityBatch() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
EmployeeGroup group1 = new EmployeeGroup();
|
||||
Employee employee1 = new Employee("Jane");
|
||||
Employee employee2 = new Employee("Jeff");
|
||||
group1.addEmployee(employee1);
|
||||
group1.addEmployee(employee2);
|
||||
EmployeeGroup group2 = new EmployeeGroup();
|
||||
Employee employee3 = new Employee("Joan");
|
||||
Employee employee4 = new Employee("John");
|
||||
group2.addEmployee(employee3);
|
||||
group2.addEmployee( employee4 );
|
||||
|
||||
s.save( group1 );
|
||||
s.save( group2 );
|
||||
s.flush();
|
||||
|
||||
s.clear();
|
||||
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
EmployeeGroup[] groups = new EmployeeGroup[] {
|
||||
(EmployeeGroup) s.load(EmployeeGroup.class, group1.getId()),
|
||||
(EmployeeGroup) s.load(EmployeeGroup.class, group2.getId())
|
||||
};
|
||||
|
||||
// groups should only contain proxies
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
for (EmployeeGroup group : groups) {
|
||||
assertFalse( Hibernate.isInitialized( group ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
|
||||
for ( EmployeeGroup group : groups ) {
|
||||
// Both groups get initialized and are added to the PersistenceContext when i == 0;
|
||||
// Still need to call Hibernate.initialize( groups[i] ) for i > 0 so that the entity
|
||||
// in the PersistenceContext gets assigned to its respective proxy target (is this a
|
||||
// bug???)
|
||||
Hibernate.initialize( group );
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
// the collections should be uninitialized
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
// both Group proxies should have been loaded in the same batch;
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
for ( EmployeeGroup group : groups ) {
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize the collection in the first; collections in both groups
|
||||
// should get initialized
|
||||
Hibernate.initialize( groups[0].getEmployees() );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
// all collections should be initialized now
|
||||
for (EmployeeGroup group : groups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
t.rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubselectFetchFromQueryList() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
EmployeeGroup group1 = new EmployeeGroup();
|
||||
Employee employee1 = new Employee("Jane");
|
||||
Employee employee2 = new Employee("Jeff");
|
||||
group1.addEmployee(employee1);
|
||||
group1.addEmployee(employee2);
|
||||
EmployeeGroup group2 = new EmployeeGroup();
|
||||
Employee employee3 = new Employee("Joan");
|
||||
Employee employee4 = new Employee("John");
|
||||
group2.addEmployee(employee3);
|
||||
group2.addEmployee( employee4 );
|
||||
|
||||
s.save( group1 );
|
||||
s.save( group2 );
|
||||
s.flush();
|
||||
|
||||
s.clear();
|
||||
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
List<EmployeeGroup> results = s.createQuery(
|
||||
"from SubselectFetchCollectionFromBatchTest$EmployeeGroup where id in :groups"
|
||||
).setParameterList(
|
||||
"groups",
|
||||
new Long[] { group1.getId(), group2.getId() }
|
||||
).list();
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
for (EmployeeGroup group : results) {
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize the collection in the first; collections in both groups
|
||||
// should get initialized
|
||||
Hibernate.initialize( results.get( 0 ).getEmployees() );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
// all collections should be initialized now
|
||||
for (EmployeeGroup group : results) {
|
||||
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
t.rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10679")
|
||||
public void testMultiSubselectFetchSamePersisterQueryList() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
EmployeeGroup group1 = new EmployeeGroup();
|
||||
Employee employee1 = new Employee("Jane");
|
||||
Employee employee2 = new Employee("Jeff");
|
||||
group1.addEmployee( employee1 );
|
||||
group1.addEmployee( employee2 );
|
||||
group1.setManager( new Employee( "group1 manager" ) );
|
||||
group1.getManager().addCollaborator( new Employee( "group1 manager's collaborator#1" ) );
|
||||
group1.getManager().addCollaborator( new Employee( "group1 manager's collaborator#2" ) );
|
||||
group1.setLead( new Employee( "group1 lead" ) );
|
||||
group1.getLead().addCollaborator( new Employee( "group1 lead's collaborator#1" ) );
|
||||
EmployeeGroup group2 = new EmployeeGroup();
|
||||
Employee employee3 = new Employee("Joan");
|
||||
Employee employee4 = new Employee("John");
|
||||
group2.addEmployee( employee3 );
|
||||
group2.addEmployee( employee4 );
|
||||
group2.setManager( new Employee( "group2 manager" ) );
|
||||
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#1" ) );
|
||||
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#2" ) );
|
||||
group2.getManager().addCollaborator( new Employee( "group2 manager's collaborator#3" ) );
|
||||
group2.setLead( new Employee( "group2 lead" ) );
|
||||
group2.getLead().addCollaborator( new Employee( "group2 lead's collaborator#1" ) );
|
||||
group2.getLead().addCollaborator( new Employee( "group2 lead's collaborator#2" ) );
|
||||
s.save( group1 );
|
||||
s.save( group2 );
|
||||
s.flush();
|
||||
|
||||
s.clear();
|
||||
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
EmployeeGroup[] groups = new EmployeeGroup[] {
|
||||
(EmployeeGroup) s.load(EmployeeGroup.class, group1.getId()),
|
||||
(EmployeeGroup) s.load(EmployeeGroup.class, group2.getId())
|
||||
};
|
||||
|
||||
// groups should only contain proxies
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
for (EmployeeGroup group : groups) {
|
||||
assertFalse( Hibernate.isInitialized( group ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
|
||||
for ( EmployeeGroup group : groups ) {
|
||||
// Both groups get initialized and are added to the PersistenceContext when i == 0;
|
||||
// Still need to call Hibernate.initialize( groups[i] ) for i > 0 so that the entity
|
||||
// in the PersistenceContext gets assigned to its respective proxy target (is this a
|
||||
// bug???)
|
||||
Hibernate.initialize( group );
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertTrue( Hibernate.isInitialized( group.getLead() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
|
||||
assertTrue( Hibernate.isInitialized( group.getManager() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
// the collections should be uninitialized
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
// both Group proxies should have been loaded in the same batch;
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
for ( EmployeeGroup group : groups ) {
|
||||
assertTrue( Hibernate.isInitialized( group ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize the collection in the first; collections in both groups
|
||||
// should get initialized
|
||||
Hibernate.initialize( groups[0].getEmployees() );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
// all EmployeeGroup#employees should be initialized now
|
||||
for (EmployeeGroup group : groups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getEmployees() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize groups[0].getLead().getCollaborators();
|
||||
// groups[1].getLead().getCollaborators() should also be initialized
|
||||
Hibernate.initialize( groups[0].getLead().getCollaborators() );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
for (EmployeeGroup group : groups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getLead().getCollaborators() ) );
|
||||
assertFalse( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
// now initialize groups[0].getManager().getCollaborators();
|
||||
// groups[1].getManager().getCollaborators() should also be initialized
|
||||
Hibernate.initialize( groups[0].getManager().getCollaborators() );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
for (EmployeeGroup group : groups) {
|
||||
assertTrue( Hibernate.isInitialized( group.getManager().getCollaborators() ) );
|
||||
}
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
assertEquals( group1.getLead().getCollaborators().size(), groups[0].getLead().getCollaborators().size() );
|
||||
assertEquals( group2.getLead().getCollaborators().size(), groups[1].getLead().getCollaborators().size() );
|
||||
assertEquals( group1.getManager().getCollaborators().size(), groups[0].getManager().getCollaborators().size() );
|
||||
assertEquals( group2.getManager().getCollaborators().size(), groups[1].getManager().getCollaborators().size() );
|
||||
|
||||
assertEquals( 0, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
t.rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { EmployeeGroup.class, Employee.class };
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "EmployeeGroup")
|
||||
@BatchSize(size = 1000)
|
||||
private static class EmployeeGroup {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
private Employee manager;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
private Employee lead;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
@JoinTable(name="EmployeeGroup_employees")
|
||||
private List<Employee> employees = new ArrayList<Employee>();
|
||||
|
||||
public EmployeeGroup(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected EmployeeGroup() {
|
||||
}
|
||||
|
||||
public Employee getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public void setManager(Employee manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public Employee getLead() {
|
||||
return lead;
|
||||
}
|
||||
|
||||
public void setLead(Employee lead) {
|
||||
this.lead = lead;
|
||||
}
|
||||
|
||||
public boolean addEmployee(Employee employee) {
|
||||
return employees.add(employee);
|
||||
}
|
||||
|
||||
public List<Employee> getEmployees() {
|
||||
return employees;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "Employee")
|
||||
private static class Employee {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@Fetch(FetchMode.SUBSELECT)
|
||||
private List<Employee> collaborators = new ArrayList<Employee>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Employee() {
|
||||
}
|
||||
|
||||
public Employee(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean addCollaborator(Employee employee) {
|
||||
return collaborators.add(employee);
|
||||
}
|
||||
|
||||
public List<Employee> getCollaborators() {
|
||||
return collaborators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.subselectfetch.Name" table="T_Name">
|
||||
<class name="org.hibernate.orm.test.mapping.collections.subselectfetch.Name" table="T_Name">
|
||||
<id name="id" column="id"/>
|
||||
<property name="name" column="c_name"/>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
|
||||
<bag name="values" inverse="true" lazy="false" fetch="subselect">
|
||||
<key column="name_id"/>
|
||||
<one-to-many class="org.hibernate.test.subselectfetch.Value"/>
|
||||
<one-to-many class="org.hibernate.orm.test.mapping.collections.subselectfetch.Value"/>
|
||||
</bag>
|
||||
|
||||
</class>
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.subselectfetch.Name" table="T_Name">
|
||||
<class name="org.hibernate.orm.test.mapping.collections.subselectfetch.Name" table="T_Name">
|
||||
<id name="id" column="id"/>
|
||||
<property name="name" column="c_name"/>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
|
||||
<bag name="values" inverse="true" lazy="false" fetch="subselect">
|
||||
<key column="name_id"/>
|
||||
<one-to-many class="org.hibernate.test.subselectfetch.Value"/>
|
||||
<one-to-many class="org.hibernate.orm.test.mapping.collections.subselectfetch.Value"/>
|
||||
</bag>
|
||||
|
||||
</class>
|
|
@ -10,7 +10,7 @@
|
|||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping
|
||||
package="org.hibernate.test.subselectfetch">
|
||||
package="org.hibernate.orm.test.mapping.collections.subselectfetch">
|
||||
|
||||
<class name="Child">
|
||||
<id name="name"/>
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.test.subselectfetch.Value" table="T_Value">
|
||||
<class name="org.hibernate.orm.test.mapping.collections.subselectfetch.Value" table="T_Value">
|
||||
<id name="id" column="id"/>
|
||||
<property name="value" column="c_value"/>
|
||||
<many-to-one name="name" column="name_id" insert="false" update="false" />
|
Loading…
Reference in New Issue