HHH-13720 - Implement mapping model support for plural attributes

a lot is working.  annoying bug still that affects deleting "element collection" data
This commit is contained in:
Steve Ebersole 2019-11-23 03:23:35 -06:00
parent 8a196bc0e5
commit a6722fe57a
97 changed files with 3753 additions and 619 deletions

View File

@ -11,14 +11,30 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.engine.FetchTiming;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.collection.BagInitializerProducer;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.FetchParent;
/**
* @author Steve Ebersole
*/
public abstract class AbstractBagSemantics<B extends Collection<?>> implements CollectionSemantics<B> {
@Override
public Class<B> getCollectionJavaType() {
//noinspection unchecked
return (Class) Collection.class;
}
@Override
@SuppressWarnings("unchecked")
public B instantiateRaw(
@ -47,4 +63,40 @@ public abstract class AbstractBagSemantics<B extends Collection<?>> implements C
rawCollection.forEach( action );
}
}
@Override
public CollectionInitializerProducer createInitializerProducer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParent fetchParent,
boolean selected,
String resultVariable,
LockMode lockMode,
DomainResultCreationState creationState) {
final TableGroup tableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( navigablePath );
return new BagInitializerProducer(
attributeMapping,
selected,
attributeMapping.getIdentifierDescriptor() == null ? null : attributeMapping.getIdentifierDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.ID.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
),
attributeMapping.getElementDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
)
);
}
}

View File

@ -12,12 +12,28 @@ import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.MapSemantics;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.collection.MapInitializerProducer;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.FetchParent;
/**
* @author Steve Ebersole
*/
public abstract class AbstractMapSemantics<M extends Map<?,?>> implements MapSemantics<M> {
@Override
public Class<M> getCollectionJavaType() {
//noinspection unchecked
return (Class) Map.class;
}
@Override
public Iterator getKeyIterator(M rawMap) {
if ( rawMap == null ) {
@ -60,4 +76,40 @@ public abstract class AbstractMapSemantics<M extends Map<?,?>> implements MapSem
rawMap.values().forEach( action );
}
}
@Override
public CollectionInitializerProducer createInitializerProducer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParent fetchParent,
boolean selected,
String resultVariable,
LockMode lockMode,
DomainResultCreationState creationState) {
final TableGroup tableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( navigablePath );
return new MapInitializerProducer(
attributeMapping,
selected,
attributeMapping.getIndexDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
),
attributeMapping.getElementDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
)
);
}
}

View File

@ -615,6 +615,10 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
this.initialized = true;
}
protected boolean isInitializing() {
return initializing;
}
protected final void setDirectlyAccessible(boolean directlyAccessible) {
this.directlyAccessible = directlyAccessible;
}

View File

@ -10,12 +10,27 @@ import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.internal.domain.collection.SetInitializerProducer;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.FetchParent;
/**
* @author Steve Ebersole
*/
public abstract class AbstractSetSemantics<S extends Set<?>> implements CollectionSemantics<S> {
@Override
public Class<S> getCollectionJavaType() {
//noinspection unchecked
return (Class) Set.class;
}
@Override
public Iterator getElementIterator(Set rawCollection) {
if ( rawCollection == null ) {
@ -31,4 +46,28 @@ public abstract class AbstractSetSemantics<S extends Set<?>> implements Collecti
rawCollection.forEach( action );
}
}
@Override
public CollectionInitializerProducer createInitializerProducer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParent fetchParent,
boolean selected,
String resultVariable,
LockMode lockMode,
DomainResultCreationState creationState) {
return new SetInitializerProducer(
attributeMapping,
selected,
attributeMapping.getElementDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
)
);
}
}

View File

@ -336,4 +336,14 @@ public class PersistentArrayHolder extends AbstractPersistentCollection {
public boolean entryExists(Object entry, int i) {
return entry != null;
}
public void load(int index, Object element) {
assert isInitializing();
for ( int i = tempList.size(); i <= index; ++i ) {
tempList.add( i, null );
}
tempList.set( index, element );
}
}

View File

@ -661,6 +661,11 @@ public class PersistentBag extends AbstractPersistentCollection implements List
return super.hashCode();
}
public void load(Object element) {
assert isInitializing();
bag.add( element );
}
final class Clear implements DelayedOperation {
@Override
public void operate() {

View File

@ -544,4 +544,12 @@ public class PersistentIdentifierBag extends AbstractPersistentCollection implem
//TODO: if we are using identity columns, fetch the identifier
}
public void load(Object identifier, Object element) {
assert isInitializing();
Object old = identifiers.put( values.size(), identifier );
if ( old == null ) {
//maintain correct duplication if loaded in a cartesian product
values.add( element );
}
}
}

View File

@ -129,6 +129,15 @@ public class PersistentList extends AbstractPersistentCollection implements List
this.list = (List) persister.getCollectionType().instantiate( anticipatedSize );
}
public void load(int index, Object element) {
assert isInitializing();
// todo (6.0) : we need to account for base - but it is not exposed from collection descriptor nor attribute
for ( int i = list.size(); i <= index; ++i ) {
list.add( i, null );
}
list.set( index, element );
}
@Override
public boolean isWrapper(Object collection) {
return list==collection;

View File

@ -145,6 +145,11 @@ public class PersistentMap extends AbstractPersistentCollection implements Map {
this.map = (Map) persister.getCollectionType().instantiate( anticipatedSize );
}
public void load(Object key, Object value) {
assert isInitializing();
map.put( key, value );
}
@Override
public int size() {
return readSize() ? getCachedSize() : map.size();

View File

@ -144,6 +144,12 @@ public class PersistentSet extends AbstractPersistentCollection implements java.
this.set = (Set) persister.getCollectionType().instantiate( anticipatedSize );
}
@SuppressWarnings("unchecked")
public void load(Object element) {
assert isInitializing();
tempList.add( element );
}
@Override
@SuppressWarnings("unchecked")
public void initializeFromCache(CollectionPersister persister, Object disassembled, Object owner)

View File

@ -10,11 +10,21 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.collection.ArrayInitializerProducer;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.FetchParent;
/**
* CollectionSemantics implementation for arrays
@ -35,6 +45,11 @@ public class StandardArraySemantics implements CollectionSemantics<Object[]> {
return CollectionClassification.ARRAY;
}
@Override
public Class<Object[]> getCollectionJavaType() {
return Object[].class;
}
@Override
public Object[] instantiateRaw(
int anticipatedSize,
@ -78,6 +93,41 @@ public class StandardArraySemantics implements CollectionSemantics<Object[]> {
for ( Object element : array ) {
action.accept( element );
}
}
@Override
public CollectionInitializerProducer createInitializerProducer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParent fetchParent,
boolean selected,
String resultVariable,
LockMode lockMode,
DomainResultCreationState creationState) {
final TableGroup tableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( navigablePath );
return new ArrayInitializerProducer(
attributeMapping,
selected,
attributeMapping.getIndexDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
),
attributeMapping.getElementDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
)
);
}
}

View File

@ -10,12 +10,22 @@ import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.collection.ListInitializerProducer;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.FetchParent;
/**
* Hibernate's standard CollectionSemantics for Lists
@ -36,6 +46,11 @@ public class StandardListSemantics implements CollectionSemantics<List> {
return CollectionClassification.LIST;
}
@Override
public Class<List> getCollectionJavaType() {
return List.class;
}
@Override
public List instantiateRaw(
int anticipatedSize,
@ -54,6 +69,42 @@ public class StandardListSemantics implements CollectionSemantics<List> {
rawCollection.forEach( action );
}
@Override
public CollectionInitializerProducer createInitializerProducer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParent fetchParent,
boolean selected,
String resultVariable,
LockMode lockMode,
DomainResultCreationState creationState) {
final TableGroup tableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( navigablePath );
return new ListInitializerProducer(
attributeMapping,
selected,
attributeMapping.getIndexDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
),
attributeMapping.getElementDescriptor().generateFetch(
fetchParent,
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
FetchTiming.IMMEDIATE,
selected,
lockMode,
null,
creationState
)
);
}
@Override
public PersistentCollection instantiateWrapper(
Object key,

View File

@ -31,6 +31,12 @@ public class StandardSortedMapSemantics extends AbstractMapSemantics<SortedMap<?
return CollectionClassification.SORTED_MAP;
}
@Override
public Class<SortedMap<?, ?>> getCollectionJavaType() {
//noinspection unchecked
return (Class) SortedMap.class;
}
@Override
public TreeMap<?, ?> instantiateRaw(
int anticipatedSize,

View File

@ -32,6 +32,12 @@ public class StandardSortedSetSemantics extends AbstractSetSemantics<SortedSet<?
return CollectionClassification.SORTED_SET;
}
@Override
public Class<SortedSet<?>> getCollectionJavaType() {
//noinspection unchecked
return (Class) SortedSet.class;
}
@Override
public SortedSet instantiateRaw(
int anticipatedSize,

View File

@ -0,0 +1,39 @@
/*
* 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.collection.spi;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* Functional contract to create a CollectionInitializer
*
* @author Steve Ebersole
*/
@FunctionalInterface
public interface CollectionInitializerProducer {
/**
* todo (6.0) : clean this contract up!
*/
CollectionInitializer produceInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState);
}

View File

@ -10,9 +10,14 @@ import java.util.Iterator;
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
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.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.FetchParent;
/**
* Describes the semantics of a persistent collection such that Hibernate
@ -30,6 +35,8 @@ public interface CollectionSemantics<C> {
*/
CollectionClassification getCollectionClassification();
Class<C> getCollectionJavaType();
C instantiateRaw(
int anticipatedSize,
CollectionPersister collectionDescriptor);
@ -47,4 +54,16 @@ public interface CollectionSemantics<C> {
Iterator getElementIterator(C rawCollection);
void visitElements(C rawCollection, Consumer action);
/**
* todo (6.0) : clean this contract up!
*/
CollectionInitializerProducer createInitializerProducer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParent fetchParent,
boolean selected,
String resultVariable,
LockMode lockMode,
DomainResultCreationState creationState);
}

View File

@ -27,7 +27,7 @@ public class SubselectFetch {
private static final String FROM_STRING = " from ";
private final Set resultingEntityKeys;
private final Set<EntityKey> resultingEntityKeys;
private final String queryString;
private final String alias;
private final Loadable loadable;
@ -58,7 +58,7 @@ public class SubselectFetch {
final String alias,
final Loadable loadable,
final QueryParameters queryParameters,
final Set resultingEntityKeys,
final Set<EntityKey> resultingEntityKeys,
final Map namedParameterLocMap) {
this(
createSubselectFetchQueryFragment( queryParameters ),
@ -90,7 +90,7 @@ public class SubselectFetch {
final String alias,
final Loadable loadable,
final QueryParameters queryParameters,
final Set resultingEntityKeys,
final Set<EntityKey> resultingEntityKeys,
final Map namedParameterLocMap) {
this.resultingEntityKeys = resultingEntityKeys;
this.queryParameters = queryParameters;
@ -168,7 +168,7 @@ public class SubselectFetch {
/**
* Get the Set of EntityKeys
*/
public Set getResult() {
public Set<EntityKey> getResult() {
return resultingEntityKeys;
}

View File

@ -1047,10 +1047,12 @@ public abstract class Loader {
return false;
}
private static Set[] transpose(List keys) {
Set[] result = new Set[( (EntityKey[]) keys.get( 0 ) ).length];
private static Set<EntityKey>[] transpose(List<EntityKey[]> keys) {
//noinspection unchecked
final Set<EntityKey>[] result = new Set[ keys.get( 0 ).length ];
for ( int j = 0; j < result.length; j++ ) {
result[j] = new HashSet( keys.size() );
result[j] = new HashSet<>( keys.size() );
for ( Object key : keys ) {
result[j].add( ( (EntityKey[]) key )[j] );
}
@ -1061,7 +1063,7 @@ public abstract class Loader {
private void createSubselects(List keys, QueryParameters queryParameters, SharedSessionContractImplementor session) {
if ( keys.size() > 1 ) { //if we only returned one entity, query by key is more efficient
Set[] keySets = transpose( keys );
Set<EntityKey>[] keySets = transpose( keys );
Map namedParameterLocMap = buildNamedParameterLocMap( queryParameters );

View File

@ -0,0 +1,22 @@
/*
* 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.loader.internal;
import org.hibernate.loader.spi.Loadable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.sql.ast.tree.select.SelectStatement;
/**
* Common contract for SQL AST based loading
*
* @author Steve Ebersole
*/
public interface LoadPlan {
Loadable getLoadable();
ModelPart getRestrictivePart();
SelectStatement getSqlAst();
}

View File

@ -52,30 +52,26 @@ import org.jboss.logging.Logger;
public class MetamodelSelectBuilderProcess {
private static final Logger log = Logger.getLogger( MetamodelSelectBuilderProcess.class );
public interface SqlAstDescriptor {
SelectStatement getSqlAst();
List<JdbcParameter> getJdbcParameters();
}
@SuppressWarnings("WeakerAccess")
public static SqlAstDescriptor createSelect(
SessionFactoryImplementor sessionFactory,
public static SelectStatement createSelect(
Loadable loadable,
List<ModelPart> partsToSelect,
ModelPart restrictedPart,
DomainResult domainResult,
DomainResult cachedDomainResult,
int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions) {
LockOptions lockOptions,
Consumer<JdbcParameter> jdbcParameterConsumer,
SessionFactoryImplementor sessionFactory) {
final MetamodelSelectBuilderProcess process = new MetamodelSelectBuilderProcess(
sessionFactory,
loadable,
partsToSelect,
restrictedPart,
domainResult,
cachedDomainResult,
numberOfKeysToLoad,
loadQueryInfluencers,
lockOptions
lockOptions,
jdbcParameterConsumer
);
return process.execute();
@ -85,10 +81,11 @@ public class MetamodelSelectBuilderProcess {
private final Loadable loadable;
private final List<ModelPart> partsToSelect;
private final ModelPart restrictedPart;
private final DomainResult domainResult;
private final DomainResult cachedDomainResult;
private final int numberOfKeysToLoad;
private final LoadQueryInfluencers loadQueryInfluencers;
private final LockOptions lockOptions;
private final Consumer<JdbcParameter> jdbcParameterConsumer;
private MetamodelSelectBuilderProcess(
@ -96,21 +93,23 @@ public class MetamodelSelectBuilderProcess {
Loadable loadable,
List<ModelPart> partsToSelect,
ModelPart restrictedPart,
DomainResult domainResult,
DomainResult cachedDomainResult,
int numberOfKeysToLoad,
LoadQueryInfluencers loadQueryInfluencers,
LockOptions lockOptions) {
LockOptions lockOptions,
Consumer<JdbcParameter> jdbcParameterConsumer) {
this.creationContext = creationContext;
this.loadable = loadable;
this.partsToSelect = partsToSelect;
this.restrictedPart = restrictedPart;
this.domainResult = domainResult;
this.cachedDomainResult = cachedDomainResult;
this.numberOfKeysToLoad = numberOfKeysToLoad;
this.loadQueryInfluencers = loadQueryInfluencers;
this.lockOptions = lockOptions != null ? lockOptions : LockOptions.NONE;
this.jdbcParameterConsumer = jdbcParameterConsumer;
}
private SqlAstDescriptor execute() {
private SelectStatement execute() {
final QuerySpec rootQuerySpec = new QuerySpec( true );
final List<DomainResult> domainResults;
@ -123,7 +122,7 @@ public class MetamodelSelectBuilderProcess {
creationContext
);
final NavigablePath rootNavigablePath = new NavigablePath( loadable.getPathName() );
final NavigablePath rootNavigablePath = new NavigablePath( loadable.getRootPathName() );
final TableGroup rootTableGroup = loadable.createRootTableGroup(
rootNavigablePath,
@ -158,9 +157,9 @@ public class MetamodelSelectBuilderProcess {
// allows re-use as they can be re-used to save on memory - they
// do not share state between
final DomainResult domainResult;
if ( this.domainResult != null ) {
if ( this.cachedDomainResult != null ) {
// used the one passed to the constructor
domainResult = this.domainResult;
domainResult = this.cachedDomainResult;
}
else {
// create one
@ -179,22 +178,17 @@ public class MetamodelSelectBuilderProcess {
creationContext.getDomainModel().getTypeConfiguration()
);
final List<JdbcParameter> jdbcParameters = new ArrayList<>( numberOfKeyColumns * numberOfKeysToLoad );
applyKeyRestriction(
rootQuerySpec,
rootNavigablePath,
rootTableGroup,
restrictedPart,
numberOfKeyColumns,
jdbcParameters::add,
jdbcParameterConsumer,
sqlAstCreationState
);
return new SqlAstDescriptorImpl(
new SelectStatement( rootQuerySpec, domainResults ),
jdbcParameters
);
return new SelectStatement( rootQuerySpec, domainResults );
}
private void applyKeyRestriction(
@ -205,8 +199,6 @@ public class MetamodelSelectBuilderProcess {
int numberOfKeyColumns,
Consumer<JdbcParameter> jdbcParameterConsumer,
LoaderSqlAstCreationState sqlAstCreationState) {
final NavigablePath keyPath = rootNavigablePath.append( keyPart.getPartName() );
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
if ( numberOfKeyColumns == 1 ) {
@ -363,27 +355,5 @@ public class MetamodelSelectBuilderProcess {
return fetches;
}
static class SqlAstDescriptorImpl implements SqlAstDescriptor {
private final SelectStatement sqlAst;
private final List<JdbcParameter> jdbcParameters;
public SqlAstDescriptorImpl(
SelectStatement sqlAst,
List<JdbcParameter> jdbcParameters) {
this.sqlAst = sqlAst;
this.jdbcParameters = jdbcParameters;
}
@Override
public SelectStatement getSqlAst() {
return sqlAst;
}
@Override
public List<JdbcParameter> getJdbcParameters() {
return jdbcParameters;
}
}
}

View File

@ -0,0 +1,133 @@
/*
* 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.loader.internal;
import java.util.Iterator;
import java.util.List;
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.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.spi.CollectionLoader;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameter;
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
/**
* @author Steve Ebersole
*/
public class SingleCollectionKeyLoader implements CollectionLoader {
private final PluralAttributeMapping pluralAttributeMapping;
private final SelectStatement sqlAst;
private final List<JdbcParameter> jdbcParameters;
public SingleCollectionKeyLoader(
PluralAttributeMapping pluralAttributeMapping,
SelectStatement sqlAst, List<JdbcParameter> jdbcParameters) {
this.pluralAttributeMapping = pluralAttributeMapping;
this.sqlAst = sqlAst;
this.jdbcParameters = jdbcParameters;
}
@Override
public PluralAttributeMapping getLoadable() {
return pluralAttributeMapping;
}
@Override
public PersistentCollection load(Object key, SharedSessionContractImplementor session) {
final CollectionKey collectionKey = new CollectionKey( pluralAttributeMapping.getCollectionDescriptor(), key );
final SessionFactoryImplementor sessionFactory = session.getFactory();
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAst );
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(
pluralAttributeMapping.getKeyDescriptor().getJdbcTypeCount( sessionFactory.getTypeConfiguration() )
);
final Iterator<JdbcParameter> paramItr = jdbcParameters.iterator();
pluralAttributeMapping.getKeyDescriptor().visitJdbcValues(
key,
Clause.WHERE,
(value, type) -> {
assert paramItr.hasNext();
final JdbcParameter parameter = paramItr.next();
jdbcParameterBindings.addBinding(
parameter,
new JdbcParameterBinding() {
@Override
public JdbcMapping getBindType() {
return type;
}
@Override
public Object getBindValue() {
return value;
}
}
);
},
session
);
assert !paramItr.hasNext();
JdbcSelectExecutorStandardImpl.INSTANCE.list(
jdbcSelect,
jdbcParameterBindings,
new ExecutionContext() {
@Override
public SharedSessionContractImplementor getSession() {
return session;
}
@Override
public CollectionKey getCollectionKey() {
return collectionKey;
}
@Override
public QueryOptions getQueryOptions() {
return QueryOptions.NONE;
}
@Override
public QueryParameterBindings getQueryParameterBindings() {
return QueryParameterBindings.NO_PARAM_BINDINGS;
}
@Override
public Callback getCallback() {
return null;
}
},
RowTransformerPassThruImpl.instance()
);
return session.getPersistenceContext().getCollection( collectionKey );
}
}

View File

@ -0,0 +1,15 @@
/*
* 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.loader.internal;
/**
* Defines a plan for loading a single entity - by id, by uk, etc
*
* @author Steve Ebersole
*/
public interface SingleEntityLoadPlan extends LoadPlan {
}

View File

@ -6,7 +6,9 @@
*/
package org.hibernate.loader.internal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
@ -22,6 +24,7 @@ import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.spi.Callback;
@ -83,15 +86,19 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
log.debugf( "Batch loading entity [%s] : %s", getLoadable().getEntityName(), idsToLoad );
}
final MetamodelSelectBuilderProcess.SqlAstDescriptor sqlAstDescriptor = MetamodelSelectBuilderProcess.createSelect(
session.getFactory(),
final List<JdbcParameter> jdbcParameters = new ArrayList<>();
final SelectStatement sqlAst = MetamodelSelectBuilderProcess.createSelect(
getLoadable(),
// null here means to select everything
null,
getLoadable().getIdentifierMapping(),
null,
numberOfIds,
session.getLoadQueryInfluencers(),
lockOptions
lockOptions,
jdbcParameters::add,
session.getFactory()
);
final SessionFactoryImplementor sessionFactory = session.getFactory();
@ -99,14 +106,14 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAstDescriptor.getSqlAst() );
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAst );
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(
getLoadable().getIdentifierMapping().getJdbcTypeCount( sessionFactory.getTypeConfiguration() )
);
for ( int i = 0; i < numberOfIds; i++ ) {
final Iterator<JdbcParameter> paramItr = sqlAstDescriptor.getJdbcParameters().iterator();
final Iterator<JdbcParameter> paramItr = jdbcParameters.iterator();
getLoadable().getIdentifierMapping().visitJdbcValues(
idsToLoad[i],

View File

@ -6,7 +6,9 @@
*/
package org.hibernate.loader.internal;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.hibernate.LockMode;
@ -16,7 +18,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.spi.InternalFetchProfile;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcParameter;
/**
* Standard implementation of SingleIdEntityLoader
@ -43,6 +46,7 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
@Override
public void prepare() {
// see `org.hibernate.persister.entity.AbstractEntityPersister#createLoaders`
// we should pre-load a few - maybe LockMode.NONE and LockMode.READ
}
@ -138,20 +142,26 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
LockOptions lockOptions,
LoadQueryInfluencers queryInfluencers,
SessionFactoryImplementor sessionFactory) {
final MetamodelSelectBuilderProcess.SqlAstDescriptor sqlAstDescriptor = MetamodelSelectBuilderProcess.createSelect(
sessionFactory,
final List<JdbcParameter> jdbcParameters = new ArrayList<>();
final SelectStatement sqlAst = MetamodelSelectBuilderProcess.createSelect(
getLoadable(),
// null here means to select everything
null,
getLoadable().getIdentifierMapping(),
null,
1,
queryInfluencers,
lockOptions
lockOptions,
jdbcParameters::add,
sessionFactory
);
return new SingleIdLoadPlan<>(
getLoadable().getIdentifierMapping(),
sqlAstDescriptor
sqlAst,
jdbcParameters
);
}
}

View File

@ -14,12 +14,14 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.spi.Loadable;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.spi.Callback;
@ -31,17 +33,41 @@ import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
/**
* todo (6.0) : this can generically define a load-by-uk as well. only the SQL AST and `restrictivePart` vary and they are passed as ctor args
*
* Describes a plan for loading an entity by identifier.
*
* @implNote Made up of (1) a SQL AST for the SQL SELECT and (2) the `ModelPart` used as the restriction
*
* @author Steve Ebersole
*/
class SingleIdLoadPlan<T> {
class SingleIdLoadPlan<T> implements SingleEntityLoadPlan {
private final ModelPart restrictivePart;
private final MetamodelSelectBuilderProcess.SqlAstDescriptor sqlAstDescriptor;
private final SelectStatement sqlAst;
private final List<JdbcParameter> jdbcParameters;
public SingleIdLoadPlan(
ModelPart restrictivePart,
MetamodelSelectBuilderProcess.SqlAstDescriptor sqlAstDescriptor) {
SelectStatement sqlAst,
List<JdbcParameter> jdbcParameters) {
this.restrictivePart = restrictivePart;
this.sqlAstDescriptor = sqlAstDescriptor;
this.sqlAst = sqlAst;
this.jdbcParameters = jdbcParameters;
}
@Override
public Loadable getLoadable() {
return null;
}
@Override
public ModelPart getRestrictivePart() {
return restrictivePart;
}
@Override
public SelectStatement getSqlAst() {
return sqlAst;
}
T load(Object restrictedValue, LockOptions lockOptions, SharedSessionContractImplementor session) {
@ -50,13 +76,13 @@ class SingleIdLoadPlan<T> {
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAstDescriptor.getSqlAst() );
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAst );
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(
restrictivePart.getJdbcTypeCount( sessionFactory.getTypeConfiguration() )
);
final Iterator<JdbcParameter> paramItr = sqlAstDescriptor.getJdbcParameters().iterator();
final Iterator<JdbcParameter> paramItr = jdbcParameters.iterator();
restrictivePart.visitJdbcValues(
restrictedValue,

View File

@ -0,0 +1,154 @@
/*
* 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.loader.internal;
import java.util.ArrayList;
import java.util.Iterator;
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.CollectionKey;
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.loader.spi.CollectionLoader;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameter;
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.spi.DomainResult;
/**
* A one-time use CollectionLoader for applying a sub-select fetch
*
* @author Steve Ebersole
*/
public class SubSelectFetchCollectionLoader implements CollectionLoader {
private final PluralAttributeMapping attributeMapping;
private final DomainResult cachedDomainResult;
private final SubselectFetch subselect;
private final SelectStatement sqlAst;
private final java.util.List<JdbcParameter> jdbcParameters;
public SubSelectFetchCollectionLoader(
PluralAttributeMapping attributeMapping,
DomainResult cachedDomainResult,
SubselectFetch subselect,
SharedSessionContractImplementor session) {
this.attributeMapping = attributeMapping;
this.cachedDomainResult = cachedDomainResult;
this.subselect = subselect;
jdbcParameters = new ArrayList<>();
sqlAst = MetamodelSelectBuilderProcess.createSelect(
attributeMapping,
null,
attributeMapping.getKeyDescriptor(),
null,
subselect.getResult().size(),
session.getLoadQueryInfluencers(),
LockOptions.READ,
jdbcParameters::add,
session.getFactory()
);
}
@Override
public PluralAttributeMapping getLoadable() {
return attributeMapping;
}
@Override
public PersistentCollection load(Object triggerKey, SharedSessionContractImplementor session) {
final SessionFactoryImplementor sessionFactory = session.getFactory();
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();
final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory ).translate( sqlAst );
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl(
attributeMapping.getKeyDescriptor().getJdbcTypeCount( sessionFactory.getTypeConfiguration() )
);
for ( EntityKey key : subselect.getResult() ) {
final Iterator<JdbcParameter> paramItr = jdbcParameters.iterator();
attributeMapping.getKeyDescriptor().visitJdbcValues(
key.getIdentifierValue(),
Clause.WHERE,
(value, type) -> {
assert paramItr.hasNext();
final JdbcParameter parameter = paramItr.next();
jdbcParameterBindings.addBinding(
parameter,
new JdbcParameterBinding() {
@Override
public JdbcMapping getBindType() {
return type;
}
@Override
public Object getBindValue() {
return value;
}
}
);
},
session
);
assert !paramItr.hasNext();
}
JdbcSelectExecutorStandardImpl.INSTANCE.list(
jdbcSelect,
jdbcParameterBindings,
new ExecutionContext() {
@Override
public SharedSessionContractImplementor getSession() {
return session;
}
@Override
public QueryOptions getQueryOptions() {
return QueryOptions.NONE;
}
@Override
public QueryParameterBindings getQueryParameterBindings() {
return QueryParameterBindings.NO_PARAM_BINDINGS;
}
@Override
public Callback getCallback() {
return null;
}
},
RowTransformerPassThruImpl.instance()
);
final CollectionKey collectionKey = new CollectionKey( attributeMapping.getCollectionDescriptor(), triggerKey );
return session.getPersistenceContext().getCollection( collectionKey );
}
}

View File

@ -176,126 +176,4 @@ public class ResultSetProcessorImpl implements ResultSetProcessor {
}
}
// private class LocalVisitationStrategy extends LoadPlanVisitationStrategyAdapter {
// private boolean hadSubselectFetches = false;
//
// @Override
// public void startingEntityFetch(EntityFetch entityFetch) {
// // only collections are currently supported for subselect fetching.
// // hadSubselectFetches = hadSubselectFetches
// // || entityFetch.getFetchStrategy().getStyle() == FetchStyle.SUBSELECT;
// }
//
// @Override
// public void startingCollectionFetch(CollectionFetch collectionFetch) {
// hadSubselectFetches = hadSubselectFetches
// || collectionFetch.getFetchStrategy().getStyle() == FetchStyle.SUBSELECT;
// }
// }
//
// private class MixedReturnRowReader extends AbstractRowReader implements RowReader {
// private final List<ReturnReader> returnReaders;
// private List<EntityReferenceReader> entityReferenceReaders = new ArrayList<EntityReferenceReader>();
// private List<CollectionReferenceReader> collectionReferenceReaders = new ArrayList<CollectionReferenceReader>();
//
// private final int numberOfReturns;
//
// public MixedReturnRowReader(LoadPlan loadPlan) {
// LoadPlanVisitor.visit(
// loadPlan,
// new LoadPlanVisitationStrategyAdapter() {
// @Override
// public void startingEntityFetch(EntityFetch entityFetch) {
// entityReferenceReaders.add( new EntityReferenceReader( entityFetch ) );
// }
//
// @Override
// public void startingCollectionFetch(CollectionFetch collectionFetch) {
// collectionReferenceReaders.add( new CollectionReferenceReader( collectionFetch ) );
// }
// }
// );
//
// final List<ReturnReader> readers = new ArrayList<ReturnReader>();
//
// for ( Return rtn : loadPlan.getReturns() ) {
// final ReturnReader returnReader = buildReturnReader( rtn );
// if ( EntityReferenceReader.class.isInstance( returnReader ) ) {
// entityReferenceReaders.add( (EntityReferenceReader) returnReader );
// }
// readers.add( returnReader );
// }
//
// this.returnReaders = readers;
// this.numberOfReturns = readers.size();
// }
//
// @Override
// protected List<EntityReferenceReader> getEntityReferenceReaders() {
// return entityReferenceReaders;
// }
//
// @Override
// protected List<CollectionReferenceReader> getCollectionReferenceReaders() {
// return collectionReferenceReaders;
// }
//
// @Override
// protected Object readLogicalRow(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException {
// Object[] logicalRow = new Object[ numberOfReturns ];
// int pos = 0;
// for ( ReturnReader reader : returnReaders ) {
// logicalRow[pos] = reader.read( resultSet, context );
// pos++;
// }
// return logicalRow;
// }
// }
//
// private class CollectionInitializerRowReader extends AbstractRowReader implements RowReader {
// private final CollectionReturnReader returnReader;
//
// private List<EntityReferenceReader> entityReferenceReaders = null;
// private final List<CollectionReferenceReader> collectionReferenceReaders = new ArrayList<CollectionReferenceReader>();
//
// public CollectionInitializerRowReader(LoadPlan loadPlan) {
// returnReader = (CollectionReturnReader) buildReturnReader( loadPlan.getReturns().get( 0 ) );
//
// LoadPlanVisitor.visit(
// loadPlan,
// new LoadPlanVisitationStrategyAdapter() {
// @Override
// public void startingEntityFetch(EntityFetch entityFetch) {
// if ( entityReferenceReaders == null ) {
// entityReferenceReaders = new ArrayList<EntityReferenceReader>();
// }
// entityReferenceReaders.add( new EntityReferenceReader( entityFetch ) );
// }
//
// @Override
// public void startingCollectionFetch(CollectionFetch collectionFetch) {
// collectionReferenceReaders.add( new CollectionReferenceReader( collectionFetch ) );
// }
// }
// );
//
// collectionReferenceReaders.add( returnReader );
// }
//
// @Override
// protected List<EntityReferenceReader> getEntityReferenceReaders() {
// return entityReferenceReaders;
// }
//
// @Override
// protected List<CollectionReferenceReader> getCollectionReferenceReaders() {
// return collectionReferenceReaders;
// }
//
// @Override
// protected Object readLogicalRow(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException {
// return returnReader.read( resultSet, context );
// }
// }
}

View File

@ -0,0 +1,26 @@
/*
* 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.loader.spi;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
/**
* A loader (initialization) for collections
*
* @author Steve Ebersole
*/
public interface CollectionLoader extends Loader {
@Override
PluralAttributeMapping getLoadable();
/**
* Load a collection by its key (not necessarily the same as its owner's PK).
*/
PersistentCollection load(Object key, SharedSessionContractImplementor session);
}

View File

@ -36,7 +36,7 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers);
boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers);
String getPathName();
String getRootPathName();
@Override
default TableGroup createRootTableGroup(

View File

@ -9,7 +9,6 @@ package org.hibernate.loader.spi;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.persister.entity.EntityPersister;
/**
* Loader for loading a single entity by primary or unique key

View File

@ -7,19 +7,11 @@
package org.hibernate.metamodel.mapping;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
/**
* Descriptor for the collection identifier. Only used with {@link CollectionClassification#IDBAG} collections
*
* @author Steve Ebersole
*/
public interface CollectionIdentifierDescriptor {
DomainResult createDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState);
public interface CollectionIdentifierDescriptor extends CollectionPart, BasicValuedModelPart {
}

View File

@ -14,7 +14,8 @@ import org.hibernate.sql.results.spi.Fetchable;
public interface CollectionPart extends ModelPart, Fetchable {
enum Nature {
ELEMENT( "{element}" ),
INDEX( "{index}" );
INDEX( "{index}" ),
ID( "{collection-id}" );
private final String name;
@ -27,11 +28,22 @@ public interface CollectionPart extends ModelPart, Fetchable {
}
public static Nature fromName(String name) {
if ( ELEMENT.name.equals( name ) ) {
if ( "key".equals( name ) || "{key}".equals( name )
|| "keys".equals( name ) || "{keys}".equals( name )
|| "index".equals( name ) || "{index}".equals( name )
|| "indices".equals( name ) || "{indices}".equals( name ) ) {
return INDEX;
}
if ( "element".equals( name ) || "{element}".equals( name )
|| "elements".equals( name ) || "{elements}".equals( name )
|| "value".equals( name ) || "{value}".equals( name )
|| "values".equals( name ) || "{values}".equals( name ) ) {
return ELEMENT;
}
else if ( INDEX.name.equals( name ) ) {
return INDEX;
if ( ID.name.equals( name ) ) {
return ID;
}
throw new IllegalArgumentException(

View File

@ -55,7 +55,7 @@ public interface EntityMappingType extends ManagedMappingType, Loadable {
}
@Override
default String getPathName() {
default String getRootPathName() {
return getEntityName();
}

View File

@ -11,6 +11,7 @@ import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
@ -30,6 +31,13 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
Predicate generateJoinPredicate(
TableReference lhs,
TableReference rhs,
JoinType joinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
@Override
default String getPartName() {
return PART_NAME;

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping;
import java.util.function.Consumer;
import org.hibernate.loader.spi.Loadable;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.results.spi.Fetchable;
@ -17,7 +18,7 @@ import org.hibernate.sql.results.spi.FetchableContainer;
* @author Steve Ebersole
*/
public interface PluralAttributeMapping
extends AttributeMapping, StateArrayContributorMapping, TableGroupJoinProducer, FetchableContainer {
extends AttributeMapping, StateArrayContributorMapping, TableGroupJoinProducer, FetchableContainer, Loadable {
CollectionPersister getCollectionDescriptor();
@ -25,6 +26,13 @@ public interface PluralAttributeMapping
CollectionPart getIndexDescriptor();
interface IndexMetadata {
CollectionPart getIndexDescriptor();
int getListIndexBase();
}
IndexMetadata getIndexMetadata();
CollectionPart getElementDescriptor();
CollectionIdentifierDescriptor getIdentifierDescriptor();

View File

@ -9,6 +9,5 @@ package org.hibernate.metamodel.mapping;
/**
* @author Steve Ebersole
*/
public interface SingularAttributeMapping
extends AttributeMapping, StateArrayContributorMapping {
public interface SingularAttributeMapping extends AttributeMapping, StateArrayContributorMapping {
}

View File

@ -171,10 +171,10 @@ public class BasicValuedCollectionPart implements CollectionPart, BasicValuedMod
nature.getName()
);
final SqlSelection sqlSelection = resolveSqlSelection(
creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup( fetchablePath.getParent() ),
creationState
);
final TableGroup tableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.findTableGroup( fetchablePath.getParent() );
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
return new BasicFetch(
sqlSelection.getValuesArrayPosition(),

View File

@ -6,45 +6,152 @@
*/
package org.hibernate.metamodel.mapping.internal;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierDescriptor {
private final CollectionPersister collectionDescriptor;
private final String containingTableName;
private final String columnName;
private final BasicType type;
public CollectionIdentifierDescriptorImpl(
CollectionPersister collectionDescriptor,
String containingTableName,
String columnName,
BasicType type) {
this.collectionDescriptor = collectionDescriptor;
this.containingTableName = containingTableName;
this.columnName = columnName;
this.type = type;
}
@Override
public Nature getNature() {
return Nature.ID;
}
@Override
public String getContainingTableExpression() {
return containingTableName;
}
@Override
public String getMappedColumnExpression() {
return columnName;
}
@Override
public BasicValueConverter getConverter() {
return null;
}
@Override
public MappingType getPartTypeDescriptor() {
return type;
}
@Override
public JdbcMapping getJdbcMapping() {
return type;
}
@Override
public MappingType getMappedTypeDescriptor() {
return type;
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override
public String getFetchableName() {
return null;
}
@Override
public FetchStrategy getMappedFetchStrategy() {
return null;
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
final TableGroup tableGroup = fromClauseAccess.getTableGroup( fetchablePath );
final SqlAstCreationState astCreationState = creationState.getSqlAstCreationState();
final SqlAstCreationContext astCreationContext = astCreationState.getCreationContext();
final SessionFactoryImplementor sessionFactory = astCreationContext.getSessionFactory();
final SqlExpressionResolver sqlExpressionResolver = astCreationState.getSqlExpressionResolver();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
columnName
),
p -> new ColumnReference(
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
columnName,
type,
sessionFactory
)
),
type.getJavaTypeDescriptor(),
sessionFactory.getTypeConfiguration()
);
return new BasicFetch<>(
sqlSelection.getValuesArrayPosition(),
fetchParent,
fetchablePath,
this,
! selected,
getConverter(),
FetchTiming.IMMEDIATE,
creationState
);
}
public DomainResult createDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
final SqlAstCreationState astCreationState = creationState.getSqlAstCreationState();
final SqlAstCreationContext astCreationContext = astCreationState.getCreationContext();
final SessionFactoryImplementor sessionFactory = astCreationContext.getSessionFactory();

View File

@ -14,6 +14,10 @@ import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.domain.collection.EntityCollectionPartTableGroup;
import org.hibernate.sql.results.internal.domain.entity.EntityFetch;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
@ -71,6 +75,32 @@ public class EntityCollectionPart implements CollectionPart, EntityValuedModelPa
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
fetchablePath,
np -> {
final TableGroup collectionTableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( fetchablePath.getParent() );
return new EntityCollectionPartTableGroup( fetchablePath, collectionTableGroup, this );
}
);
return new EntityFetch( fetchParent, this, lockMode, selected, fetchablePath, creationState );
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}

View File

@ -763,6 +763,7 @@ public class MappingModelCreationHelper {
identifierDescriptor = new CollectionIdentifierDescriptorImpl(
collectionDescriptor,
tableExpression,
identifierColumnName,
(BasicType) loadableCollection.getIdentifierType()
);

View File

@ -7,12 +7,15 @@
package org.hibernate.metamodel.mapping.internal;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.List;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionMappingType;
import org.hibernate.metamodel.mapping.CollectionPart;
@ -26,20 +29,22 @@ import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.internal.domain.collection.CollectionDomainResult;
import org.hibernate.sql.results.internal.domain.collection.DelayedCollectionFetch;
import org.hibernate.sql.results.internal.domain.collection.EagerCollectionFetch;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
@ -48,6 +53,10 @@ import org.hibernate.sql.results.spi.FetchParent;
* @author Steve Ebersole
*/
public class PluralAttributeMappingImpl extends AbstractAttributeMapping implements PluralAttributeMapping {
public interface Aware {
void injectAttributeMapping(PluralAttributeMapping attributeMapping);
}
private final int stateArrayPosition;
private final PropertyAccess propertyAccess;
private final StateArrayContributorMetadataAccess stateArrayContributorMetadataAccess;
@ -65,6 +74,8 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
private final String sqlAliasStem;
private final IndexMetadata indexMetadata;
@SuppressWarnings("WeakerAccess")
public PluralAttributeMappingImpl(
String attributeName,
@ -101,6 +112,33 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
else {
separateCollectionTable = ( (Joinable) collectionDescriptor ).getTableName();
}
indexMetadata = new IndexMetadata() {
final int baseIndex;
{
if ( bootDescriptor instanceof List ) {
baseIndex = ( (List) bootDescriptor ).getBaseIndex();
}
else {
baseIndex = -1;
}
}
@Override
public CollectionPart getIndexDescriptor() {
return indexDescriptor;
}
@Override
public int getListIndexBase() {
return baseIndex;
}
};
if ( collectionDescriptor instanceof Aware ) {
( (Aware) collectionDescriptor ).injectAttributeMapping( this );
}
}
@Override
@ -128,6 +166,11 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
return indexDescriptor;
}
@Override
public IndexMetadata getIndexMetadata() {
return indexMetadata;
}
@Override
public CollectionIdentifierDescriptor getIdentifierDescriptor() {
return identifierDescriptor;
@ -163,6 +206,22 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
return fetchStrategy;
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
final TableGroup collectionTableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( navigablePath );
assert collectionTableGroup != null;
//noinspection unchecked
return new CollectionDomainResult( navigablePath, this, resultVariable, tableGroup, creationState );
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
@ -201,7 +260,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
return new EagerCollectionFetch(
fetchablePath,
this,
fkDescriptor.createDomainResult( fetchablePath, collectionTableGroup, creationState ),
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
fetchParent,
creationState
@ -280,6 +338,57 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
getCollectionDescriptor().applyTableReferences( sqlAliasBase, baseJoinType, collector, sqlExpressionResolver, creationContext );
}
@Override
public TableGroup createRootTableGroup(
NavigablePath navigablePath,
String explicitSourceAlias,
JoinType tableReferenceJoinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
final TableGroupBuilder tableGroupBuilder = TableGroupBuilder.builder(
navigablePath,
this,
lockMode,
sqlAliasBase,
creationContext.getSessionFactory()
);
applyTableReferences(
sqlAliasBase,
tableReferenceJoinType,
tableGroupBuilder,
sqlExpressionResolver,
creationContext
);
return tableGroupBuilder.build();
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
return getCollectionDescriptor().isAffectedByEnabledFilters( influencers );
}
@Override
public boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers) {
return getCollectionDescriptor().isAffectedByEntityGraph( influencers );
}
@Override
public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers) {
return getCollectionDescriptor().isAffectedByEnabledFetchProfiles( influencers );
}
@Override
public String getRootPathName() {
return getCollectionDescriptor().getRole();
}
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
final CollectionPart.Nature nature = CollectionPart.Nature.fromName( name );
@ -289,6 +398,9 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
else if ( nature == CollectionPart.Nature.INDEX ) {
return indexDescriptor;
}
else if ( nature == CollectionPart.Nature.ID ) {
return identifierDescriptor;
}
return null;
}

View File

@ -10,10 +10,16 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.ColumnConsumer;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.Clause;
@ -31,6 +37,8 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -38,7 +46,7 @@ import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
*/
public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicValuedModelPart {
private final String keyColumnContainingTable;
private final String keyColumnExpression;
private final String targetColumnContainingTable;
@ -97,6 +105,51 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
);
}
@Override
public Predicate generateJoinPredicate(
TableReference lhs,
TableReference rhs,
JoinType joinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
if ( lhs.getTableExpression().equals( keyColumnContainingTable ) ) {
assert rhs.getTableExpression().equals( targetColumnContainingTable );
return new ComparisonPredicate(
new ColumnReference(
lhs,
keyColumnExpression,
jdbcMapping,
creationContext.getSessionFactory()
),
ComparisonOperator.EQUAL,
new ColumnReference(
rhs,
targetColumnExpression,
jdbcMapping,
creationContext.getSessionFactory()
)
);
}
else {
assert rhs.getTableExpression().equals( keyColumnContainingTable );
return new ComparisonPredicate(
new ColumnReference(
lhs,
targetColumnExpression,
jdbcMapping,
creationContext.getSessionFactory()
),
ComparisonOperator.EQUAL,
new ColumnReference(
rhs,
keyColumnExpression,
jdbcMapping,
creationContext.getSessionFactory()
)
);
}
}
@Override
public Predicate generateJoinPredicate(
TableGroup lhs,
@ -252,4 +305,52 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
SharedSessionContractImplementor session) {
valuesConsumer.consume( value, jdbcMapping );
}
@Override
public String getContainingTableExpression() {
return keyColumnContainingTable;
}
@Override
public String getMappedColumnExpression() {
return keyColumnExpression;
}
@Override
public BasicValueConverter getConverter() {
return null;
}
@Override
public String getFetchableName() {
return PART_NAME;
}
@Override
public FetchStrategy getMappedFetchStrategy() {
return FetchStrategy.IMMEDIATE_JOIN;
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
return null;
}
@Override
public MappingType getMappedTypeDescriptor() {
return null;
}
@Override
public JdbcMapping getJdbcMapping() {
return jdbcMapping;
}
}

View File

@ -10,6 +10,7 @@ import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
@ -21,6 +22,7 @@ import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode;
import org.hibernate.Filter;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.QueryException;
@ -39,6 +41,9 @@ import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
@ -56,6 +61,10 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.loader.internal.MetamodelSelectBuilderProcess;
import org.hibernate.loader.internal.SingleCollectionKeyLoader;
import org.hibernate.loader.internal.SubSelectFetchCollectionLoader;
import org.hibernate.loader.spi.CollectionLoader;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
@ -67,6 +76,11 @@ import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.PluralAttributeMappingImpl;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
@ -85,6 +99,7 @@ import org.hibernate.persister.walking.spi.CompositeCollectionElementDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.Alias;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.SimpleSelect;
@ -93,8 +108,16 @@ import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcParameter;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.type.AnyType;
import org.hibernate.type.AssociationType;
import org.hibernate.type.BasicType;
@ -113,7 +136,7 @@ import org.jboss.logging.Logger;
* @see OneToManyPersister
*/
public abstract class AbstractCollectionPersister
implements CollectionMetadata, SQLLoadableCollection {
implements CollectionMetadata, SQLLoadableCollection, PluralAttributeMappingImpl.Aware {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class,
AbstractCollectionPersister.class.getName() );
@ -765,9 +788,92 @@ public abstract class AbstractCollectionPersister
}
}
private CollectionLoader standardCollectionLoader;
@Override
public void initialize(Object key, SharedSessionContractImplementor session) throws HibernateException {
getAppropriateInitializer( key, session ).initialize( key, session );
// getAppropriateInitializer( key, session ).initialize( key, session );
determineLoaderToUse( key, session ).load( key, session );
}
protected CollectionLoader getStandardCollectionLoader() {
CollectionLoader localCopy = standardCollectionLoader;
if ( localCopy == null ) {
synchronized (this) {
if ( localCopy == null ) {
localCopy = createCollectionLoader( LoadQueryInfluencers.NONE );
standardCollectionLoader = localCopy;
}
}
}
return localCopy;
}
protected CollectionLoader determineLoaderToUse(Object key, SharedSessionContractImplementor session) {
if ( queryLoaderName != null ) {
// if there is a user-specified loader, return that
return getStandardCollectionLoader();
}
final CollectionLoader subSelectLoader = resolveSubSelectLoader( key, session );
if ( subSelectLoader != null ) {
return subSelectLoader;
}
if ( ! session.getLoadQueryInfluencers().hasEnabledFilters() ) {
return getStandardCollectionLoader();
}
return createCollectionLoader( session.getLoadQueryInfluencers() );
}
private CollectionLoader resolveSubSelectLoader(Object key, SharedSessionContractImplementor session) {
if ( !isSubselectLoadable() ) {
return null;
}
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityKey ownerEntityKey = session.generateEntityKey( key, getOwnerEntityPersister() );
final SubselectFetch subselect = persistenceContext.getBatchFetchQueue().getSubselect( ownerEntityKey );
if ( subselect == null ) {
return null;
}
// Take care of any entities that might have
// been evicted!
subselect.getResult().removeIf( o -> !persistenceContext.containsEntity( o ) );
// Run a subquery loader
return createSubSelectLoader( subselect, session );
}
protected CollectionLoader createSubSelectLoader(SubselectFetch subselect, SharedSessionContractImplementor session) {
//noinspection RedundantCast
return new SubSelectFetchCollectionLoader(
attributeMapping,
(DomainResult) null,
subselect,
session
);
}
protected CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
final java.util.List<JdbcParameter> jdbcParameters = new ArrayList<>();
final SelectStatement sqlAst = MetamodelSelectBuilderProcess.createSelect(
attributeMapping,
null,
attributeMapping.getKeyDescriptor(),
null,
1,
loadQueryInfluencers,
LockOptions.READ,
jdbcParameters::add,
getFactory()
);
return new SingleCollectionKeyLoader( attributeMapping, sqlAst, jdbcParameters );
}
protected CollectionInitializer getAppropriateInitializer(Object key, SharedSessionContractImplementor session) {
@ -1995,9 +2101,7 @@ public abstract class AbstractCollectionPersister
@Override
public boolean isAffectedByEnabledFilters(SharedSessionContractImplementor session) {
final Map<String, Filter> enabledFilters = session.getLoadQueryInfluencers().getEnabledFilters();
return filterHelper.isAffectedBy( enabledFilters ) ||
( isManyToMany() && manyToManyFilterHelper.isAffectedBy( enabledFilters ) );
return isAffectedByEnabledFilters( session.getLoadQueryInfluencers() );
}
public boolean isSubselectLoadable() {
@ -2382,6 +2486,47 @@ public abstract class AbstractCollectionPersister
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// "mapping model"
// todo (6.0) : atm there is no way to get a `PluralAttributeMapping` reference except through its declaring `ManagedTypeMapping` attributes. this is a backhand way
// of getting access to it for use from the persister
private PluralAttributeMapping attributeMapping;
@Override
public void injectAttributeMapping(PluralAttributeMapping attributeMapping) {
this.attributeMapping = attributeMapping;
}
@Override
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
if ( influencers.hasEnabledFilters() ) {
final Map<String, Filter> enabledFilters = influencers.getEnabledFilters();
return filterHelper.isAffectedBy( enabledFilters ) ||
( isManyToMany() && manyToManyFilterHelper.isAffectedBy( enabledFilters ) );
}
return false;
}
@Override
public boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers) {
// todo (6.0) : anything to do here?
return false;
}
@Override
public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers) {
if ( influencers.hasEnabledFetchProfiles() ) {
for ( String enabledFetchProfileName : influencers.getEnabledFetchProfileNames() ) {
final FetchProfile fetchProfile = getFactory().getFetchProfile( enabledFetchProfileName );
final Fetch fetchByRole = fetchProfile.getFetchByRole( getRole() );
if ( fetchByRole.getStyle() == Fetch.Style.JOIN ) {
return true;
}
}
}
return false;
}
@Override
public void applyTableReferences(
@ -2413,6 +2558,16 @@ public abstract class AbstractCollectionPersister
}
if ( elementPersister != null ) {
collector.applyPrimaryJoinProducer(
(lhs, rhs) -> new TableReferenceJoin(
baseJoinType,
rhs,
generateEntityElementJoinPredicate(
lhs, rhs, baseJoinType, sqlExpressionResolver, creationContext
)
)
);
elementPersister.applyTableReferences(
sqlAliasBase,
// todo (6.0) : determine the proper join-type to use
@ -2425,6 +2580,100 @@ public abstract class AbstractCollectionPersister
}
private Predicate generateEntityElementJoinPredicate(
TableReference lhs,
TableReference rhs,
JoinType baseJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
// `lhs` should be the collection table
// `rhs` should be the primary element table
assert lhs.getTableExpression().equals( getTableName() );
final String fkTargetModelPartName = getCollectionType().getRHSUniqueKeyPropertyName();
final ModelPart fkTargetDescriptor;
if ( fkTargetModelPartName != null ) {
fkTargetDescriptor = elementPersister.findSubPart( fkTargetModelPartName );
}
else {
fkTargetDescriptor = elementPersister.getIdentifierMapping();
}
final int jdbcTypeCount = fkTargetDescriptor.getJdbcTypeCount( sessionFactory.getTypeConfiguration() );
assert jdbcTypeCount == elementColumnNames.length;
if ( jdbcTypeCount == 1 ) {
final BasicValuedModelPart fkModelPartType = (BasicValuedModelPart) fkTargetDescriptor;
return new ComparisonPredicate(
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( lhs, elementColumnNames[0] ),
sqlAstProcessingState -> new ColumnReference(
lhs,
elementColumnNames[0],
fkModelPartType.getJdbcMapping(),
sessionFactory
)
),
ComparisonOperator.EQUAL,
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( rhs, elementColumnNames[0] ),
sqlAstProcessingState -> new ColumnReference(
rhs,
fkModelPartType.getMappedColumnExpression(),
fkModelPartType.getJdbcMapping(),
sessionFactory
)
)
);
}
else {
// todo (6.0) : tuple or disjunction?
// for now use a tuple - its easier to build, even though disjunction is more universally supported at DB level
final java.util.List<JdbcMapping> jdbcMappings = new ArrayList<>( jdbcTypeCount );
final SqlTuple.Builder comparisonRhsBuilder = new SqlTuple.Builder( fkTargetDescriptor, jdbcTypeCount );
fkTargetDescriptor.visitColumns(
(containingTableExpression, columnExpression, jdbcMapping) -> {
assert rhs.getTableExpression().equals( containingTableExpression );
jdbcMappings.add( jdbcMapping );
comparisonRhsBuilder.addSubExpression(
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( rhs, elementColumnNames[0] ),
sqlAstProcessingState -> new ColumnReference(
rhs,
columnExpression,
jdbcMapping,
sessionFactory
)
)
);
}
);
final SqlTuple comparisonRhs = comparisonRhsBuilder.buildTuple();
final SqlTuple.Builder comparisonLhsBuilder = new SqlTuple.Builder( fkTargetDescriptor, jdbcTypeCount );
for ( int i = 0; i < elementColumnNames.length; i++ ) {
final String lhsColumnName = elementColumnNames[i];
final JdbcMapping jdbcMapping = jdbcMappings.get( i );
comparisonLhsBuilder.addSubExpression(
sqlExpressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( lhs, elementColumnNames[0] ),
sqlAstProcessingState -> new ColumnReference(
lhs,
lhsColumnName,
jdbcMapping,
sessionFactory
)
)
);
}
final SqlTuple comparisionLhs = comparisonLhsBuilder.buildTuple();
return new ComparisonPredicate( comparisionLhs, ComparisonOperator.EQUAL, comparisonRhs );
}
}
@Override
public CollectionSemantics getCollectionSemantics() {
return collectionSemantics;

View File

@ -11,6 +11,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Comparator;
import java.util.Map;
import java.util.function.Consumer;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
@ -19,23 +20,28 @@ import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.entry.CacheEntryStructure;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.ast.tree.from.TableReferenceContributor;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* A strategy for persisting a collection role. Defines a contract between
@ -72,6 +78,8 @@ import org.hibernate.type.Type;
* @author Gavin King
*/
public interface CollectionPersister extends CollectionDefinition, TableReferenceContributor {
NavigableRole getNavigableRole();
/**
* Initialize the given collection with the given key
*/
@ -87,8 +95,6 @@ public interface CollectionPersister extends CollectionDefinition, TableReferenc
*/
CollectionDataAccess getCacheAccessStrategy();
NavigableRole getNavigableRole();
/**
* Get the cache structure
*/
@ -301,6 +307,18 @@ public interface CollectionPersister extends CollectionDefinition, TableReferenc
boolean isAffectedByEnabledFilters(SharedSessionContractImplementor session);
default boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}
default boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers) {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}
default boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers) {
throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
}
/**
* Generates the collection's key column aliases, based on the given
* suffix.

View File

@ -4552,15 +4552,14 @@ public abstract class AbstractEntityPersister
//Relational based Persisters should be content with this implementation
protected void createLoaders() {
// We load the entity loaders for the most common lock modes.
// create the entity loaders for the most common lock modes.
noneLockLoader = createEntityLoader( LockMode.NONE );
readLockLoader = createEntityLoader( LockMode.READ );
// The loaders for the other lock modes are lazily loaded and will later be stored in this map,
// unless this setting is disabled
if ( ! factory.getSessionFactoryOptions().isDelayBatchFetchLoaderCreationsEnabled() ) {
// see if the user enabled delaying creation of the remaining loaders
final boolean delayCreationsEnabled = factory.getSessionFactoryOptions().isDelayBatchFetchLoaderCreationsEnabled();
if ( ! delayCreationsEnabled ) {
// the setting is disabled -> do the creations
for ( LockMode lockMode : EnumSet.complementOf( EnumSet.of( LockMode.NONE, LockMode.READ, LockMode.WRITE ) ) ) {
loaders.put( lockMode, createEntityLoader( lockMode ) );
}
@ -4568,7 +4567,6 @@ public abstract class AbstractEntityPersister
// And finally, create the internal merge and refresh load plans
loaders.put(
"merge",
new CascadeEntityLoader( this, CascadingActions.MERGE, getFactory() )
@ -4715,7 +4713,11 @@ public abstract class AbstractEntityPersister
@Override
public boolean isAffectedByEntityGraph(LoadQueryInfluencers loadQueryInfluencers) {
return loadQueryInfluencers.getEffectiveEntityGraph().getGraph() != null;
if ( loadQueryInfluencers.getEffectiveEntityGraph().getGraph() == null ) {
return false;
}
return loadQueryInfluencers.getEffectiveEntityGraph().getGraph().appliesTo( getEntityName() );
}
@Override

View File

@ -11,6 +11,7 @@ import java.util.Collections;
import java.util.List;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.sql.ast.spi.SqlAstWalker;
/**
@ -48,6 +49,11 @@ public class SqlTuple implements Expression {
this.valueMapping = valueMapping;
}
public Builder(MappingModelExpressable valueMapping, int jdbcTypeCount) {
this( valueMapping );
expressions = new ArrayList<>( jdbcTypeCount );
}
public void addSubExpression(Expression expression) {
if ( expressions == null ) {
expressions = new ArrayList<>();

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.ast.tree.from;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.hibernate.LockMode;
@ -29,6 +30,16 @@ public class TableGroupBuilder implements TableReferenceCollector {
return new TableGroupBuilder( path, producer, lockMode, sqlAliasBase, sessionFactory );
}
public static TableGroupBuilder builder(
NavigablePath path,
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
BiFunction<TableReference, TableReference,TableReferenceJoin> primaryJoinProducer,
SessionFactoryImplementor sessionFactory) {
return new TableGroupBuilder( path, producer, lockMode, sqlAliasBase, primaryJoinProducer, sessionFactory );
}
private final NavigablePath path;
private final TableGroupProducer producer;
private final SessionFactoryImplementor sessionFactory;
@ -36,7 +47,7 @@ public class TableGroupBuilder implements TableReferenceCollector {
private final SqlAliasBase sqlAliasBase;
private final LockMode lockMode;
private final Function<TableReference,TableReferenceJoin> primaryJoinProducer;
private BiFunction<TableReference, TableReference,TableReferenceJoin> primaryJoinProducer;
private TableReference primaryTableReference;
private TableReference secondaryTableLhs;
@ -57,7 +68,7 @@ public class TableGroupBuilder implements TableReferenceCollector {
TableGroupProducer producer,
LockMode lockMode,
SqlAliasBase sqlAliasBase,
Function<TableReference,TableReferenceJoin> primaryJoinProducer,
BiFunction<TableReference, TableReference,TableReferenceJoin> primaryJoinProducer,
SessionFactoryImplementor sessionFactory) {
this.path = path;
this.producer = producer;
@ -67,6 +78,11 @@ public class TableGroupBuilder implements TableReferenceCollector {
this.sessionFactory = sessionFactory;
}
@Override
public void applyPrimaryJoinProducer(BiFunction<TableReference, TableReference, TableReferenceJoin> primaryJoinProducer) {
this.primaryJoinProducer = primaryJoinProducer;
}
public TableGroup build() {
if ( primaryTableReference == null ) {
throw new IllegalStateException( "Primary TableReference was not specified : " + path );
@ -87,9 +103,7 @@ public class TableGroupBuilder implements TableReferenceCollector {
public void applyPrimaryReference(TableReference tableReference) {
if ( primaryTableReference != null ) {
assert primaryJoinProducer != null;
addTableReferenceJoin( primaryJoinProducer.apply( tableReference ) );
addTableReferenceJoin( primaryJoinProducer.apply( primaryTableReference, tableReference ) );
}
else {
primaryTableReference = tableReference;

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.sql.ast.tree.from;
import java.util.function.BiFunction;
import org.hibernate.sql.ast.JoinType;
/**
@ -15,6 +17,8 @@ import org.hibernate.sql.ast.JoinType;
* @author Steve Ebersole
*/
public interface TableReferenceCollector {
void applyPrimaryJoinProducer(BiFunction<TableReference, TableReference, TableReferenceJoin> primaryJoinProducer);
void applyPrimaryReference(TableReference tableReference);
/**

View File

@ -22,7 +22,7 @@ public class TableReferenceJoin implements SqlAstNode {
private final Predicate predicate;
public TableReferenceJoin(JoinType joinType, TableReference joinedTableBinding, Predicate predicate) {
this.joinType = joinType;
this.joinType = joinType == null ? JoinType.LEFT : joinType;
this.joinedTableBinding = joinedTableBinding;
this.predicate = predicate;

View File

@ -38,7 +38,7 @@ public class LoadingCollectionEntryImpl implements LoadingCollectionEntry {
this.key = key;
this.collectionInstance = collectionInstance;
collectionInstance.beforeInitialize( getCollectionDescriptor(), -1 );
collectionInstance.beforeInitialize( collectionDescriptor, -1 );
collectionInstance.beginRead();
}

View File

@ -13,7 +13,6 @@ import org.hibernate.query.named.RowReaderMemento;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.EntityInitializer;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingState;

View File

@ -30,6 +30,7 @@ public abstract class AbstractFetchParent implements FetchParent {
public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) {
this.fetchContainer = fetchContainer;
this.navigablePath = navigablePath;
assert fetchContainer instanceof ManagedMappingType;
}
protected void afterInitialize(DomainResultCreationState creationState) {

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.results.internal.domain;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.collection.internal.PersistentArrayHolder;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.CollectionInitializer;
@ -44,6 +45,11 @@ public class ArrayInitializer implements CollectionInitializer {
this.navigablePath = navigablePath;
}
@Override
public PluralAttributeMapping getInitializedPart() {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public CollectionPersister getInitializingCollectionDescriptor() {
return arrayDescriptor;

View File

@ -0,0 +1,170 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* Base support for CollectionInitializer implementations
*
* @author Steve Ebersole
*/
public abstract class AbstractCollectionInitializer implements CollectionInitializer {
private final NavigablePath collectionPath;
private final PluralAttributeMapping collectionAttributeMapping;
private final FetchParentAccess parentAccess;
private final boolean selected;
/**
* refers to the collection's container value - which collection-key?
*/
private final DomainResultAssembler keyContainerAssembler;
/**
* refers to the rows entry in the collection. null indicates that the collection is empty
*/
private final DomainResultAssembler keyCollectionAssembler;
// per-row state
private Object keyContainerValue;
private Object keyCollectionValue;
private CollectionKey collectionKey;
@SuppressWarnings("WeakerAccess")
protected AbstractCollectionInitializer(
NavigablePath collectionPath,
PluralAttributeMapping collectionAttributeMapping,
FetchParentAccess parentAccess,
boolean selected,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler) {
this.collectionPath = collectionPath;
this.collectionAttributeMapping = collectionAttributeMapping;
this.parentAccess = parentAccess;
this.selected = selected;
this.keyContainerAssembler = keyContainerAssembler;
this.keyCollectionAssembler = keyCollectionAssembler;
}
@Override
public NavigablePath getNavigablePath() {
return collectionPath;
}
public PluralAttributeMapping getCollectionAttributeMapping() {
return collectionAttributeMapping;
}
@Override
public PluralAttributeMapping getInitializedPart() {
return getCollectionAttributeMapping();
}
/**
* Are the values for performing this initialization present in the current
* {@link org.hibernate.sql.results.spi.JdbcValuesSourceProcessingState}?
* Or should a separate/subsequent select be performed
*
* todo (6.0) : opportunity for performance gain by batching these selects triggered at the end of processing the JdbcValuesSource
*/
protected boolean isSelected() {
return selected;
}
protected FetchParentAccess getParentAccess() {
return parentAccess;
}
/**
* The value of the container/owner side of the collection key (FK). Identifies the
* owner of the collection
*/
@SuppressWarnings("WeakerAccess")
protected Object getKeyContainerValue() {
return keyContainerValue;
}
/**
* The value of the collection side of the collection key (FK). Identifies
* inclusion in the collection. Can be null to indicate that the current row
* does not contain any collection values
*/
@SuppressWarnings("WeakerAccess")
protected Object getKeyCollectionValue() {
return keyCollectionValue;
}
public CollectionKey resolveCollectionKey(RowProcessingState rowProcessingState) {
resolveKey( rowProcessingState );
return collectionKey;
}
@Override
public void resolveKey(RowProcessingState rowProcessingState) {
if ( collectionKey != null ) {
// already resolved
return;
}
final CollectionKey loadingKey = rowProcessingState.getCollectionKey();
if ( loadingKey != null ) {
collectionKey = loadingKey;
return;
}
keyContainerValue = keyContainerAssembler.assemble(
rowProcessingState,
rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
);
if ( keyCollectionAssembler == null || keyContainerAssembler == keyCollectionAssembler ) {
keyCollectionValue = keyContainerValue;
}
else {
keyCollectionValue = keyCollectionAssembler.assemble(
rowProcessingState,
rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
);
}
Object keyContainerValue = getKeyContainerValue();
if ( keyContainerValue != null ) {
this.collectionKey = new CollectionKey(
collectionAttributeMapping.getCollectionDescriptor(),
keyContainerValue
);
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Current row collection key : %s",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), this.collectionKey.getKey() )
);
}
}
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
keyContainerValue = null;
keyCollectionValue = null;
collectionKey = null;
}
}

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.CollectionResultNode;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public abstract class AbstractCollectionResultNode implements CollectionResultNode {
private final NavigablePath navigablePath;
private final PluralAttributeMapping attributeMapping;
private final String resultVariable;
@SuppressWarnings("WeakerAccess")
protected AbstractCollectionResultNode(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
String resultVariable) {
this.navigablePath = navigablePath;
this.attributeMapping = attributeMapping;
this.resultVariable = resultVariable;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@SuppressWarnings("WeakerAccess")
protected PluralAttributeMapping getAttributeMapping() {
return attributeMapping;
}
@Override
public JavaTypeDescriptor getResultJavaTypeDescriptor() {
return attributeMapping.getJavaTypeDescriptor();
}
public String getResultVariable() {
return resultVariable;
}
}

View File

@ -0,0 +1,314 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.results.internal.LoadingCollectionEntryImpl;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.LoadingCollectionEntry;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* Base support for CollectionInitializer implementations that represent
* an immediate initialization of some sort (join, select, batch, sub-select)
* for a persistent collection.
*
* @implNote Mainly an intention contract wrt the immediacy of the fetch.
*
* @author Steve Ebersole
*/
@SuppressWarnings("WeakerAccess")
public abstract class AbstractImmediateCollectionInitializer extends AbstractCollectionInitializer {
private final LockMode lockMode;
// per-row state
private PersistentCollection collectionInstance;
private boolean responsible;
private boolean collectionEmpty = true;
public AbstractImmediateCollectionInitializer(
NavigablePath collectionPath,
PluralAttributeMapping collectionAttributeMapping,
FetchParentAccess parentAccess,
boolean selected,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler) {
super( collectionPath, collectionAttributeMapping, parentAccess, selected, keyContainerAssembler, keyCollectionAssembler );
this.lockMode = lockMode;
}
@Override
public PersistentCollection getCollectionInstance() {
return collectionInstance;
}
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
if ( collectionInstance != null ) {
return;
}
final SharedSessionContractImplementor session = rowProcessingState.getSession();
final PersistenceContext persistenceContext = session.getPersistenceContext();
final CollectionKey collectionKey = resolveCollectionKey( rowProcessingState );
if ( CollectionLoadingLogger.TRACE_ENABLED ) {
CollectionLoadingLogger.INSTANCE.tracef(
"(%s) Beginning Initializer#resolveInstance for collection : %s",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() )
);
}
// determine the PersistentCollection instance to use and whether
// we (this initializer) is responsible for loading its state
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// First, look for a LoadingCollectionEntry
final LoadingCollectionEntry existingLoadingEntry = persistenceContext
.getLoadContexts()
.findLoadingCollectionEntry( collectionKey );
// final LoadingCollectionEntry existingLoadingEntry = rowProcessingState.getJdbcValuesSourceProcessingState()
// .findLoadingCollectionLocally( getCollectionDescriptor(), collectionKey.getKey() );
final PluralAttributeMapping collectionAttributeMapping = getCollectionAttributeMapping();
final CollectionPersister collectionDescriptor = collectionAttributeMapping.getCollectionDescriptor();
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
if ( existingLoadingEntry != null ) {
collectionInstance = existingLoadingEntry.getCollectionInstance();
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Found existing loading collection entry [%s]; using loading collection instance - %s",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
LoggingHelper.toLoggableString( collectionInstance )
);
}
if ( existingLoadingEntry.getInitializer() == this ) {
// we are responsible for loading the collection values
responsible = true;
}
else {
// the entity is already being loaded elsewhere
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Collection [%s] being loaded by another initializer [%s] - skipping processing",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
existingLoadingEntry.getInitializer()
);
}
// EARLY EXIT!!!
return;
}
}
else {
final PersistentCollection existing = persistenceContext.getCollection( collectionKey );
if ( existing != null ) {
collectionInstance = existing;
// we found the corresponding collection instance on the Session. If
// it is already initialized we have nothing to do
if ( collectionInstance.wasInitialized() ) {
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Found existing collection instance [%s] in Session; skipping processing - [%s]",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
LoggingHelper.toLoggableString( collectionInstance )
);
}
// EARLY EXIT!!!
return;
}
else {
assert isSelected();
takeResponsibility( rowProcessingState, collectionKey );
}
}
else {
final PersistentCollection existingUnowned = persistenceContext.useUnownedCollection( collectionKey );
if ( existingUnowned != null ) {
collectionInstance = existingUnowned;
// we found the corresponding collection instance as unowned on the Session. If
// it is already initialized we have nothing to do
if ( collectionInstance.wasInitialized() ) {
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Found existing unowned collection instance [%s] in Session; skipping processing - [%s]",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
LoggingHelper.toLoggableString( collectionInstance )
);
}
// EARLY EXIT!!!
return;
}
else {
assert isSelected();
takeResponsibility( rowProcessingState, collectionKey );
}
}
}
if ( ! isSelected() ) {
collectionInstance = collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
collectionDescriptor,
session
);
persistenceContext.addNonLazyCollection( collectionInstance );
// EARLY EXIT!!!
return;
}
}
if ( collectionInstance == null && collectionKey != null ) {
collectionInstance = collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
getInitializingCollectionDescriptor(),
session
);
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Created new collection wrapper [%s] : %s",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
LoggingHelper.toLoggableString( collectionInstance )
);
}
persistenceContext.addUninitializedCollection( collectionDescriptor, collectionInstance, collectionKey.getKey() );
takeResponsibility( rowProcessingState, collectionKey );
}
if ( responsible ) {
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Responsible for loading collection [%s] : %s",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
LoggingHelper.toLoggableString( collectionInstance )
);
}
if ( getParentAccess() != null ) {
getParentAccess().registerResolutionListener(
owner -> collectionInstance.setOwner( owner )
);
}
// if ( getCollectionDescriptor().getSemantics().getCollectionClassification() == CollectionClassification.ARRAY ) {
// persistenceContext.addCollectionHolder( collectionInstance );
// }
}
}
protected void takeResponsibility(RowProcessingState rowProcessingState, CollectionKey collectionKey) {
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
getCollectionAttributeMapping().getCollectionDescriptor(),
this,
collectionKey.getKey(),
collectionInstance
)
);
responsible = true;
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( !responsible ) {
return;
}
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContext();
// the LHS key value of the association
final CollectionKey collectionKey = resolveCollectionKey( rowProcessingState );
// the RHS key value of the association
final Object keyCollectionValue = getKeyCollectionValue();
if ( keyCollectionValue != null ) {
// the row contains an element in the collection...
if ( CollectionLoadingLogger.DEBUG_ENABLED ) {
CollectionLoadingLogger.INSTANCE.debugf(
"(%s) Reading element from row for collection [%s] -> %s",
StringHelper.collapse( this.getClass().getName() ),
LoggingHelper.toLoggableString( getNavigablePath(), collectionKey.getKey() ),
LoggingHelper.toLoggableString( collectionInstance )
);
}
readCollectionRow( rowProcessingState );
collectionEmpty = false;
}
}
protected abstract void readCollectionRow(RowProcessingState rowProcessingState);
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
super.finishUpRow( rowProcessingState );
collectionInstance = null;
responsible = false;
collectionEmpty = true;
}
@Override
public void endLoading(ExecutionContext context) {
if ( getParentAccess() == null && collectionEmpty ) {
// collection is empty; handle special logic here.
final CollectionKey collectionKey = context.getCollectionKey();
if ( collectionKey != null ) {
// We expected to load a collection with this collection key but we found the collection
// contained no results, therefore we need to do the collection init phase here because
// the LoadingCollectionEntry won't finalize this for us without at least one row.
final PersistenceContext persistenceContext = context.getSession().getPersistenceContext();
final PersistentCollection collection = persistenceContext.getCollection( collectionKey );
collection.beforeInitialize( getCollectionAttributeMapping().getCollectionDescriptor(), 0 );
collection.beginRead();
collection.endRead();
final CollectionEntry entry = persistenceContext.getCollectionEntry( collection );
if ( entry != null ) {
entry.postInitialize( collection );
}
}
}
}
}

View File

@ -0,0 +1,70 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.LockMode;
import org.hibernate.collection.internal.PersistentArrayHolder;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* @author Chris Cranford
*/
public class ArrayInitializer extends AbstractImmediateCollectionInitializer {
private final DomainResultAssembler listIndexAssembler;
private final DomainResultAssembler elementAssembler;
private final int indexBase;
public ArrayInitializer(
NavigablePath navigablePath,
PluralAttributeMapping arrayDescriptor,
FetchParentAccess parentAccess,
boolean selected,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
DomainResultAssembler listIndexAssembler,
DomainResultAssembler elementAssembler) {
super(
navigablePath,
arrayDescriptor,
parentAccess,
selected,
lockMode,
keyContainerAssembler,
keyCollectionAssembler
);
this.listIndexAssembler = listIndexAssembler;
this.elementAssembler = elementAssembler;
this.indexBase = getCollectionAttributeMapping().getIndexMetadata().getListIndexBase();
}
@Override
public PersistentArrayHolder getCollectionInstance() {
return (PersistentArrayHolder) super.getCollectionInstance();
}
@Override
protected void readCollectionRow(RowProcessingState rowProcessingState) {
int index = (int) listIndexAssembler.assemble( rowProcessingState );
if ( indexBase != 0 ) {
index -= indexBase;
}
getCollectionInstance().load( index, elementAssembler.assemble( rowProcessingState ) );
}
@Override
public String toString() {
return "ArrayInitializer{" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
}

View File

@ -0,0 +1,72 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Chris Cranford
*/
public class ArrayInitializerProducer implements CollectionInitializerProducer {
private final PluralAttributeMapping arrayDescriptor;
private final boolean joined;
private final Fetch listIndexFetch;
private final Fetch elementFetch;
public ArrayInitializerProducer(
PluralAttributeMapping arrayDescriptor,
boolean joined,
Fetch listIndexFetch,
Fetch elementFetch) {
this.arrayDescriptor = arrayDescriptor;
this.joined = joined;
this.listIndexFetch = listIndexFetch;
this.elementFetch = elementFetch;
}
@Override
public CollectionInitializer produceInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
return new ArrayInitializer(
navigablePath,
arrayDescriptor,
parentAccess,
joined,
lockMode,
keyContainerAssembler,
keyCollectionAssembler,
listIndexFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
),
elementFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
)
);
}
}

View File

@ -0,0 +1,62 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.LockMode;
import org.hibernate.collection.internal.PersistentBag;
import org.hibernate.collection.internal.PersistentIdentifierBag;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* Initializer for both {@link PersistentBag} and {@link PersistentIdentifierBag}
* collections
*
* @author Steve Ebersole
*/
public class BagInitializer extends AbstractImmediateCollectionInitializer {
private final DomainResultAssembler elementAssembler;
private final DomainResultAssembler collectionIdAssembler;
public BagInitializer(
PluralAttributeMapping bagDescriptor,
FetchParentAccess parentAccess,
NavigablePath navigablePath,
boolean selected,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
DomainResultAssembler elementAssembler,
DomainResultAssembler collectionIdAssembler) {
super( navigablePath, bagDescriptor, parentAccess, selected, lockMode, keyContainerAssembler, keyCollectionAssembler );
this.elementAssembler = elementAssembler;
this.collectionIdAssembler = collectionIdAssembler;
}
@Override
@SuppressWarnings("unchecked")
protected void readCollectionRow(RowProcessingState rowProcessingState) {
if ( collectionIdAssembler != null ) {
( (PersistentIdentifierBag) getCollectionInstance() ).load(
collectionIdAssembler.assemble( rowProcessingState ),
elementAssembler.assemble( rowProcessingState )
);
}
else {
( (PersistentBag) getCollectionInstance() ).load( elementAssembler.assemble( rowProcessingState ) );
}
}
@Override
public String toString() {
return "BagInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
}

View File

@ -0,0 +1,94 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class BagInitializerProducer implements CollectionInitializerProducer {
private final PluralAttributeMapping bagDescriptor;
private final boolean selected;
private final Fetch collectionIdFetch;
private final Fetch elementFetch;
public BagInitializerProducer(
PluralAttributeMapping bagDescriptor,
boolean selected,
Fetch collectionIdFetch,
Fetch elementFetch) {
this.bagDescriptor = bagDescriptor;
this.selected = selected;
if ( bagDescriptor.getIdentifierDescriptor() != null ) {
assert collectionIdFetch != null;
this.collectionIdFetch = collectionIdFetch;
}
else {
assert collectionIdFetch == null;
this.collectionIdFetch = null;
}
this.elementFetch = elementFetch;
}
@Override
public CollectionInitializer produceInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
final DomainResultAssembler elementAssembler = elementFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
);
final DomainResultAssembler collectionIdAssembler;
if ( bagDescriptor.getIdentifierDescriptor() == null ) {
collectionIdAssembler = null;
}
else {
collectionIdAssembler = collectionIdFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
);
}
return new BagInitializer(
bagDescriptor,
parentAccess,
navigablePath,
selected,
lockMode,
keyContainerAssembler,
keyCollectionAssembler,
elementAssembler,
collectionIdAssembler
);
}
}

View File

@ -0,0 +1,315 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.LoadingCollectionEntryImpl;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.CollectionResultNode;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchableContainer;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.LoadContexts;
import org.hibernate.sql.results.spi.LoadingCollectionEntry;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class CollectionDomainResult implements DomainResult, CollectionResultNode, FetchParent {
private final NavigablePath loadingPath;
private final PluralAttributeMapping loadingAttribute;
private final String resultVariable;
private final DomainResult fkResult;
private final CollectionInitializerProducer initializerProducer;
public CollectionDomainResult(
NavigablePath loadingPath,
PluralAttributeMapping loadingAttribute,
String resultVariable,
TableGroup tableGroup,
DomainResultCreationState creationState) {
this.loadingPath = loadingPath;
this.loadingAttribute = loadingAttribute;
this.resultVariable = resultVariable;
fkResult = loadingAttribute.getKeyDescriptor().createDomainResult(
loadingPath,
tableGroup,
creationState
);
final CollectionSemantics collectionSemantics = loadingAttribute.getCollectionDescriptor().getCollectionSemantics();
initializerProducer = collectionSemantics.createInitializerProducer(
loadingPath,
loadingAttribute,
this,
true,
null,
LockMode.READ,
creationState
);
}
@Override
public String getResultVariable() {
return resultVariable;
}
@Override
public JavaTypeDescriptor getResultJavaTypeDescriptor() {
return loadingAttribute.getJavaTypeDescriptor();
}
@Override
public DomainResultAssembler createResultAssembler(
Consumer initializerCollector,
AssemblerCreationState creationState) {
final DomainResultAssembler fkAssembler = fkResult.createResultAssembler(
initializerCollector,
creationState
);
final CollectionInitializer initializer = initializerProducer.produceInitializer(
loadingPath,
loadingAttribute,
null,
LockMode.READ,
fkAssembler,
fkAssembler,
initializerCollector,
creationState
);
initializerCollector.accept( initializer );
return new EagerCollectionAssembler( loadingAttribute, initializer );
}
@Override
public FetchableContainer getReferencedMappingContainer() {
return loadingAttribute;
}
@Override
public FetchableContainer getReferencedMappingType() {
return getReferencedMappingContainer();
}
@Override
public NavigablePath getNavigablePath() {
return loadingPath;
}
@Override
public List<Fetch> getFetches() {
return null;
}
@Override
public Fetch findFetch(String fetchableName) {
return null;
}
private static class InitializerImpl implements CollectionInitializer {
private final NavigablePath loadingPath;
private final PluralAttributeMapping loadingCollection;
private final DomainResultAssembler fkAssembler;
private final DomainResultAssembler elementAssembler;
private final DomainResultAssembler indexAssembler;
private final DomainResultAssembler identifierAssembler;
private CollectionKey collectionKey;
private boolean managing;
private Object fkValue;
// todo (6.0) : consider using the initializer itself as the holder of the various "temp" collections
// used while reading a collection. that would mean collection-type specific initializers (List, versus Set)
private PersistentCollection instance;
public InitializerImpl(
NavigablePath loadingPath,
PluralAttributeMapping loadingCollection,
DomainResult fkResult,
Fetch elementFetch,
Fetch indexFetch,
DomainResult identifierResult,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
this.loadingPath = loadingPath;
this.loadingCollection = loadingCollection;
this.fkAssembler = fkResult.createResultAssembler( collector, creationState );
// questionable what should be the parent access here
this.elementAssembler = elementFetch.createAssembler( null, collector, creationState );
this.indexAssembler = indexFetch == null
? null
: indexFetch.createAssembler( null, collector, creationState );
this.identifierAssembler = identifierResult == null
? null
: identifierResult.createResultAssembler( collector, creationState );
}
@Override
public PluralAttributeMapping getInitializedPart() {
return loadingCollection;
}
@Override
public PersistentCollection getCollectionInstance() {
return instance;
}
@Override
public NavigablePath getNavigablePath() {
return loadingPath;
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
collectionKey = null;
managing = false;
instance = null;
}
@Override
public void resolveKey(RowProcessingState rowProcessingState) {
if ( collectionKey != null ) {
// already resolved
return;
}
final Object fkValue = fkAssembler.assemble( rowProcessingState );
assert fkValue != null;
collectionKey = new CollectionKey(
loadingCollection.getCollectionDescriptor(),
fkValue
);
}
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
if ( instance != null ) {
// already resolved
return;
}
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContext();
// see if the collection is already being initialized
final LoadContexts loadContexts = persistenceContext.getLoadContexts();
final LoadingCollectionEntry existingEntry = loadContexts.findLoadingCollectionEntry( collectionKey );
if ( existingEntry != null ) {
this.instance = existingEntry.getCollectionInstance();
if ( existingEntry.getInitializer() == this ) {
this.managing = true;
}
return;
}
// see if it has been already registered with the Session
final PersistentCollection registeredInstance = persistenceContext.getCollection( collectionKey );
if ( registeredInstance != null ) {
this.instance = registeredInstance;
// it was already registered, so use that wrapper.
if ( ! registeredInstance.wasInitialized() ) {
// if the existing wrapper is not initialized, we will take responsibility for initializing it
managing = true;
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
getInitializingCollectionDescriptor(),
this,
collectionKey,
registeredInstance
)
);
return;
}
}
this.instance = makePersistentCollection( loadingCollection, collectionKey, rowProcessingState );
this.managing = true;
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
loadingCollection.getCollectionDescriptor(),
this,
collectionKey.getKey(),
instance
)
);
}
private static PersistentCollection makePersistentCollection(
PluralAttributeMapping fetchedMapping,
CollectionKey collectionKey,
RowProcessingState rowProcessingState) {
final CollectionPersister collectionDescriptor = fetchedMapping.getCollectionDescriptor();
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
return collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
collectionDescriptor,
rowProcessingState.getSession()
);
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( ! managing ) {
return;
}
final Object fkValue = fkAssembler.assemble( rowProcessingState );
if ( fkValue == null ) {
// this row contains no collection element
return;
}
final PersistentCollection collectionInstance = getCollectionInstance();
collectionInstance.readFrom(
rowProcessingState,
elementAssembler,
indexAssembler,
identifierAssembler,
collectionInstance.getOwner()
);
}
}
}

View File

@ -8,7 +8,6 @@ package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;

View File

@ -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.sql.results.internal.domain.collection;
import org.hibernate.sql.results.SqlResultsLogger;
import org.jboss.logging.BasicLogger;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public interface CollectionLoadingLogger extends BasicLogger {
String LOGGER_NAME = SqlResultsLogger.LOGGER_NAME + "loading.collection";
/**
* Static access to the logging instance
*/
Logger INSTANCE = Logger.getLogger( LOGGER_NAME );
boolean TRACE_ENABLED = INSTANCE.isTraceEnabled();
boolean DEBUG_ENABLED = INSTANCE.isDebugEnabled();
}

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.io.Serializable;
import java.util.function.Consumer;
import org.hibernate.collection.spi.CollectionSemantics;
@ -143,8 +142,8 @@ public class DelayedCollectionAssembler implements DomainResultAssembler {
}
@Override
public CollectionPersister getInitializingCollectionDescriptor() {
return fetchedMapping.getCollectionDescriptor();
public PluralAttributeMapping getInitializedPart() {
return fetchedMapping;
}
@Override

View File

@ -0,0 +1,113 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.log.LoggingHelper;
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.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* @author Steve Ebersole
*/
public class DelayedCollectionInitializer extends AbstractCollectionInitializer {
// per-row state
private PersistentCollection collectionInstance;
public DelayedCollectionInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler) {
super( navigablePath, attributeMapping, parentAccess, false, keyContainerAssembler, keyCollectionAssembler );
}
@Override
public PersistentCollection getCollectionInstance() {
return collectionInstance;
}
@Override
public void resolveKey(RowProcessingState rowProcessingState) {
super.resolveKey( rowProcessingState );
getParentAccess().registerResolutionListener(
owner -> collectionInstance.setOwner( owner )
);
}
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
final CollectionKey collectionKey = resolveCollectionKey( rowProcessingState );
if(collectionKey != null) {
final SharedSessionContractImplementor session = rowProcessingState.getSession();
final PersistenceContext persistenceContext = session.getPersistenceContext();
final PluralAttributeMapping attributeMapping = getCollectionAttributeMapping();
final CollectionPersister collectionDescriptor = attributeMapping.getCollectionDescriptor();
// todo (6.0) : look for LoadingCollectionEntry?
final PersistentCollection existing = persistenceContext.getCollection( collectionKey );
if ( existing != null ) {
collectionInstance = existing;
}
else {
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
collectionInstance = collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
collectionDescriptor,
session
);
getParentAccess().registerResolutionListener(
owner -> collectionInstance.setOwner( owner )
);
persistenceContext.addUninitializedCollection(
collectionDescriptor,
collectionInstance,
collectionKey.getKey()
);
if ( collectionSemantics.getCollectionClassification() == CollectionClassification.ARRAY ) {
session.getPersistenceContext().addCollectionHolder( collectionInstance );
}
}
}
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
/// nothing to do
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
collectionInstance = null;
super.finishUpRow( rowProcessingState );
}
@Override
public String toString() {
return "DelayedCollectionInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
}

View File

@ -6,26 +6,10 @@
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.internal.LoadingCollectionEntryImpl;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.LoadContexts;
import org.hibernate.sql.results.spi.LoadingCollectionEntry;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -34,36 +18,13 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*/
public class EagerCollectionAssembler implements DomainResultAssembler {
private final PluralAttributeMapping fetchedMapping;
private final FetchParentAccess parentAccess;
private final CollectionInitializer initializer;
public EagerCollectionAssembler(
NavigablePath fetchPath,
PluralAttributeMapping fetchedMapping,
DomainResult fkResult,
Fetch elementFetch,
Fetch indexFetch,
DomainResult identifierResult,
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
CollectionInitializer initializer) {
this.fetchedMapping = fetchedMapping;
this.parentAccess = parentAccess;
this.initializer = new InitializerImpl(
fetchPath,
fetchedMapping,
parentAccess,
fkResult,
elementFetch,
indexFetch,
identifierResult,
collector,
creationState
);
collector.accept( initializer );
this.initializer = initializer;
}
@Override
@ -76,183 +37,4 @@ public class EagerCollectionAssembler implements DomainResultAssembler {
return fetchedMapping.getJavaTypeDescriptor();
}
private static class InitializerImpl implements CollectionInitializer {
private final NavigablePath fetchedPath;
private final PluralAttributeMapping fetchedMapping;
private final FetchParentAccess parentAccess;
private final DomainResultAssembler fkAssembler;
private final DomainResultAssembler elementAssembler;
private final DomainResultAssembler indexAssembler;
private final DomainResultAssembler identifierAssembler;
private CollectionKey collectionKey;
private boolean managing;
private Object fkValue;
// todo (6.0) : consider using the initializer itself as the holder of the various "temp" collections
// used while reading a collection. that would mean collection-type specific initializers (List, versus Set)
private PersistentCollection instance;
public InitializerImpl(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedMapping,
FetchParentAccess parentAccess,
DomainResult fkResult,
Fetch elementFetch,
Fetch indexFetch,
DomainResult identifierResult,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
this.fetchedPath = fetchedPath;
this.fetchedMapping = fetchedMapping;
this.parentAccess = parentAccess;
this.fkAssembler = fkResult.createResultAssembler( collector, creationState );
// questionable what should be the parent access here
this.elementAssembler = elementFetch.createAssembler( parentAccess, collector, creationState );
this.indexAssembler = indexFetch == null
? null
: indexFetch.createAssembler( parentAccess, collector, creationState );
this.identifierAssembler = identifierResult == null
? null
: identifierResult.createResultAssembler( collector, creationState );
}
@Override
public CollectionPersister getInitializingCollectionDescriptor() {
return fetchedMapping.getCollectionDescriptor();
}
@Override
public PersistentCollection getCollectionInstance() {
return instance;
}
@Override
public NavigablePath getNavigablePath() {
return fetchedPath;
}
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
collectionKey = null;
managing = false;
instance = null;
}
@Override
public void resolveKey(RowProcessingState rowProcessingState) {
if ( collectionKey != null ) {
// already resolved
return;
}
collectionKey = new CollectionKey(
fetchedMapping.getCollectionDescriptor(),
parentAccess.getParentKey()
);
final Object fkValue = fkAssembler.assemble( rowProcessingState );
if ( fkValue == null ) {
// this row has no collection element
return;
}
}
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
if ( instance != null ) {
// already resolved
return;
}
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContext();
// see if the collection is already being initialized
final LoadContexts loadContexts = persistenceContext.getLoadContexts();
final LoadingCollectionEntry existingEntry = loadContexts.findLoadingCollectionEntry( collectionKey );
if ( existingEntry != null ) {
this.instance = existingEntry.getCollectionInstance();
if ( existingEntry.getInitializer() == this ) {
this.managing = true;
}
return;
}
// see if it has been already registered with the Session
final PersistentCollection registeredInstance = persistenceContext.getCollection( collectionKey );
if ( registeredInstance != null ) {
this.instance = registeredInstance;
// it was already registered, so use that wrapper.
if ( ! registeredInstance.wasInitialized() ) {
// if the existing wrapper is not initialized, we will take responsibility for initializing it
managing = true;
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
getInitializingCollectionDescriptor(),
this,
collectionKey,
registeredInstance
)
);
return;
}
}
this.instance = makePersistentCollection( fetchedMapping, collectionKey, rowProcessingState );
this.managing = true;
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingCollection(
collectionKey,
new LoadingCollectionEntryImpl(
fetchedMapping.getCollectionDescriptor(),
this,
collectionKey.getKey(),
instance
)
);
}
private static PersistentCollection makePersistentCollection(
PluralAttributeMapping fetchedMapping,
CollectionKey collectionKey,
RowProcessingState rowProcessingState) {
final CollectionPersister collectionDescriptor = fetchedMapping.getCollectionDescriptor();
final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics();
return collectionSemantics.instantiateWrapper(
collectionKey.getKey(),
collectionDescriptor,
rowProcessingState.getSession()
);
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( ! managing ) {
return;
}
final Object fkValue = fkAssembler.assemble( rowProcessingState );
if ( fkValue == null ) {
// this row contains no collection element
return;
}
getCollectionInstance().readFrom(
rowProcessingState,
elementAssembler,
indexAssembler,
identifierAssembler,
parentAccess.getFetchParentInstance()
);
}
}
}

View File

@ -9,12 +9,17 @@ package org.hibernate.sql.results.internal.domain.collection;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
@ -29,31 +34,43 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
* @author Steve Ebersole
*/
public class EagerCollectionFetch extends CollectionFetch implements FetchParent {
private final DomainResult fkResult;
private final DomainResult keyContainerResult;
private final DomainResult keyCollectionResult;
private final Fetch elementFetch;
private final Fetch indexFetch;
private final DomainResult identifierResult;
private final List<Fetch> fetches;
private final CollectionInitializerProducer initializerProducer;
public EagerCollectionFetch(
NavigablePath fetchedPath,
PluralAttributeMapping fetchedAttribute,
DomainResult fkResult,
boolean nullable,
FetchParent fetchParent,
DomainResultCreationState creationState) {
super( fetchedPath, fetchedAttribute, nullable, fetchParent );
this.fkResult = fkResult;
final CollectionIdentifierDescriptor identifierDescriptor = fetchedAttribute.getIdentifierDescriptor();
if ( identifierDescriptor == null ) {
this.identifierResult = null;
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
final TableGroup collectionTableGroup = fromClauseAccess.getTableGroup( fetchedPath );
final NavigablePath parentPath = fetchedPath.getParent();
final TableGroup parentTableGroup = parentPath == null ? null : fromClauseAccess.findTableGroup( parentPath );
final ForeignKeyDescriptor keyDescriptor = fetchedAttribute.getKeyDescriptor();
if ( parentTableGroup != null ) {
// join fetch
keyContainerResult = keyDescriptor.createDomainResult( fetchedPath, parentTableGroup, creationState );
keyCollectionResult = keyDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
}
else {
final TableGroup collectionTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().getTableGroup( fetchedPath );
this.identifierResult = identifierDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
// select fetch
// todo (6.0) : we could potentially leverage batch fetching for performance
keyContainerResult = keyDescriptor.createDomainResult( fetchedPath, collectionTableGroup, creationState );
// use null for `keyCollectionResult`... the initializer will see that as trigger to use
// the assembled container-key value as the collection-key value.
keyCollectionResult = null;
}
fetches = creationState.visitFetches( this );
@ -67,6 +84,18 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
indexFetch = null;
elementFetch = fetches.get( 0 );
}
final CollectionSemantics collectionSemantics = getFetchedMapping().getCollectionDescriptor().getCollectionSemantics();
initializerProducer = collectionSemantics.createInitializerProducer(
fetchedPath,
fetchedAttribute,
fetchParent,
nullable,
null,
// todo (6.0) : we need to propagate these lock modes
LockMode.READ,
creationState
);
}
@Override
@ -74,17 +103,36 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
return new EagerCollectionAssembler(
getNavigablePath(),
getFetchedMapping(),
fkResult,
elementFetch,
indexFetch,
identifierResult,
parentAccess,
final DomainResultAssembler keyContainerAssembler = keyContainerResult.createResultAssembler(
collector,
creationState
);
final DomainResultAssembler keyCollectionAssembler;
if ( keyCollectionResult == null ) {
keyCollectionAssembler = null;
}
else {
keyCollectionAssembler = keyCollectionResult.createResultAssembler(
collector,
creationState
);
}
final CollectionInitializer initializer = initializerProducer.produceInitializer(
getNavigablePath(),
getFetchedMapping(),
parentAccess,
null,
keyContainerAssembler,
keyCollectionAssembler,
collector,
creationState
);
collector.accept( initializer );
return new EagerCollectionAssembler( getFetchedMapping(), initializer );
}
@Override

View File

@ -0,0 +1,120 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
/**
* @author Steve Ebersole
*/
public class EntityCollectionPartTableGroup implements TableGroup {
private final NavigablePath collectionPartPath;
private final TableGroup collectionTableGroup;
private final EntityCollectionPart collectionPart;
public EntityCollectionPartTableGroup(
NavigablePath collectionPartPath,
TableGroup collectionTableGroup,
EntityCollectionPart collectionPart) {
this.collectionPartPath = collectionPartPath;
this.collectionTableGroup = collectionTableGroup;
this.collectionPart = collectionPart;
}
@Override
public NavigablePath getNavigablePath() {
return collectionPartPath;
}
@Override
public String getGroupAlias() {
return null;
}
@Override
public EntityCollectionPart getModelPart() {
return collectionPart;
}
@Override
public LockMode getLockMode() {
return collectionTableGroup.getLockMode();
}
@Override
public Set<TableGroupJoin> getTableGroupJoins() {
return collectionTableGroup.getTableGroupJoins();
}
@Override
public boolean hasTableGroupJoins() {
return collectionTableGroup.hasTableGroupJoins();
}
@Override
public void setTableGroupJoins(Set<TableGroupJoin> joins) {
collectionTableGroup.setTableGroupJoins( joins );
}
@Override
public void addTableGroupJoin(TableGroupJoin join) {
collectionTableGroup.addTableGroupJoin( join );
}
@Override
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
collectionTableGroup.visitTableGroupJoins( consumer );
}
@Override
public void applyAffectedTableNames(Consumer<String> nameCollector) {
collectionTableGroup.applyAffectedTableNames( nameCollector );
}
@Override
public TableReference getPrimaryTableReference() {
return collectionTableGroup.getPrimaryTableReference();
}
@Override
public List<TableReferenceJoin> getTableReferenceJoins() {
return collectionTableGroup.getTableReferenceJoins();
}
@Override
public boolean isInnerJoinPossible() {
return collectionTableGroup.isInnerJoinPossible();
}
@Override
public TableReference resolveTableReference(String tableExpression, Supplier<TableReference> creator) {
return collectionTableGroup.resolveTableReference( tableExpression, creator );
}
@Override
public TableReference resolveTableReference(String tableExpression) {
return collectionTableGroup.resolveTableReference( tableExpression );
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
// do nothing
}
}

View File

@ -0,0 +1,65 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.LockMode;
import org.hibernate.collection.internal.PersistentList;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* CollectionInitializer for PersistentList loading
*
* @author Steve Ebersole
*/
public class ListInitializer extends AbstractImmediateCollectionInitializer {
private final DomainResultAssembler listIndexAssembler;
private final DomainResultAssembler elementAssembler;
private final int listIndexBase;
public ListInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
boolean selected,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
DomainResultAssembler listIndexAssembler,
DomainResultAssembler elementAssembler) {
super( navigablePath, attributeMapping, parentAccess, selected, lockMode, keyContainerAssembler, keyCollectionAssembler );
this.listIndexAssembler = listIndexAssembler;
this.elementAssembler = elementAssembler;
listIndexBase = attributeMapping.getIndexMetadata().getListIndexBase();
}
@Override
public PersistentList getCollectionInstance() {
return (PersistentList) super.getCollectionInstance();
}
@Override
protected void readCollectionRow(RowProcessingState rowProcessingState) {
int index = (int) listIndexAssembler.assemble( rowProcessingState );
getCollectionAttributeMapping().getIndexMetadata().getIndexDescriptor();
if ( listIndexBase != 0 ) {
index -= listIndexBase;
}
getCollectionInstance().load( index, elementAssembler.assemble( rowProcessingState ) );
}
@Override
public String toString() {
return "ListInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
}

View File

@ -0,0 +1,73 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class ListInitializerProducer implements CollectionInitializerProducer {
private final PluralAttributeMapping attributeMapping;
private final boolean joined;
private final Fetch listIndexFetch;
private final Fetch elementFetch;
public ListInitializerProducer(
PluralAttributeMapping attributeMapping,
boolean joined,
Fetch listIndexFetch,
Fetch elementFetch) {
this.attributeMapping = attributeMapping;
this.joined = joined;
this.listIndexFetch = listIndexFetch;
this.elementFetch = elementFetch;
}
@Override
public CollectionInitializer produceInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
return new ListInitializer(
navigablePath,
attributeMapping,
parentAccess,
joined,
lockMode,
keyContainerAssembler,
keyCollectionAssembler,
listIndexFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
),
elementFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
)
);
}
}

View File

@ -0,0 +1,63 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.LockMode;
import org.hibernate.collection.internal.PersistentMap;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* Represents an immediate initialization of some sort (join, select, batch, sub-select)
* of a persistent Map valued attribute.
*
* @see DelayedCollectionInitializer
*
* @author Steve Ebersole
*/
public class MapInitializer extends AbstractImmediateCollectionInitializer {
private final DomainResultAssembler mapKeyAssembler;
private final DomainResultAssembler mapValueAssembler;
public MapInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
boolean selected,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
DomainResultAssembler mapKeyAssembler,
DomainResultAssembler mapValueAssembler) {
super( navigablePath, attributeMapping, parentAccess, selected, lockMode, keyContainerAssembler, keyCollectionAssembler );
this.mapKeyAssembler = mapKeyAssembler;
this.mapValueAssembler = mapValueAssembler;
}
@Override
public PersistentMap getCollectionInstance() {
return (PersistentMap) super.getCollectionInstance();
}
@Override
@SuppressWarnings("unchecked")
protected void readCollectionRow(RowProcessingState rowProcessingState) {
getCollectionInstance().load(
mapKeyAssembler.assemble( rowProcessingState ),
mapValueAssembler.assemble( rowProcessingState )
);
}
@Override
public String toString() {
return "MapInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
}

View File

@ -0,0 +1,76 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class MapInitializerProducer implements CollectionInitializerProducer {
private final PluralAttributeMapping mapDescriptor;
private final boolean isJoined;
private final Fetch mapKeyFetch;
private final Fetch mapValueFetch;
public MapInitializerProducer(
PluralAttributeMapping mapDescriptor,
boolean isJoined,
Fetch mapKeyFetch,
Fetch mapValueFetch) {
this.mapDescriptor = mapDescriptor;
this.isJoined = isJoined;
this.mapKeyFetch = mapKeyFetch;
this.mapValueFetch = mapValueFetch;
}
@Override
public CollectionInitializer produceInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
final DomainResultAssembler mapKeyAssembler = mapKeyFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
);
final DomainResultAssembler mapValueAssembler = mapValueFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
);
return new MapInitializer(
navigablePath,
mapDescriptor,
parentAccess,
isJoined,
lockMode,
keyContainerAssembler,
keyCollectionAssembler,
mapKeyAssembler,
mapValueAssembler
);
}
}

View File

@ -0,0 +1,41 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class PluralAttributeAssemblerImpl implements DomainResultAssembler {
private final CollectionInitializer initializer;
public PluralAttributeAssemblerImpl(CollectionInitializer initializer) {
this.initializer = initializer;
}
@Override
public Object assemble(
RowProcessingState rowProcessingState,
JdbcValuesSourceProcessingOptions options) {
PersistentCollection collectionInstance = initializer.getCollectionInstance();
if ( collectionInstance == null ) {
return null;
}
return collectionInstance.getValue();
}
@Override
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
return initializer.getInitializedPart().getJavaTypeDescriptor();
}
}

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import org.hibernate.LockMode;
import org.hibernate.collection.internal.PersistentSet;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.RowProcessingState;
/**
* @author Steve Ebersole
*/
public class SetInitializer extends AbstractImmediateCollectionInitializer {
private final DomainResultAssembler elementAssembler;
public SetInitializer(
NavigablePath navigablePath,
PluralAttributeMapping setDescriptor,
FetchParentAccess parentAccess,
boolean selected,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
DomainResultAssembler elementAssembler) {
super( navigablePath, setDescriptor, parentAccess, selected, lockMode, keyContainerAssembler, keyCollectionAssembler );
this.elementAssembler = elementAssembler;
}
@Override
public PersistentSet getCollectionInstance() {
return (PersistentSet) super.getCollectionInstance();
}
@Override
protected void readCollectionRow(RowProcessingState rowProcessingState) {
getCollectionInstance().load( elementAssembler.assemble( rowProcessingState ) );
}
@Override
public String toString() {
return "SetInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
}

View File

@ -0,0 +1,67 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.internal.domain.collection;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.collection.spi.CollectionInitializerProducer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CollectionInitializer;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class SetInitializerProducer implements CollectionInitializerProducer {
private final PluralAttributeMapping setDescriptor;
private final boolean isSelected;
private final Fetch elementFetch;
public SetInitializerProducer(
PluralAttributeMapping setDescriptor,
boolean isSelected,
Fetch elementFetch) {
this.setDescriptor = setDescriptor;
this.elementFetch = elementFetch;
this.isSelected = isSelected;
}
@Override
public CollectionInitializer produceInitializer(
NavigablePath navigablePath,
PluralAttributeMapping attributeMapping,
FetchParentAccess parentAccess,
LockMode lockMode,
DomainResultAssembler keyContainerAssembler,
DomainResultAssembler keyCollectionAssembler,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
final DomainResultAssembler elementAssembler = elementFetch.createAssembler(
parentAccess,
initializerConsumer,
creationState
);
return new SetInitializer(
navigablePath,
setDescriptor,
parentAccess,
isSelected,
lockMode,
keyContainerAssembler,
keyCollectionAssembler,
elementAssembler
);
}
}

View File

@ -18,7 +18,7 @@ import org.hibernate.sql.results.internal.NullValueAssembler;
import org.hibernate.sql.results.internal.domain.AbstractFetchParentAccess;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CompositeInitializer;
import org.hibernate.sql.results.spi.CompositeResultMappingNode;
import org.hibernate.sql.results.spi.CompositeResultNode;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParentAccess;
@ -42,7 +42,7 @@ public abstract class AbstractCompositeInitializer extends AbstractFetchParentAc
@SuppressWarnings("WeakerAccess")
public AbstractCompositeInitializer(
CompositeResultMappingNode resultDescriptor,
CompositeResultNode resultDescriptor,
FetchParentAccess fetchParentAccess,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
@ -69,7 +69,7 @@ public abstract class AbstractCompositeInitializer extends AbstractFetchParentAc
}
@Override
public EmbeddableValuedModelPart getInitializingModelPart() {
public EmbeddableValuedModelPart getInitializedPart() {
return embeddedModelPartDescriptor;
}

View File

@ -25,7 +25,7 @@ public class CompositeAssembler implements DomainResultAssembler {
@Override
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
return initializer.getInitializingModelPart().getJavaTypeDescriptor();
return initializer.getInitializedPart().getJavaTypeDescriptor();
}
@Override

View File

@ -17,7 +17,7 @@ import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.internal.domain.AbstractFetchParent;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CompositeResultMappingNode;
import org.hibernate.sql.results.spi.CompositeResultNode;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
@ -29,7 +29,7 @@ import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class CompositeFetch extends AbstractFetchParent implements CompositeResultMappingNode, Fetch {
public class CompositeFetch extends AbstractFetchParent implements CompositeResultNode, Fetch {
private final FetchParent fetchParent;
private final FetchTiming fetchTiming;
private final boolean nullable;
@ -41,7 +41,7 @@ public class CompositeFetch extends AbstractFetchParent implements CompositeResu
FetchTiming fetchTiming,
boolean nullable,
DomainResultCreationState creationState) {
super( embeddedPartDescriptor, navigablePath );
super( embeddedPartDescriptor.getEmbeddableTypeDescriptor(), navigablePath );
this.fetchParent = fetchParent;
this.fetchTiming = fetchTiming;
@ -50,7 +50,7 @@ public class CompositeFetch extends AbstractFetchParent implements CompositeResu
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
getNavigablePath(),
np -> {
final TableGroupJoin tableGroupJoin = getFetchContainer().createTableGroupJoin(
final TableGroupJoin tableGroupJoin = getReferencedMappingContainer().createTableGroupJoin(
getNavigablePath(),
creationState.getSqlAstCreationState()
.getFromClauseAccess()
@ -77,23 +77,23 @@ public class CompositeFetch extends AbstractFetchParent implements CompositeResu
}
@Override
public EmbeddableValuedModelPart getFetchContainer() {
return (EmbeddableValuedModelPart) super.getFetchContainer();
public EmbeddableMappingType getFetchContainer() {
return (EmbeddableMappingType) super.getFetchContainer();
}
@Override
public EmbeddableValuedModelPart getReferencedMappingContainer() {
return getFetchContainer();
return getFetchContainer().getEmbeddedValueMapping();
}
@Override
public Fetchable getFetchedMapping() {
return getFetchContainer();
return getReferencedMappingContainer();
}
@Override
public EmbeddableMappingType getReferencedMappingType() {
return getFetchContainer().getEmbeddableTypeDescriptor();
return getFetchContainer();
}
@Override

View File

@ -10,7 +10,7 @@ import java.util.function.Consumer;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CompositeInitializer;
import org.hibernate.sql.results.spi.CompositeResultMappingNode;
import org.hibernate.sql.results.spi.CompositeResultNode;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Initializer;
@ -22,7 +22,7 @@ public class CompositeFetchInitializer
implements CompositeInitializer {
public CompositeFetchInitializer(
FetchParentAccess fetchParentAccess,
CompositeResultMappingNode resultDescriptor,
CompositeResultNode resultDescriptor,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
super( resultDescriptor, fetchParentAccess, initializerConsumer, creationState );

View File

@ -17,7 +17,7 @@ import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.internal.domain.AbstractFetchParent;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CompositeResultMappingNode;
import org.hibernate.sql.results.spi.CompositeResultNode;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
@ -27,7 +27,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class CompositeResult<T> extends AbstractFetchParent implements CompositeResultMappingNode, DomainResult<T> {
public class CompositeResult<T> extends AbstractFetchParent implements CompositeResultNode, DomainResult<T> {
private final String resultVariable;
public CompositeResult(
@ -35,7 +35,7 @@ public class CompositeResult<T> extends AbstractFetchParent implements Composite
EmbeddableValuedModelPart modelPart,
String resultVariable,
DomainResultCreationState creationState) {
super( modelPart, navigablePath );
super( modelPart.getEmbeddableTypeDescriptor(), navigablePath );
this.resultVariable = resultVariable;
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
@ -68,8 +68,8 @@ public class CompositeResult<T> extends AbstractFetchParent implements Composite
}
@Override
public EmbeddableValuedModelPart getFetchContainer() {
return (EmbeddableValuedModelPart) super.getFetchContainer();
public EmbeddableMappingType getFetchContainer() {
return (EmbeddableMappingType) super.getFetchContainer();
}
@Override
@ -79,12 +79,12 @@ public class CompositeResult<T> extends AbstractFetchParent implements Composite
@Override
public EmbeddableMappingType getReferencedMappingType() {
return getFetchContainer().getEmbeddableTypeDescriptor();
return getFetchContainer();
}
@Override
public EmbeddableValuedModelPart getReferencedMappingContainer() {
return getFetchContainer();
return getFetchContainer().getEmbeddedValueMapping();
}
@Override

View File

@ -9,7 +9,7 @@ package org.hibernate.sql.results.internal.domain.composite;
import java.util.function.Consumer;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.CompositeResultMappingNode;
import org.hibernate.sql.results.spi.CompositeResultNode;
import org.hibernate.sql.results.spi.Initializer;
/**
@ -17,7 +17,7 @@ import org.hibernate.sql.results.spi.Initializer;
*/
public class CompositeRootInitializer extends AbstractCompositeInitializer {
public CompositeRootInitializer(
CompositeResultMappingNode resultDescriptor,
CompositeResultNode resultDescriptor,
Consumer<Initializer> initializerConsumer,
AssemblerCreationState creationState) {
super( resultDescriptor, null, initializerConsumer, creationState );

View File

@ -9,7 +9,6 @@ package org.hibernate.sql.results.internal.domain.entity;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.internal.SingularAssociationAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResultAssembler;
@ -23,16 +22,16 @@ import org.hibernate.sql.results.spi.Initializer;
/**
* @author Andrea Boriero
*/
public abstract class AbstractEntityFecth implements Fetch {
public abstract class AbstractEntityFetch implements Fetch {
private final FetchParent fetchParent;
private final SingularAssociationAttributeMapping fetchedAttribute;
private final Fetchable fetchedAttribute;
private final NavigablePath navigablePath;
private final boolean nullable;
private final LockMode lockMode;
public AbstractEntityFecth(
public AbstractEntityFetch(
FetchParent fetchParent,
SingularAssociationAttributeMapping fetchedAttribute,
Fetchable fetchedAttribute,
NavigablePath navigablePath,
boolean nullable,
LockMode lockMode) {

View File

@ -323,8 +323,6 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
session.getPersistenceContext().getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
}
}
// todo (6.0) : subselect fetches similar to batch fetch handling above
}
@Override

View File

@ -48,7 +48,7 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
NavigablePath navigablePath,
EntityMappingType targetType,
DomainResultCreationState creationState) {
super( referencedModelPart, navigablePath );
super( referencedModelPart.getEntityMappingType(), navigablePath );
this.referencedModelPart = referencedModelPart;
this.lockMode = lockMode;
this.targetType = targetType;

View File

@ -24,7 +24,7 @@ import org.hibernate.sql.results.spi.Initializer;
* @author Andrea Boriero
* @author Steve Ebersole
*/
public class DelayedEntityFetchImpl extends AbstractEntityFecth {
public class DelayedEntityFetchImpl extends AbstractEntityFetch {
private final DomainResult result;

View File

@ -10,26 +10,26 @@ import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.internal.SingularAssociationAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.EntityInitializer;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Andrea Boriero
* @author Steve Ebersole
*/
public class EntityFetch extends AbstractEntityFecth {
public class EntityFetch extends AbstractEntityFetch {
private final EntityResultImpl entityResult;
public EntityFetch(
FetchParent fetchParent,
SingularAssociationAttributeMapping fetchedAttribute,
Fetchable fetchedAttribute,
LockMode lockMode,
boolean nullable,
NavigablePath navigablePath,
@ -38,7 +38,7 @@ public class EntityFetch extends AbstractEntityFecth {
entityResult = new EntityResultImpl(
navigablePath,
(EntityValuedModelPart) fetchedAttribute.getMappedTypeDescriptor(),
(EntityValuedModelPart) fetchedAttribute,
null,
creationState
);

View File

@ -7,6 +7,8 @@
package org.hibernate.sql.results.spi;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.sql.exec.spi.ExecutionContext;
@ -16,7 +18,12 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
* @author Steve Ebersole
*/
public interface CollectionInitializer extends Initializer {
CollectionPersister getInitializingCollectionDescriptor();
@Override
PluralAttributeMapping getInitializedPart();
default CollectionPersister getInitializingCollectionDescriptor() {
return getInitializedPart().getCollectionDescriptor();
}
PersistentCollection getCollectionInstance();

View File

@ -0,0 +1,13 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.results.spi;
/**
* @author Steve Ebersole
*/
public interface CollectionResultNode extends ResultSetMappingNode {
}

View File

@ -13,7 +13,8 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
* @author Steve Ebersole
*/
public interface CompositeInitializer extends Initializer, FetchParentAccess {
EmbeddableValuedModelPart getInitializingModelPart();
@Override
EmbeddableValuedModelPart getInitializedPart();
Object getCompositeInstance();

View File

@ -14,7 +14,7 @@ import org.hibernate.query.NavigablePath;
/**
* @author Steve Ebersole
*/
public interface CompositeResultMappingNode extends ResultSetMappingNode, FetchParent {
public interface CompositeResultNode extends ResultSetMappingNode, FetchParent {
@Override
default NavigablePath getNavigablePath() {
return null;

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.sql.results.spi;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.persister.entity.EntityPersister;
/**
@ -14,6 +15,10 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Steve Ebersole
*/
public interface EntityInitializer extends Initializer, FetchParentAccess {
@Override
default ModelPart getInitializedPart() {
return getEntityDescriptor();
}
/**
* Get the descriptor for the type of entity being initialized

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.sql.results.spi;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.exec.spi.ExecutionContext;
@ -17,10 +18,12 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
* @author Steve Ebersole
*/
public interface Initializer {
Object getInitializedInstance();
NavigablePath getNavigablePath();
ModelPart getInitializedPart();
Object getInitializedInstance();
/**
* Step 1 - Resolve the key value for this initializer for the current
* row.

View File

@ -29,6 +29,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
import org.hibernate.sql.results.internal.domain.collection.DelayedCollectionFetch;
import org.hibernate.sql.results.internal.domain.collection.EagerCollectionFetch;
@ -39,13 +40,10 @@ import org.hibernate.sql.results.spi.Fetch;
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 org.hamcrest.CoreMatchers;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
@ -68,20 +66,23 @@ public class MappedFetchTests {
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
final DomainMetamodel domainModel = sessionFactory.getDomainModel();
final EntityPersister rootEntityDescriptor = domainModel.getEntityDescriptor( RootEntity.class );
final MetamodelSelectBuilderProcess.SqlAstDescriptor sqlAstDescriptor = MetamodelSelectBuilderProcess.createSelect(
sessionFactory,
final SelectStatement sqlAst = MetamodelSelectBuilderProcess.createSelect(
rootEntityDescriptor,
null,
rootEntityDescriptor.getIdentifierMapping(),
null,
1,
LoadQueryInfluencers.NONE,
LockOptions.NONE
LockOptions.NONE,
jdbcParameter -> {
},
sessionFactory
);
assertThat( sqlAstDescriptor.getSqlAst().getDomainResultDescriptors().size(), is( 1 ) );
assertThat( sqlAst.getDomainResultDescriptors().size(), is( 1 ) );
final DomainResult domainResult = sqlAstDescriptor.getSqlAst().getDomainResultDescriptors().get( 0 );
final DomainResult domainResult = sqlAst.getDomainResultDescriptors().get( 0 );
assertThat( domainResult, instanceOf( EntityResult.class ) );
final EntityResult entityResult = (EntityResult) domainResult;
@ -105,7 +106,7 @@ public class MappedFetchTests {
assertThat( simpleEntitiesFetch, instanceOf( DelayedCollectionFetch.class ) );
final QuerySpec querySpec = sqlAstDescriptor.getSqlAst().getQuerySpec();
final QuerySpec querySpec = sqlAst.getQuerySpec();
final TableGroup tableGroup = querySpec.getFromClause().getRoots().get( 0 );
assertThat( tableGroup.getModelPart(), is( rootEntityDescriptor ) );

View File

@ -6,21 +6,7 @@
*/
package org.hibernate.orm.test.metamodel.mapping.collections;
import java.util.EnumSet;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.SourceType;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.spi.CommandAcceptanceException;
import org.hibernate.tool.schema.spi.ExceptionHandler;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.ScriptTargetOutput;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope;
@ -81,68 +67,7 @@ public class MapOperationTests {
// uber hacky temp way:
final ServiceRegistryImplementor serviceRegistry = scope.getSessionFactory().getServiceRegistry();
final SchemaManagementTool schemaTool = serviceRegistry.getService( SchemaManagementTool.class );
final ExecutionOptions executionOptions = new ExecutionOptions() {
@Override
public Map getConfigurationValues() {
return scope.getSessionFactory().getProperties();
}
@Override
public boolean shouldManageNamespaces() {
return false;
}
@Override
public ExceptionHandler getExceptionHandler() {
return new ExceptionHandler() {
@Override
public void handleException(CommandAcceptanceException exception) {
throw exception;
}
};
}
};
final SourceDescriptor sourceDescriptor = new SourceDescriptor() {
@Override
public SourceType getSourceType() {
return SourceType.METADATA;
}
@Override
public ScriptSourceInput getScriptSourceInput() {
return null;
}
};
final TargetDescriptor targetDescriptor = new TargetDescriptor() {
@Override
public EnumSet<TargetType> getTargetTypes() {
return EnumSet.of( TargetType.DATABASE );
}
@Override
public ScriptTargetOutput getScriptTargetOutput() {
return null;
}
};
schemaTool.getSchemaDropper( scope.getSessionFactory().getProperties() ).doDrop(
domainModelScope.getDomainModel(),
executionOptions,
sourceDescriptor,
targetDescriptor
);
schemaTool.getSchemaCreator( scope.getSessionFactory().getProperties() ).doCreation(
domainModelScope.getDomainModel(),
executionOptions,
sourceDescriptor,
targetDescriptor
);
TempDropDataHelper.cleanDatabaseSchema( scope, domainModelScope );
}
@Test

View File

@ -0,0 +1,139 @@
/*
* 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.metamodel.mapping.collections;
import org.hibernate.Hibernate;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.ServiceRegistry;
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 static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Steve Ebersole
*/
@SuppressWarnings("WeakerAccess")
@DomainModel(
annotatedClasses = {
SimpleEntity.class,
EntityContainingSets.class,
SomeStuff.class
}
)
@ServiceRegistry
@SessionFactory
public class SetOperationTests {
@BeforeEach
public void createData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingSets entity = new EntityContainingSets( 1, "first-map-entity" );
entity.addBasic( "a value" );
entity.addBasic( "another value" );
entity.addEnum( EnumValue.ONE );
entity.addEnum( EnumValue.TWO );
entity.addConvertedBasic( EnumValue.ONE );
entity.addConvertedBasic( EnumValue.THREE );
entity.addComponent( new SomeStuff( "the stuff - 1", "the stuff - 2" ) );
entity.addComponent( new SomeStuff( "other stuff - 1", "other stuff - 2" ) );
session.save( entity );
}
);
}
@AfterEach
public void dropData(SessionFactoryScope scope, DomainModelScope domainModelScope) {
// scope.inTransaction(
// session -> {
// final EntityContainingSets entity = session.load( EntityContainingSets.class, 1 );
// session.delete( entity );
// }
// );
TempDropDataHelper.cleanDatabaseSchema( scope, domainModelScope );
}
@Test
public void testLoad(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingSets entity = session.load( EntityContainingSets.class, 1 );
assertThat( entity, is( notNullValue() ) );
assertThat( Hibernate.isInitialized( entity ), is( false ) );
}
);
}
@Test
public void testGet(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingSets entity = session.get( EntityContainingSets.class, 1 );
assertThat( entity, is( notNullValue() ) );
assertThat( Hibernate.isInitialized( entity ), is( true ) );
assertThat( Hibernate.isInitialized( entity.getSetOfBasics() ), is( false ) );
}
);
}
@Test
public void testSqmFetch(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingSets entity = session.createQuery(
"select e from EntityContainingSets e join fetch e.setOfBasics",
EntityContainingSets.class
).getSingleResult();
assert Hibernate.isInitialized( entity.getSetOfBasics() );
assert entity.getSetOfBasics().size() == 2;
}
);
}
@Test
@FailureExpected( reason = "FlushVisitor collection handling" )
public void testDeleteWithElementCollectionData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingSets entity = session.load( EntityContainingSets.class, 1 );
session.delete( entity );
}
);
}
@Test
@FailureExpected( reason = "not sure" )
public void testTriggerFetch(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityContainingSets entity = session.get( EntityContainingSets.class, 1 );
assert ! Hibernate.isInitialized( entity.getSetOfBasics() );
assertThat( entity.getSetOfBasics().size(), is( 2 ) );
assert Hibernate.isInitialized( entity.getSetOfBasics() );
assert ! Hibernate.isInitialized( entity.getSetOfEnums() );
}
);
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.metamodel.mapping.collections;
import java.util.EnumSet;
import java.util.Map;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.SourceType;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.spi.CommandAcceptanceException;
import org.hibernate.tool.schema.spi.ExceptionHandler;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.ScriptTargetOutput;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;
import org.hibernate.testing.orm.junit.DomainModelScope;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
/**
* @author Steve Ebersole
*/
public class TempDropDataHelper {
static void cleanDatabaseSchema(SessionFactoryScope scope, DomainModelScope domainModelScope) {
final ServiceRegistryImplementor serviceRegistry = scope.getSessionFactory().getServiceRegistry();
final SchemaManagementTool schemaTool = serviceRegistry.getService( SchemaManagementTool.class );
final ExecutionOptions executionOptions = new ExecutionOptions() {
@Override
public Map getConfigurationValues() {
return scope.getSessionFactory().getProperties();
}
@Override
public boolean shouldManageNamespaces() {
return false;
}
@Override
public ExceptionHandler getExceptionHandler() {
return new ExceptionHandler() {
@Override
public void handleException(CommandAcceptanceException exception) {
throw exception;
}
};
}
};
final SourceDescriptor sourceDescriptor = new SourceDescriptor() {
@Override
public SourceType getSourceType() {
return SourceType.METADATA;
}
@Override
public ScriptSourceInput getScriptSourceInput() {
return null;
}
};
final TargetDescriptor targetDescriptor = new TargetDescriptor() {
@Override
public EnumSet<TargetType> getTargetTypes() {
return EnumSet.of( TargetType.DATABASE );
}
@Override
public ScriptTargetOutput getScriptTargetOutput() {
return null;
}
};
schemaTool.getSchemaDropper( scope.getSessionFactory().getProperties() ).doDrop(
domainModelScope.getDomainModel(),
executionOptions,
sourceDescriptor,
targetDescriptor
);
schemaTool.getSchemaCreator( scope.getSessionFactory().getProperties() ).doCreation(
domainModelScope.getDomainModel(),
executionOptions,
sourceDescriptor,
targetDescriptor
);
}
}

View File

@ -24,6 +24,8 @@ log4j.logger.org.hibernate.orm.query.hql=debug
log4j.logger.org.hibernate.tool.hbm2ddl=trace
log4j.logger.org.hibernate.testing.cache=debug
log4j.logger.org.hibernate.orm.sql.results.loading.collection=trace
# SQL Logging - HHH-6833
log4j.logger.org.hibernate.SQL=debug