mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-10 13:14:50 +00:00
HHH-16468 Don't create fetch for _identifierMapper anymore
This commit is contained in:
parent
5a3d60f508
commit
3ee817008a
@ -689,7 +689,7 @@ private BiConsumer<Fetchable, Boolean> createFetchableBiConsumer(
|
|||||||
LoaderSqlAstCreationState creationState,
|
LoaderSqlAstCreationState creationState,
|
||||||
ImmutableFetchList.Builder fetches) {
|
ImmutableFetchList.Builder fetches) {
|
||||||
return (fetchable, isKeyFetchable) -> {
|
return (fetchable, isKeyFetchable) -> {
|
||||||
if ( !fetchable.isSelectable() ) {
|
if ( !fetchable.isSelectable() || fetchable.getPartName().equals( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.hibernate.cache.MutableCacheKeyBuilder;
|
import org.hibernate.cache.MutableCacheKeyBuilder;
|
||||||
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
@ -35,8 +36,15 @@
|
|||||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.internal.NonAggregatedIdentifierMappingFetch;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.internal.NonAggregatedIdentifierMappingResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "non-aggregated" composite identifier.
|
* A "non-aggregated" composite identifier.
|
||||||
@ -316,6 +324,38 @@ public void applySqlSelections(
|
|||||||
identifierValueMapper.applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer );
|
identifierValueMapper.applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> DomainResult<T> createDomainResult(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
TableGroup tableGroup,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
return new NonAggregatedIdentifierMappingResult<>(
|
||||||
|
navigablePath,
|
||||||
|
this,
|
||||||
|
resultVariable,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Fetch generateFetch(
|
||||||
|
FetchParent fetchParent,
|
||||||
|
NavigablePath fetchablePath,
|
||||||
|
FetchTiming fetchTiming,
|
||||||
|
boolean selected,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
return new NonAggregatedIdentifierMappingFetch(
|
||||||
|
fetchablePath,
|
||||||
|
this,
|
||||||
|
fetchParent,
|
||||||
|
fetchTiming,
|
||||||
|
selected,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// EmbeddableValuedFetchable
|
// EmbeddableValuedFetchable
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ public ImmutableFetchList visitFetches(FetchParent fetchParent) {
|
|||||||
|
|
||||||
private Consumer<Fetchable> createFetchableConsumer(FetchParent fetchParent, ImmutableFetchList.Builder fetches) {
|
private Consumer<Fetchable> createFetchableConsumer(FetchParent fetchParent, ImmutableFetchList.Builder fetches) {
|
||||||
return fetchable -> {
|
return fetchable -> {
|
||||||
if ( !fetchable.isSelectable() ) {
|
if ( !fetchable.isSelectable() || fetchable.getPartName().equals( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String fetchableName = fetchable.getFetchableName();
|
final String fetchableName = fetchable.getFetchableName();
|
||||||
|
@ -7144,7 +7144,7 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Fetch createFetch(FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) {
|
private Fetch createFetch(FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) {
|
||||||
if ( !fetchable.isSelectable() ) {
|
if ( !fetchable.isSelectable() || fetchable.getPartName().equals( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath( fetchable );
|
final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath( fetchable );
|
||||||
|
@ -9,17 +9,12 @@
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
||||||
import org.hibernate.metamodel.internal.StandardEmbeddableInstantiator;
|
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
import org.hibernate.metamodel.mapping.VirtualModelPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
|
||||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
|
||||||
import org.hibernate.metamodel.spi.ValueAccess;
|
import org.hibernate.metamodel.spi.ValueAccess;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
@ -37,41 +32,27 @@
|
|||||||
import org.hibernate.sql.results.internal.NullValueAssembler;
|
import org.hibernate.sql.results.internal.NullValueAssembler;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
|
||||||
import static java.lang.Boolean.FALSE;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||||
import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY;
|
import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess implements EmbeddableInitializer,
|
public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess
|
||||||
ValueAccess {
|
implements EmbeddableInitializer, ValueAccess {
|
||||||
private static final Object NULL_MARKER = new Object() {
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Composite NULL_MARKER";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private final EmbeddableValuedModelPart embedded;
|
private final EmbeddableValuedModelPart embedded;
|
||||||
private final EmbeddableMappingType representationEmbeddable;
|
|
||||||
private final EmbeddableRepresentationStrategy representationStrategy;
|
|
||||||
private final FetchParentAccess fetchParentAccess;
|
private final FetchParentAccess fetchParentAccess;
|
||||||
private final boolean createEmptyCompositesEnabled;
|
private final boolean createEmptyCompositesEnabled;
|
||||||
private final SessionFactoryImplementor sessionFactory;
|
private final SessionFactoryImplementor sessionFactory;
|
||||||
|
|
||||||
private final List<DomainResultAssembler<?>> assemblers;
|
private final List<DomainResultAssembler<?>> assemblers;
|
||||||
|
|
||||||
private final boolean usesStandardInstantiation;
|
|
||||||
|
|
||||||
// per-row state
|
// per-row state
|
||||||
private final Object[] rowState;
|
private final Object[] rowState;
|
||||||
private Boolean stateAllNull;
|
private State state = State.INITIAL;
|
||||||
private Boolean stateInjected;
|
|
||||||
protected Object compositeInstance;
|
protected Object compositeInstance;
|
||||||
private boolean isParentInitialized;
|
|
||||||
private RowProcessingState wrappedProcessingState;
|
private RowProcessingState wrappedProcessingState;
|
||||||
|
|
||||||
public AbstractEmbeddableInitializer(
|
public AbstractEmbeddableInitializer(
|
||||||
@ -83,16 +64,6 @@ public AbstractEmbeddableInitializer(
|
|||||||
this.fetchParentAccess = fetchParentAccess;
|
this.fetchParentAccess = fetchParentAccess;
|
||||||
|
|
||||||
final EmbeddableMappingType embeddableTypeDescriptor = embedded.getEmbeddableTypeDescriptor();
|
final EmbeddableMappingType embeddableTypeDescriptor = embedded.getEmbeddableTypeDescriptor();
|
||||||
if ( embedded instanceof CompositeIdentifierMapping ) {
|
|
||||||
representationEmbeddable = ( (CompositeIdentifierMapping) embedded ).getMappedIdEmbeddableTypeDescriptor();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
representationEmbeddable = embeddableTypeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.representationStrategy = representationEmbeddable.getRepresentationStrategy();
|
|
||||||
this.usesStandardInstantiation = representationStrategy.getInstantiator() instanceof StandardEmbeddableInstantiator;
|
|
||||||
|
|
||||||
final int size = embeddableTypeDescriptor.getNumberOfFetchables();
|
final int size = embeddableTypeDescriptor.getNumberOfFetchables();
|
||||||
this.rowState = new Object[ size ];
|
this.rowState = new Object[ size ];
|
||||||
this.assemblers = arrayList( size );
|
this.assemblers = arrayList( size );
|
||||||
@ -140,7 +111,7 @@ public NavigablePath getNavigablePath() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getCompositeInstance() {
|
public Object getCompositeInstance() {
|
||||||
return compositeInstance == NULL_MARKER ? null : compositeInstance;
|
return state == State.NULL ? null : compositeInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -174,16 +145,6 @@ public void resolveInstance(RowProcessingState processingState) {
|
|||||||
public void initializeInstance(RowProcessingState processingState) {
|
public void initializeInstance(RowProcessingState processingState) {
|
||||||
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Initializing composite instance [%s]", navigablePath );
|
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Initializing composite instance [%s]", navigablePath );
|
||||||
|
|
||||||
if ( compositeInstance == NULL_MARKER ) {
|
|
||||||
// we already know it is null
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isParentInstanceNull() ) {
|
|
||||||
compositeInstance = NULL_MARKER;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IMPORTANT: This method might be called multiple times for the same role for a single row.
|
// IMPORTANT: This method might be called multiple times for the same role for a single row.
|
||||||
// EmbeddableAssembler calls it as part of its `#assemble` and the RowReader calls it
|
// EmbeddableAssembler calls it as part of its `#assemble` and the RowReader calls it
|
||||||
// as part of its normal Initializer handling
|
// as part of its normal Initializer handling
|
||||||
@ -203,74 +164,66 @@ public void initializeInstance(RowProcessingState processingState) {
|
|||||||
// critical in the case we have custom constructor injection. Luckily, custom instantiation
|
// critical in the case we have custom constructor injection. Luckily, custom instantiation
|
||||||
// is only allowed for non-key usage atm, so we leverage that distinction here
|
// is only allowed for non-key usage atm, so we leverage that distinction here
|
||||||
|
|
||||||
if ( !usesStandardInstantiation ) {
|
switch ( state ) {
|
||||||
// we have a custom instantiator
|
case NULL:
|
||||||
if ( compositeInstance != null ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
case INITIAL:
|
||||||
}
|
if ( isParentInstanceNull() ) {
|
||||||
if ( isParentInitialized ) {
|
state = State.NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to possibly wrap the processing state if the embeddable is within an aggregate
|
// We need to possibly wrap the processing state if the embeddable is within an aggregate
|
||||||
if ( wrappedProcessingState == null ) {
|
if ( wrappedProcessingState == null ) {
|
||||||
wrappedProcessingState = wrapProcessingState( processingState );
|
wrappedProcessingState = wrapProcessingState( processingState );
|
||||||
}
|
}
|
||||||
initializeInstance( );
|
extractRowState( wrappedProcessingState );
|
||||||
}
|
prepareCompositeInstance( wrappedProcessingState );
|
||||||
|
if ( state == State.NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
notifyResolutionListeners( compositeInstance );
|
||||||
|
case EXTRACTED:
|
||||||
|
if ( embedded.getParentInjectionAttributePropertyAccess() != null || embedded instanceof VirtualModelPart ) {
|
||||||
|
handleParentInjection( wrappedProcessingState );
|
||||||
|
|
||||||
private void initializeInstance() {
|
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( compositeInstance );
|
||||||
stateInjected = false;
|
// If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual
|
||||||
extractRowState( wrappedProcessingState );
|
// and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution
|
||||||
prepareCompositeInstance( wrappedProcessingState );
|
if ( lazyInitializer != null ) {
|
||||||
if ( isParentInitialized ) {
|
final Initializer parentInitializer = wrappedProcessingState.resolveInitializer( navigablePath.getParent() );
|
||||||
return;
|
if ( parentInitializer != this ) {
|
||||||
}
|
( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> {
|
||||||
if ( !stateInjected ) {
|
embedded.getEmbeddableTypeDescriptor().setValues( entity, rowState );
|
||||||
handleParentInjection( wrappedProcessingState );
|
state = State.INJECTED;
|
||||||
}
|
} );
|
||||||
|
}
|
||||||
if ( compositeInstance != NULL_MARKER ) {
|
else {
|
||||||
notifyResolutionListeners( compositeInstance );
|
// At this point, createEmptyCompositesEnabled is always true, so we generate
|
||||||
|
// the composite instance.
|
||||||
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( compositeInstance );
|
//
|
||||||
// If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual
|
// NOTE: `valuesAccess` is set to null to indicate that all values are null,
|
||||||
// and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution
|
// as opposed to returning the all-null value array. the instantiator
|
||||||
if ( lazyInitializer != null ) {
|
// interprets that as the values are not known or were all null.
|
||||||
final Initializer parentInitializer = wrappedProcessingState.resolveInitializer( navigablePath.getParent() );
|
final Object target = embedded.getEmbeddableTypeDescriptor().getRepresentationStrategy()
|
||||||
if ( parentInitializer != this ) {
|
.getInstantiator()
|
||||||
( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> {
|
.instantiate( this, sessionFactory);
|
||||||
representationEmbeddable.setValues( entity, rowState );
|
state = State.INJECTED;
|
||||||
stateInjected = true;
|
lazyInitializer.setImplementation( target );
|
||||||
} );
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
embedded.getEmbeddableTypeDescriptor().setValues( compositeInstance, rowState );
|
||||||
|
state = State.INJECTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// At this point, createEmptyCompositesEnabled is always true, so we generate
|
state = State.INJECTED;
|
||||||
// the composite instance.
|
|
||||||
//
|
|
||||||
// NOTE: `valuesAccess` is set to null to indicate that all values are null,
|
|
||||||
// as opposed to returning the all-null value array. the instantiator
|
|
||||||
// interprets that as the values are not known or were all null.
|
|
||||||
final Object target = representationStrategy
|
|
||||||
.getInstantiator()
|
|
||||||
.instantiate( this, sessionFactory);
|
|
||||||
stateInjected = true;
|
|
||||||
lazyInitializer.setImplementation( target );
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ( stateAllNull == FALSE && stateInjected != TRUE ) {
|
|
||||||
representationEmbeddable.setValues( compositeInstance, rowState );
|
|
||||||
stateInjected = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareCompositeInstance(RowProcessingState processingState) {
|
private void prepareCompositeInstance(RowProcessingState processingState) {
|
||||||
if ( compositeInstance != null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Virtual model parts use the owning entity as container which the fetch parent access provides.
|
// Virtual model parts use the owning entity as container which the fetch parent access provides.
|
||||||
// For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
|
// For an identifier or foreign key this is called during the resolveKey phase of the fetch parent,
|
||||||
// so we can't use the fetch parent access in that case.
|
// so we can't use the fetch parent access in that case.
|
||||||
@ -282,7 +235,6 @@ private void prepareCompositeInstance(RowProcessingState processingState) {
|
|||||||
compositeInstance = fetchParentAccess.getInitializedInstance();
|
compositeInstance = fetchParentAccess.getInitializedInstance();
|
||||||
EntityInitializer entityInitializer = fetchParentAccess.asEntityInitializer();
|
EntityInitializer entityInitializer = fetchParentAccess.asEntityInitializer();
|
||||||
if ( entityInitializer != null && entityInitializer.isEntityInitialized() ) {
|
if ( entityInitializer != null && entityInitializer.isEntityInitialized() ) {
|
||||||
this.isParentInitialized = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,7 +242,6 @@ private void prepareCompositeInstance(RowProcessingState processingState) {
|
|||||||
if ( compositeInstance == null ) {
|
if ( compositeInstance == null ) {
|
||||||
compositeInstance = createCompositeInstance(
|
compositeInstance = createCompositeInstance(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
representationStrategy,
|
|
||||||
sessionFactory
|
sessionFactory
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -326,7 +277,7 @@ private boolean isParentInstanceNull() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void extractRowState(RowProcessingState processingState) {
|
private void extractRowState(RowProcessingState processingState) {
|
||||||
stateAllNull = true;
|
boolean stateAllNull = true;
|
||||||
final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|
final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|
||||||
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
|
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
|
||||||
|| EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() );
|
|| EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() );
|
||||||
@ -353,51 +304,23 @@ else if ( isKey ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyMapsId( processingState );
|
state = stateAllNull ? State.NULL : State.EXTRACTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyMapsId(RowProcessingState processingState) {
|
private Object createCompositeInstance(NavigablePath navigablePath, SessionFactoryImplementor sessionFactory) {
|
||||||
final SharedSessionContractImplementor session = processingState.getSession();
|
if ( state == State.NULL ) {
|
||||||
if ( embedded instanceof CompositeIdentifierMapping ) {
|
// todo (6.0) : should we initialize the composite instance if it has a parent attribute?
|
||||||
final CompositeIdentifierMapping cid = (CompositeIdentifierMapping) embedded;
|
// if ( !createEmptyCompositesEnabled && embedded.getParentInjectionAttributePropertyAccess() == null ) {
|
||||||
final EmbeddableMappingType mappedIdEmbeddable = cid.getMappedIdEmbeddableTypeDescriptor();
|
if ( !createEmptyCompositesEnabled ) {
|
||||||
if ( cid.hasContainingClass() ) {
|
return null;
|
||||||
final EmbeddableMappingType virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor();
|
|
||||||
if ( virtualIdEmbeddable == mappedIdEmbeddable ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtualIdEmbeddable.forEachAttributeMapping(
|
|
||||||
(position, virtualIdAttribute) -> {
|
|
||||||
final AttributeMapping mappedIdAttribute = mappedIdEmbeddable.getAttributeMapping( position );
|
|
||||||
|
|
||||||
if ( virtualIdAttribute instanceof ToOneAttributeMapping
|
|
||||||
&& !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) {
|
|
||||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute;
|
|
||||||
final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
|
|
||||||
final Object associationKey = fkDescriptor.getAssociationKeyFromSide(
|
|
||||||
rowState[position],
|
|
||||||
toOneAttributeMapping.getSideNature().inverse(),
|
|
||||||
session
|
|
||||||
);
|
|
||||||
rowState[position] = associationKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private Object createCompositeInstance(
|
final Object instance = embedded.getEmbeddableTypeDescriptor()
|
||||||
NavigablePath navigablePath,
|
.getRepresentationStrategy()
|
||||||
EmbeddableRepresentationStrategy representationStrategy,
|
.getInstantiator()
|
||||||
SessionFactoryImplementor sessionFactory) {
|
.instantiate( this, sessionFactory );
|
||||||
if ( !createEmptyCompositesEnabled && stateAllNull == TRUE ) {
|
state = State.EXTRACTED;
|
||||||
return NULL_MARKER;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Object instance = representationStrategy.getInstantiator().instantiate( this, sessionFactory );
|
|
||||||
stateInjected = true;
|
|
||||||
|
|
||||||
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Created composite instance [%s] : %s", navigablePath, instance );
|
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Created composite instance [%s] : %s", navigablePath, instance );
|
||||||
|
|
||||||
@ -406,12 +329,12 @@ private Object createCompositeInstance(
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getValues() {
|
public Object[] getValues() {
|
||||||
return stateAllNull ? null : rowState;
|
return state == State.NULL ? null : rowState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T getValue(int i, Class<T> clazz) {
|
public <T> T getValue(int i, Class<T> clazz) {
|
||||||
return stateAllNull ? null : clazz.cast( rowState[i] );
|
return state == State.NULL ? null : clazz.cast( rowState[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -420,17 +343,6 @@ public Object getOwner() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleParentInjection(RowProcessingState processingState) {
|
private void handleParentInjection(RowProcessingState processingState) {
|
||||||
// todo (6.0) : should we initialize the composite instance if we get here and it is null (not NULL_MARKER)?
|
|
||||||
|
|
||||||
// we want to avoid injection for `NULL_MARKER`
|
|
||||||
if ( compositeInstance == null || compositeInstance == NULL_MARKER ) {
|
|
||||||
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf(
|
|
||||||
"Skipping parent injection for null embeddable [%s]",
|
|
||||||
navigablePath
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PropertyAccess parentInjectionAccess = embedded.getParentInjectionAttributePropertyAccess();
|
final PropertyAccess parentInjectionAccess = embedded.getParentInjectionAttributePropertyAccess();
|
||||||
if ( parentInjectionAccess == null ) {
|
if ( parentInjectionAccess == null ) {
|
||||||
// embeddable defined no parent injection
|
// embeddable defined no parent injection
|
||||||
@ -504,9 +416,7 @@ private Object determineParentInstance(RowProcessingState processingState) {
|
|||||||
@Override
|
@Override
|
||||||
public void finishUpRow(RowProcessingState rowProcessingState) {
|
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||||
compositeInstance = null;
|
compositeInstance = null;
|
||||||
stateAllNull = null;
|
state = State.INITIAL;
|
||||||
stateInjected = null;
|
|
||||||
isParentInitialized = false;
|
|
||||||
wrappedProcessingState = null;
|
wrappedProcessingState = null;
|
||||||
|
|
||||||
clearResolutionListeners();
|
clearResolutionListeners();
|
||||||
@ -516,4 +426,10 @@ public void finishUpRow(RowProcessingState rowProcessingState) {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + "(" + navigablePath + ") : `" + getInitializedPart().getJavaType().getJavaTypeClass() + "`";
|
return getClass().getSimpleName() + "(" + navigablePath + ") : `" + getInitializedPart().getJavaType().getJavaTypeClass() + "`";
|
||||||
}
|
}
|
||||||
|
enum State {
|
||||||
|
INITIAL,
|
||||||
|
EXTRACTED,
|
||||||
|
NULL,
|
||||||
|
INJECTED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
|
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||||
|
import org.hibernate.metamodel.spi.ValueAccess;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
|
import org.hibernate.spi.EntityIdentifierNavigablePath;
|
||||||
|
import org.hibernate.spi.NavigablePath;
|
||||||
|
import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||||
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableLoadingLogger;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||||
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
|
import org.hibernate.sql.results.internal.NullValueAssembler;
|
||||||
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
|
||||||
|
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||||
|
import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public abstract class AbstractNonAggregatedIdentifierMappingInitializer extends AbstractFetchParentAccess
|
||||||
|
implements EmbeddableInitializer, ValueAccess {
|
||||||
|
|
||||||
|
private final NavigablePath navigablePath;
|
||||||
|
private final NonAggregatedIdentifierMapping embedded;
|
||||||
|
private final EmbeddableMappingType representationEmbeddable;
|
||||||
|
private final EmbeddableRepresentationStrategy representationStrategy;
|
||||||
|
private final FetchParentAccess fetchParentAccess;
|
||||||
|
private final SessionFactoryImplementor sessionFactory;
|
||||||
|
|
||||||
|
private final List<DomainResultAssembler<?>> assemblers;
|
||||||
|
private final boolean hasIdClass;
|
||||||
|
|
||||||
|
|
||||||
|
// per-row state
|
||||||
|
private final Object[] virtualIdState;
|
||||||
|
private final Object[] idClassState;
|
||||||
|
private State state = State.INITIAL;
|
||||||
|
protected Object compositeInstance;
|
||||||
|
|
||||||
|
public AbstractNonAggregatedIdentifierMappingInitializer(
|
||||||
|
EmbeddableResultGraphNode resultDescriptor,
|
||||||
|
FetchParentAccess fetchParentAccess,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
this.navigablePath = resultDescriptor.getNavigablePath();
|
||||||
|
this.embedded = (NonAggregatedIdentifierMapping) resultDescriptor.getReferencedMappingContainer();
|
||||||
|
this.fetchParentAccess = fetchParentAccess;
|
||||||
|
|
||||||
|
final EmbeddableMappingType virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor();
|
||||||
|
this.representationEmbeddable = embedded.getMappedIdEmbeddableTypeDescriptor();
|
||||||
|
this.representationStrategy = representationEmbeddable.getRepresentationStrategy();
|
||||||
|
this.hasIdClass = embedded.hasContainingClass() && virtualIdEmbeddable != representationEmbeddable;
|
||||||
|
|
||||||
|
final int size = virtualIdEmbeddable.getNumberOfFetchables();
|
||||||
|
this.virtualIdState = new Object[ size ];
|
||||||
|
this.idClassState = new Object[ size ];
|
||||||
|
this.assemblers = arrayList( size );
|
||||||
|
|
||||||
|
this.sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
|
||||||
|
initializeAssemblers( resultDescriptor, creationState, virtualIdEmbeddable );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void initializeAssemblers(
|
||||||
|
EmbeddableResultGraphNode resultDescriptor,
|
||||||
|
AssemblerCreationState creationState,
|
||||||
|
EmbeddableMappingType embeddableTypeDescriptor) {
|
||||||
|
final int size = embeddableTypeDescriptor.getNumberOfFetchables();
|
||||||
|
for ( int i = 0; i < size; i++ ) {
|
||||||
|
final Fetchable stateArrayContributor = embeddableTypeDescriptor.getFetchable( i );
|
||||||
|
final Fetch fetch = resultDescriptor.findFetch( stateArrayContributor );
|
||||||
|
|
||||||
|
final DomainResultAssembler<?> stateAssembler = fetch == null
|
||||||
|
? new NullValueAssembler<>( stateArrayContributor.getJavaType() )
|
||||||
|
: fetch.createAssembler( this, creationState );
|
||||||
|
|
||||||
|
assemblers.add( stateAssembler );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EmbeddableValuedModelPart getInitializedPart() {
|
||||||
|
return embedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FetchParentAccess getFetchParentAccess() {
|
||||||
|
return fetchParentAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavigablePath getNavigablePath() {
|
||||||
|
return navigablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCompositeInstance() {
|
||||||
|
return compositeInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FetchParentAccess findFirstEntityDescriptorAccess() {
|
||||||
|
if ( fetchParentAccess == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fetchParentAccess.findFirstEntityDescriptorAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityInitializer findFirstEntityInitializer() {
|
||||||
|
final FetchParentAccess firstEntityDescriptorAccess = findFirstEntityDescriptorAccess();
|
||||||
|
if ( firstEntityDescriptorAccess == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return firstEntityDescriptorAccess.findFirstEntityInitializer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveKey(RowProcessingState processingState) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveInstance(RowProcessingState processingState) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeInstance(RowProcessingState processingState) {
|
||||||
|
EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Initializing composite instance [%s]", navigablePath );
|
||||||
|
|
||||||
|
switch ( state ) {
|
||||||
|
case NULL:
|
||||||
|
return;
|
||||||
|
case INITIAL:
|
||||||
|
// If we don't have an id class and this is a find by id lookup, we just use that instance
|
||||||
|
if ( !hasIdClass && processingState.getEntityId() != null
|
||||||
|
&& navigablePath.getParent().getParent() == null
|
||||||
|
&& navigablePath instanceof EntityIdentifierNavigablePath ) {
|
||||||
|
compositeInstance = processingState.getEntityId();
|
||||||
|
state = State.INJECTED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We need to possibly wrap the processing state if the embeddable is within an aggregate
|
||||||
|
processingState = wrapProcessingState( processingState );
|
||||||
|
extractRowState( processingState );
|
||||||
|
if ( state == State.NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compositeInstance = representationStrategy.getInstantiator().instantiate( this, sessionFactory );
|
||||||
|
}
|
||||||
|
case EXTRACTED:
|
||||||
|
final Object parentInstance;
|
||||||
|
if ( fetchParentAccess != null && ( parentInstance = fetchParentAccess.getInitializedInstance() ) != null ) {
|
||||||
|
notifyResolutionListeners( compositeInstance );
|
||||||
|
|
||||||
|
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( parentInstance );
|
||||||
|
// If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual
|
||||||
|
// and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution
|
||||||
|
if ( lazyInitializer != null ) {
|
||||||
|
final Initializer parentInitializer = processingState.resolveInitializer( navigablePath.getParent() );
|
||||||
|
if ( parentInitializer != this ) {
|
||||||
|
( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> {
|
||||||
|
embedded.getVirtualIdEmbeddable().setValues( entity, virtualIdState );
|
||||||
|
state = State.INJECTED;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert false;
|
||||||
|
// At this point, createEmptyCompositesEnabled is always true, so we generate
|
||||||
|
// the composite instance.
|
||||||
|
//
|
||||||
|
// NOTE: `valuesAccess` is set to null to indicate that all values are null,
|
||||||
|
// as opposed to returning the all-null value array. the instantiator
|
||||||
|
// interprets that as the values are not known or were all null.
|
||||||
|
final Object target = representationStrategy
|
||||||
|
.getInstantiator()
|
||||||
|
.instantiate( this, sessionFactory);
|
||||||
|
|
||||||
|
state = State.INJECTED;
|
||||||
|
lazyInitializer.setImplementation( target );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
embedded.getVirtualIdEmbeddable().setValues( parentInstance, virtualIdState );
|
||||||
|
state = State.INJECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractRowState(RowProcessingState processingState) {
|
||||||
|
state = State.NULL;
|
||||||
|
for ( int i = 0; i < assemblers.size(); i++ ) {
|
||||||
|
final DomainResultAssembler<?> assembler = assemblers.get( i );
|
||||||
|
final Object contributorValue = assembler.assemble(
|
||||||
|
processingState,
|
||||||
|
processingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( contributorValue == null ) {
|
||||||
|
// This is a key and there is a null part, the whole thing has to be turned into null
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( contributorValue == BATCH_PROPERTY ) {
|
||||||
|
virtualIdState[i] = null;
|
||||||
|
idClassState[i] = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
virtualIdState[i] = contributorValue;
|
||||||
|
idClassState[i] = contributorValue;
|
||||||
|
if ( hasIdClass ) {
|
||||||
|
final AttributeMapping virtualIdAttribute = embedded.getEmbeddableTypeDescriptor().getAttributeMapping( i );
|
||||||
|
final AttributeMapping mappedIdAttribute = representationEmbeddable.getAttributeMapping( i );
|
||||||
|
if ( virtualIdAttribute instanceof ToOneAttributeMapping
|
||||||
|
&& !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) {
|
||||||
|
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute;
|
||||||
|
final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
|
||||||
|
final Object associationKey = fkDescriptor.getAssociationKeyFromSide(
|
||||||
|
virtualIdState[i],
|
||||||
|
toOneAttributeMapping.getSideNature().inverse(),
|
||||||
|
processingState.getSession()
|
||||||
|
);
|
||||||
|
idClassState[i] = associationKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = State.EXTRACTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getValues() {
|
||||||
|
return state == State.NULL ? null : idClassState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getValue(int i, Class<T> clazz) {
|
||||||
|
return state == State.NULL ? null : clazz.cast( idClassState[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getOwner() {
|
||||||
|
return fetchParentAccess.getInitializedInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||||
|
compositeInstance = null;
|
||||||
|
state = State.INITIAL;
|
||||||
|
|
||||||
|
clearResolutionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "(" + navigablePath + ") : `" + getInitializedPart().getJavaType().getJavaTypeClass() + "`";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
INITIAL,
|
||||||
|
EXTRACTED,
|
||||||
|
NULL,
|
||||||
|
INJECTED
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@
|
|||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.AbstractFetchParent;
|
import org.hibernate.sql.results.graph.AbstractFetchParent;
|
||||||
@ -98,7 +99,9 @@ public DomainResultAssembler<T> createResultAssembler(
|
|||||||
final EmbeddableInitializer initializer = creationState.resolveInitializer(
|
final EmbeddableInitializer initializer = creationState.resolveInitializer(
|
||||||
getNavigablePath(),
|
getNavigablePath(),
|
||||||
getReferencedModePart(),
|
getReferencedModePart(),
|
||||||
() -> new EmbeddableResultInitializer( this, parentAccess, creationState )
|
() -> getReferencedModePart() instanceof NonAggregatedIdentifierMapping
|
||||||
|
? new NonAggregatedIdentifierMappingResultInitializer( this, null, creationState )
|
||||||
|
: new EmbeddableResultInitializer( this, null, creationState )
|
||||||
).asEmbeddableInitializer();
|
).asEmbeddableInitializer();
|
||||||
|
|
||||||
assert initializer != null;
|
assert initializer != null;
|
||||||
|
@ -6,13 +6,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.sql.results.graph.embeddable.internal;
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.CollectionKey;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
|
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
||||||
import org.hibernate.sql.exec.spi.Callback;
|
import org.hibernate.sql.exec.spi.Callback;
|
||||||
import org.hibernate.sql.results.graph.Initializer;
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
||||||
|
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
import org.hibernate.sql.results.spi.RowReader;
|
import org.hibernate.sql.results.spi.RowReader;
|
||||||
@ -89,8 +93,43 @@ public QueryParameterBindings getQueryParameterBindings() {
|
|||||||
return processingState.getQueryParameterBindings();
|
return processingState.getQueryParameterBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrollResult(){
|
||||||
|
return processingState.isScrollResult();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Callback getCallback() {
|
public Callback getCallback() {
|
||||||
return processingState.getCallback();
|
return processingState.getCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CollectionKey getCollectionKey() {
|
||||||
|
return processingState.getCollectionKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityInstance() {
|
||||||
|
return processingState.getEntityInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityId() {
|
||||||
|
return processingState.getEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||||
|
processingState.registerLoadingEntityEntry( entityKey, entry );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterStatement(LogicalConnectionImplementor logicalConnection) {
|
||||||
|
processingState.afterStatement( logicalConnection );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasQueryExecutionToBeAddedToStatistics() {
|
||||||
|
return processingState.hasQueryExecutionToBeAddedToStatistics();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
|
import org.hibernate.spi.NavigablePath;
|
||||||
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||||
|
|
||||||
|
public class NonAggregatedIdentifierMappingFetch extends EmbeddableFetchImpl {
|
||||||
|
public NonAggregatedIdentifierMappingFetch(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
NonAggregatedIdentifierMapping embeddedPartDescriptor,
|
||||||
|
FetchParent fetchParent,
|
||||||
|
FetchTiming fetchTiming,
|
||||||
|
boolean hasTableGroup,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
super( navigablePath, embeddedPartDescriptor, fetchParent, fetchTiming, hasTableGroup, creationState );
|
||||||
|
}
|
||||||
|
|
||||||
|
public NonAggregatedIdentifierMappingFetch(EmbeddableFetchImpl original) {
|
||||||
|
super( original );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Initializer buildEmbeddableFetchInitializer(
|
||||||
|
FetchParentAccess parentAccess,
|
||||||
|
EmbeddableResultGraphNode embeddableFetch,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
return new NonAggregatedIdentifierMappingFetchInitializer( parentAccess, this, creationState );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class NonAggregatedIdentifierMappingFetchInitializer
|
||||||
|
extends AbstractNonAggregatedIdentifierMappingInitializer {
|
||||||
|
public NonAggregatedIdentifierMappingFetchInitializer(
|
||||||
|
FetchParentAccess fetchParentAccess,
|
||||||
|
EmbeddableResultGraphNode resultDescriptor,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
super( resultDescriptor, fetchParentAccess, creationState );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getParentKey() {
|
||||||
|
return findFirstEntityDescriptorAccess().getParentKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||||
|
import org.hibernate.spi.NavigablePath;
|
||||||
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||||
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
|
||||||
|
|
||||||
|
public class NonAggregatedIdentifierMappingResult<T> extends EmbeddableResultImpl<T> {
|
||||||
|
public NonAggregatedIdentifierMappingResult(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
NonAggregatedIdentifierMapping modelPart,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
super( navigablePath, modelPart, resultVariable, creationState );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomainResultAssembler<T> createResultAssembler(
|
||||||
|
FetchParentAccess parentAccess,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
final EmbeddableInitializer initializer = creationState.resolveInitializer(
|
||||||
|
getNavigablePath().append( "{embeddable_result}" ),
|
||||||
|
getReferencedModePart(),
|
||||||
|
() -> new NonAggregatedIdentifierMappingResultInitializer(
|
||||||
|
this,
|
||||||
|
parentAccess,
|
||||||
|
creationState
|
||||||
|
)
|
||||||
|
).asEmbeddableInitializer();
|
||||||
|
|
||||||
|
assert initializer != null;
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
return new EmbeddableAssembler( initializer );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||||
|
|
||||||
|
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class NonAggregatedIdentifierMappingResultInitializer extends AbstractNonAggregatedIdentifierMappingInitializer {
|
||||||
|
public NonAggregatedIdentifierMappingResultInitializer(
|
||||||
|
EmbeddableResultGraphNode resultDescriptor,
|
||||||
|
FetchParentAccess parentAccess,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
super( resultDescriptor, parentAccess, creationState );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getParentKey() {
|
||||||
|
return findFirstEntityDescriptorAccess().getParentKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "EmbeddableResultInitializer(" + getNavigablePath() + ")";
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,7 @@
|
|||||||
import org.hibernate.sql.results.graph.Fetch;
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
import org.hibernate.sql.results.graph.Initializer;
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
|
||||||
|
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableAssembler;
|
||||||
import org.hibernate.sql.results.internal.NullValueAssembler;
|
import org.hibernate.sql.results.internal.NullValueAssembler;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||||
@ -524,6 +525,13 @@ else if ( entityInstanceFromExecutionContext != null ) {
|
|||||||
// look to see if another initializer from a parent load context or an earlier
|
// look to see if another initializer from a parent load context or an earlier
|
||||||
// initializer is already loading the entity
|
// initializer is already loading the entity
|
||||||
entityInstance = resolveInstance( entityIdentifier, existingLoadingEntry, rowProcessingState );
|
entityInstance = resolveInstance( entityIdentifier, existingLoadingEntry, rowProcessingState );
|
||||||
|
if ( isOwningInitializer && !isInitialized && identifierAssembler instanceof EmbeddableAssembler ) {
|
||||||
|
// If this is the owning initializer and the returned object is not initialized,
|
||||||
|
// this means that the entity instance was just instantiated.
|
||||||
|
// In this case, we want to call "assemble" and hence "initializeInstance" on the initializer
|
||||||
|
// for possibly non-aggregated identifier mappings, so inject the virtual id representation
|
||||||
|
identifierAssembler.assemble( rowProcessingState );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upgradeLockMode( rowProcessingState );
|
upgradeLockMode( rowProcessingState );
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
package org.hibernate.sql.results.internal;
|
package org.hibernate.sql.results.internal;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.CollectionKey;
|
import org.hibernate.engine.spi.CollectionKey;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
|
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
@ -15,6 +17,7 @@
|
|||||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
import org.hibernate.sql.results.graph.Initializer;
|
import org.hibernate.sql.results.graph.Initializer;
|
||||||
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
||||||
|
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesCacheHit;
|
import org.hibernate.sql.results.jdbc.internal.JdbcValuesCacheHit;
|
||||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl;
|
import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
|
||||||
@ -138,6 +141,11 @@ public QueryParameterBindings getQueryParameterBindings() {
|
|||||||
return getJdbcValuesSourceProcessingState().getExecutionContext().getQueryParameterBindings();
|
return getJdbcValuesSourceProcessingState().getExecutionContext().getQueryParameterBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrollResult(){
|
||||||
|
return executionContext.isScrollResult();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Callback getCallback() {
|
public Callback getCallback() {
|
||||||
return executionContext.getCallback();
|
return executionContext.getCallback();
|
||||||
@ -148,6 +156,31 @@ public CollectionKey getCollectionKey() {
|
|||||||
return executionContext.getCollectionKey();
|
return executionContext.getCollectionKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityInstance() {
|
||||||
|
return executionContext.getEntityInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityId() {
|
||||||
|
return executionContext.getEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||||
|
executionContext.registerLoadingEntityEntry( entityKey, entry );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterStatement(LogicalConnectionImplementor logicalConnection) {
|
||||||
|
executionContext.afterStatement( logicalConnection );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasQueryExecutionToBeAddedToStatistics() {
|
||||||
|
return executionContext.hasQueryExecutionToBeAddedToStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Initializer resolveInitializer(NavigablePath path) {
|
public Initializer resolveInitializer(NavigablePath path) {
|
||||||
return this.initializers.resolveInitializer( path );
|
return this.initializers.resolveInitializer( path );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user