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:
parent
8a196bc0e5
commit
a6722fe57a
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -55,7 +55,7 @@ public interface EntityMappingType extends ManagedMappingType, Loadable {
|
|||
}
|
||||
|
||||
@Override
|
||||
default String getPathName() {
|
||||
default String getRootPathName() {
|
||||
return getEntityName();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -9,6 +9,5 @@ package org.hibernate.metamodel.mapping;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SingularAttributeMapping
|
||||
extends AttributeMapping, StateArrayContributorMapping {
|
||||
public interface SingularAttributeMapping extends AttributeMapping, StateArrayContributorMapping {
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
||||
|
|
|
@ -763,6 +763,7 @@ public class MappingModelCreationHelper {
|
|||
|
||||
identifierDescriptor = new CollectionIdentifierDescriptorImpl(
|
||||
collectionDescriptor,
|
||||
tableExpression,
|
||||
identifierColumnName,
|
||||
(BasicType) loadableCollection.getIdentifierType()
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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() ) + ")";
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ public class CompositeAssembler implements DomainResultAssembler {
|
|||
|
||||
@Override
|
||||
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
|
||||
return initializer.getInitializingModelPart().getJavaTypeDescriptor();
|
||||
return initializer.getInitializedPart().getJavaTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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) {
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ) );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue