HHH-13725: Implement ToOne Associations support
This commit is contained in:
parent
f1bf079122
commit
8a196bc0e5
|
@ -35,6 +35,7 @@ import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.internal.domain.entity.DelayedEntityFetchImpl;
|
import org.hibernate.sql.results.internal.domain.entity.DelayedEntityFetchImpl;
|
||||||
import org.hibernate.sql.results.internal.domain.entity.EntityFetch;
|
import org.hibernate.sql.results.internal.domain.entity.EntityFetch;
|
||||||
|
import org.hibernate.sql.results.internal.domain.entity.SelectEntityFetchImpl;
|
||||||
import org.hibernate.sql.results.spi.DomainResult;
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.spi.Fetch;
|
import org.hibernate.sql.results.spi.Fetch;
|
||||||
|
@ -47,10 +48,12 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
implements EntityValuedModelPart, TableGroupJoinProducer {
|
implements EntityValuedModelPart, TableGroupJoinProducer {
|
||||||
private final String sqlAliasStem;
|
private final String sqlAliasStem;
|
||||||
private final boolean isNullable;
|
private final boolean isNullable;
|
||||||
|
private final boolean referringPrimaryKey;
|
||||||
|
final protected boolean unwrapProxy;
|
||||||
|
private final String referencedPropertyName;
|
||||||
|
|
||||||
private ForeignKeyDescriptor foreignKeyDescriptor;
|
private ForeignKeyDescriptor foreignKeyDescriptor;
|
||||||
|
|
||||||
private final String referencedPropertyName;
|
|
||||||
private final boolean referringPrimaryKey;
|
|
||||||
|
|
||||||
public SingularAssociationAttributeMapping(
|
public SingularAssociationAttributeMapping(
|
||||||
String name,
|
String name,
|
||||||
|
@ -74,6 +77,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
this.isNullable = value.isNullable();
|
this.isNullable = value.isNullable();
|
||||||
referencedPropertyName = value.getReferencedPropertyName();
|
referencedPropertyName = value.getReferencedPropertyName();
|
||||||
referringPrimaryKey = value.isReferenceToPrimaryKey();
|
referringPrimaryKey = value.isReferenceToPrimaryKey();
|
||||||
|
unwrapProxy = value.isUnwrapProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
|
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
|
||||||
|
@ -144,7 +148,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
fetchParent,
|
fetchParent,
|
||||||
this,
|
this,
|
||||||
lockMode,
|
lockMode,
|
||||||
!selected,
|
true,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
|
@ -160,14 +164,23 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
.createDomainResult( fetchablePath, lhsTableGroup, null, creationState );
|
.createDomainResult( fetchablePath, lhsTableGroup, null, creationState );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( fetchTiming == FetchTiming.IMMEDIATE && !selected ) {
|
||||||
|
return new SelectEntityFetchImpl(
|
||||||
|
fetchParent,
|
||||||
|
this,
|
||||||
|
lockMode,
|
||||||
|
fetchablePath,
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return new DelayedEntityFetchImpl(
|
return new DelayedEntityFetchImpl(
|
||||||
fetchParent,
|
fetchParent,
|
||||||
this,
|
this,
|
||||||
lockMode,
|
lockMode,
|
||||||
isNullable,
|
isNullable,
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
result,
|
result
|
||||||
creationState
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,4 +293,11 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNullable() {
|
||||||
|
return isNullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUnwrapProxy() {
|
||||||
|
return unwrapProxy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.engine.profile.FetchProfile;
|
||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
|
import org.hibernate.mapping.ToOne;
|
||||||
import org.hibernate.persister.collection.AbstractCollectionPersister;
|
import org.hibernate.persister.collection.AbstractCollectionPersister;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -119,6 +120,14 @@ public final class FetchStrategyHelper {
|
||||||
FetchStyle style,
|
FetchStyle style,
|
||||||
AssociationType type,
|
AssociationType type,
|
||||||
SessionFactoryImplementor sessionFactory) {
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
if ( type instanceof ToOne ) {
|
||||||
|
if ( ( (ToOne) type ).isLazy() ) {
|
||||||
|
return FetchTiming.DELAYED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return FetchTiming.IMMEDIATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
switch ( style ) {
|
switch ( style ) {
|
||||||
case JOIN: {
|
case JOIN: {
|
||||||
return FetchTiming.IMMEDIATE;
|
return FetchTiming.IMMEDIATE;
|
||||||
|
|
|
@ -229,7 +229,10 @@ public class StandardSqmSelectTranslator
|
||||||
// because it
|
// because it
|
||||||
assert getFromClauseIndex().getTableGroup( fetchablePath ) != null;
|
assert getFromClauseIndex().getTableGroup( fetchablePath ) != null;
|
||||||
|
|
||||||
fetchTiming = FetchTiming.IMMEDIATE;
|
//
|
||||||
|
if ( fetchedJoin.isFetched() ) {
|
||||||
|
fetchTiming = FetchTiming.IMMEDIATE;
|
||||||
|
}
|
||||||
joined = true;
|
joined = true;
|
||||||
alias = fetchedJoin.getExplicitAlias();
|
alias = fetchedJoin.getExplicitAlias();
|
||||||
lockMode = determineLockMode( alias );
|
lockMode = determineLockMode( alias );
|
||||||
|
|
|
@ -26,7 +26,7 @@ import org.hibernate.sql.results.spi.Initializer;
|
||||||
*/
|
*/
|
||||||
public class DelayedEntityFetchImpl extends AbstractEntityFecth {
|
public class DelayedEntityFetchImpl extends AbstractEntityFecth {
|
||||||
|
|
||||||
private DomainResult result;
|
private final DomainResult result;
|
||||||
|
|
||||||
public DelayedEntityFetchImpl(
|
public DelayedEntityFetchImpl(
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
|
@ -34,8 +34,7 @@ public class DelayedEntityFetchImpl extends AbstractEntityFecth {
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
boolean nullable,
|
boolean nullable,
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
DomainResult result,
|
DomainResult result) {
|
||||||
DomainResultCreationState creationState) {
|
|
||||||
super( fetchParent, fetchedAttribute, navigablePath, nullable, lockMode );
|
super( fetchParent, fetchedAttribute, navigablePath, nullable, lockMode );
|
||||||
this.result = result;
|
this.result = result;
|
||||||
}
|
}
|
||||||
|
@ -47,10 +46,7 @@ public class DelayedEntityFetchImpl extends AbstractEntityFecth {
|
||||||
AssemblerCreationState creationState) {
|
AssemblerCreationState creationState) {
|
||||||
final SingularAssociationAttributeMapping fetchedAttribute = (SingularAssociationAttributeMapping) getFetchedMapping();
|
final SingularAssociationAttributeMapping fetchedAttribute = (SingularAssociationAttributeMapping) getFetchedMapping();
|
||||||
return new DelayedEntityFetchInitializer(
|
return new DelayedEntityFetchInitializer(
|
||||||
parentAccess,
|
|
||||||
getNavigablePath(),
|
getNavigablePath(),
|
||||||
fetchedAttribute.getMappedFetchStrategy(),
|
|
||||||
getLockMode(),
|
|
||||||
(EntityPersister) fetchedAttribute.getMappedTypeDescriptor(),
|
(EntityPersister) fetchedAttribute.getMappedTypeDescriptor(),
|
||||||
result.createResultAssembler( collector, creationState )
|
result.createResultAssembler( collector, creationState )
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,16 +8,12 @@ package org.hibernate.sql.results.internal.domain.entity;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
|
||||||
import org.hibernate.engine.FetchTiming;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.internal.domain.AbstractFetchParentAccess;
|
import org.hibernate.sql.results.internal.domain.AbstractFetchParentAccess;
|
||||||
import org.hibernate.sql.results.spi.DomainResultAssembler;
|
import org.hibernate.sql.results.spi.DomainResultAssembler;
|
||||||
import org.hibernate.sql.results.spi.EntityInitializer;
|
import org.hibernate.sql.results.spi.EntityInitializer;
|
||||||
import org.hibernate.sql.results.spi.FetchParentAccess;
|
|
||||||
import org.hibernate.sql.results.spi.RowProcessingState;
|
import org.hibernate.sql.results.spi.RowProcessingState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,31 +22,20 @@ import org.hibernate.sql.results.spi.RowProcessingState;
|
||||||
*/
|
*/
|
||||||
public class DelayedEntityFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
public class DelayedEntityFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
||||||
|
|
||||||
private final FetchParentAccess parentAccess;
|
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private FetchStrategy mappedFetchedStrategy;
|
|
||||||
private LockMode lockMode;
|
|
||||||
private final EntityPersister concreteDescriptor;
|
private final EntityPersister concreteDescriptor;
|
||||||
private final DomainResultAssembler fkValueAssembler;
|
private final DomainResultAssembler identifierAssembler;
|
||||||
|
|
||||||
|
|
||||||
private Object entityInstance;
|
private Object entityInstance;
|
||||||
private Object fkValue;
|
private Object identifier;
|
||||||
|
|
||||||
protected DelayedEntityFetchInitializer(
|
protected DelayedEntityFetchInitializer(
|
||||||
FetchParentAccess parentAccess,
|
|
||||||
NavigablePath fetchedNavigable,
|
NavigablePath fetchedNavigable,
|
||||||
FetchStrategy mappedFetchedStrategy,
|
|
||||||
LockMode lockMode,
|
|
||||||
EntityPersister concreteDescriptor,
|
EntityPersister concreteDescriptor,
|
||||||
DomainResultAssembler fkValueAssembler
|
DomainResultAssembler identifierAssembler) {
|
||||||
) {
|
|
||||||
this.parentAccess = parentAccess;
|
|
||||||
this.navigablePath = fetchedNavigable;
|
this.navigablePath = fetchedNavigable;
|
||||||
this.mappedFetchedStrategy = mappedFetchedStrategy;
|
|
||||||
this.lockMode = lockMode;
|
|
||||||
this.concreteDescriptor = concreteDescriptor;
|
this.concreteDescriptor = concreteDescriptor;
|
||||||
this.fkValueAssembler = fkValueAssembler;
|
this.identifierAssembler = identifierAssembler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,34 +50,32 @@ public class DelayedEntityFetchInitializer extends AbstractFetchParentAccess imp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveInstance(RowProcessingState rowProcessingState) {
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
fkValue = fkValueAssembler.assemble( rowProcessingState );
|
if ( entityInstance != null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
identifier = identifierAssembler.assemble( rowProcessingState );
|
||||||
|
|
||||||
// todo (6.0) : technically the entity could be managed or cached already. who/what handles that?
|
// todo (6.0) : technically the entity could be managed or cached already. who/what handles that?
|
||||||
|
|
||||||
// todo (6.0) : could also be getting loaded elsewhere (LoadingEntityEntry)
|
// todo (6.0) : could also be getting loaded elsewhere (LoadingEntityEntry)
|
||||||
if ( fkValue == null ) {
|
if ( identifier == null ) {
|
||||||
// todo (6.0) : check this is the correct behaviour
|
// todo (6.0) : check this is the correct behaviour
|
||||||
entityInstance = null;
|
entityInstance = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( mappedFetchedStrategy.getTiming() != FetchTiming.IMMEDIATE ) {
|
if ( concreteDescriptor.hasProxy() ) {
|
||||||
if ( concreteDescriptor.hasProxy() ) {
|
entityInstance = concreteDescriptor.createProxy(
|
||||||
entityInstance = concreteDescriptor.createProxy(
|
identifier,
|
||||||
fkValue,
|
rowProcessingState.getSession()
|
||||||
rowProcessingState.getSession()
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
else if ( concreteDescriptor
|
|
||||||
.getBytecodeEnhancementMetadata()
|
|
||||||
.isEnhancedForLazyLoading() ) {
|
|
||||||
entityInstance = concreteDescriptor.instantiate(
|
|
||||||
fkValue,
|
|
||||||
rowProcessingState.getSession()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else if ( concreteDescriptor
|
||||||
entityInstance = rowProcessingState.getSession().immediateLoad( concreteDescriptor.getEntityName(), fkValue );
|
.getBytecodeEnhancementMetadata()
|
||||||
|
.isEnhancedForLazyLoading() ) {
|
||||||
|
entityInstance = concreteDescriptor.instantiate(
|
||||||
|
identifier,
|
||||||
|
rowProcessingState.getSession()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyParentResolutionListeners( entityInstance );
|
notifyParentResolutionListeners( entityInstance );
|
||||||
|
@ -107,7 +90,7 @@ public class DelayedEntityFetchInitializer extends AbstractFetchParentAccess imp
|
||||||
@Override
|
@Override
|
||||||
public void finishUpRow(RowProcessingState rowProcessingState) {
|
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||||
entityInstance = null;
|
entityInstance = null;
|
||||||
fkValue = null;
|
identifier = null;
|
||||||
|
|
||||||
clearParentResolutionListeners();
|
clearParentResolutionListeners();
|
||||||
}
|
}
|
||||||
|
@ -136,4 +119,5 @@ public class DelayedEntityFetchInitializer extends AbstractFetchParentAccess imp
|
||||||
super.registerResolutionListener( listener );
|
super.registerResolutionListener( listener );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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.entity;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.SingularAssociationAttributeMapping;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.results.spi.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
|
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.Initializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class SelectEntityFetchImpl extends AbstractEntityFecth {
|
||||||
|
|
||||||
|
private final DomainResult result;
|
||||||
|
|
||||||
|
public SelectEntityFetchImpl(
|
||||||
|
FetchParent fetchParent,
|
||||||
|
SingularAssociationAttributeMapping fetchedAttribute,
|
||||||
|
LockMode lockMode,
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
DomainResult result) {
|
||||||
|
super( fetchParent, fetchedAttribute, navigablePath, fetchedAttribute.isNullable(), lockMode );
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EntityInitializer getEntityInitializer(
|
||||||
|
FetchParentAccess parentAccess,
|
||||||
|
Consumer<Initializer> collector,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
final SingularAssociationAttributeMapping fetchedAttribute = (SingularAssociationAttributeMapping) getFetchedMapping();
|
||||||
|
|
||||||
|
return new SelectEntityInitializer(
|
||||||
|
getNavigablePath(),
|
||||||
|
(EntityPersister) fetchedAttribute.getMappedTypeDescriptor(),
|
||||||
|
result.createResultAssembler( collector, creationState ),
|
||||||
|
fetchedAttribute.isUnwrapProxy(),
|
||||||
|
fetchedAttribute.isNullable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* 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.entity;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.results.internal.domain.AbstractFetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultAssembler;
|
||||||
|
import org.hibernate.sql.results.spi.EntityInitializer;
|
||||||
|
import org.hibernate.sql.results.spi.RowProcessingState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class SelectEntityInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
||||||
|
|
||||||
|
private final NavigablePath navigablePath;
|
||||||
|
private final EntityPersister concreteDescriptor;
|
||||||
|
private final DomainResultAssembler identifierAssembler;
|
||||||
|
private final boolean unwrapProxy;
|
||||||
|
private final boolean nullable;
|
||||||
|
|
||||||
|
private Object entityInstance;
|
||||||
|
|
||||||
|
protected SelectEntityInitializer(
|
||||||
|
NavigablePath fetchedNavigable,
|
||||||
|
EntityPersister concreteDescriptor,
|
||||||
|
DomainResultAssembler identifierAssembler,
|
||||||
|
boolean unwrapProxy,
|
||||||
|
boolean nullable) {
|
||||||
|
this.navigablePath = fetchedNavigable;
|
||||||
|
this.concreteDescriptor = concreteDescriptor;
|
||||||
|
this.identifierAssembler = identifierAssembler;
|
||||||
|
this.unwrapProxy = unwrapProxy;
|
||||||
|
this.nullable = nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NavigablePath getNavigablePath() {
|
||||||
|
return navigablePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveKey(RowProcessingState rowProcessingState) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeInstance(RowProcessingState rowProcessingState) {
|
||||||
|
if ( entityInstance != null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object id = identifierAssembler.assemble( rowProcessingState );
|
||||||
|
if ( id == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String entityName = concreteDescriptor.getEntityName();
|
||||||
|
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
||||||
|
|
||||||
|
entityInstance = session.internalLoad(
|
||||||
|
entityName,
|
||||||
|
id,
|
||||||
|
false,
|
||||||
|
nullable
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( entityInstance instanceof HibernateProxy ) {
|
||||||
|
final boolean isProxyUnwrapEnabled = unwrapProxy && concreteDescriptor.isInstrumented();
|
||||||
|
|
||||||
|
( (HibernateProxy) entityInstance ).getHibernateLazyInitializer().setUnwrap( isProxyUnwrapEnabled );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishUpRow(RowProcessingState rowProcessingState) {
|
||||||
|
entityInstance = null;
|
||||||
|
|
||||||
|
clearParentResolutionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityPersister getEntityDescriptor() {
|
||||||
|
return concreteDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntityInstance() {
|
||||||
|
return entityInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getParentKey() {
|
||||||
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerResolutionListener(Consumer<Object> listener) {
|
||||||
|
if ( entityInstance != null ) {
|
||||||
|
listener.accept( entityInstance );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
super.registerResolutionListener( listener );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -103,6 +103,7 @@ public class ManyToOneTest {
|
||||||
|
|
||||||
AnotherSimpleEntity anotherSimpleEntity = otherEntity.getAnotherSimpleEntity();
|
AnotherSimpleEntity anotherSimpleEntity = otherEntity.getAnotherSimpleEntity();
|
||||||
assertTrue( Hibernate.isInitialized( anotherSimpleEntity ) );
|
assertTrue( Hibernate.isInitialized( anotherSimpleEntity ) );
|
||||||
|
assertThat( anotherSimpleEntity.getName(), is( "other" ) );
|
||||||
|
|
||||||
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
||||||
}
|
}
|
||||||
|
@ -118,6 +119,7 @@ public class ManyToOneTest {
|
||||||
OtherEntity otherEntity = session.
|
OtherEntity otherEntity = session.
|
||||||
createQuery( "from OtherEntity o join o.simpleEntity", OtherEntity.class )
|
createQuery( "from OtherEntity o join o.simpleEntity", OtherEntity.class )
|
||||||
.uniqueResult();
|
.uniqueResult();
|
||||||
|
// the eager association is null
|
||||||
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
||||||
assertThat( otherEntity.getName(), is( "Bar" ) );
|
assertThat( otherEntity.getName(), is( "Bar" ) );
|
||||||
|
|
||||||
|
@ -134,8 +136,49 @@ public class ManyToOneTest {
|
||||||
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
OtherEntity otherEntity = session.
|
||||||
|
createQuery( "from OtherEntity", OtherEntity.class )
|
||||||
|
.uniqueResult();
|
||||||
|
AnotherSimpleEntity anotherSimpleEntity = new AnotherSimpleEntity();
|
||||||
|
anotherSimpleEntity.setId( 3 );
|
||||||
|
anotherSimpleEntity.setName( "other" );
|
||||||
|
session.save( anotherSimpleEntity );
|
||||||
|
otherEntity.setAnotherSimpleEntity( anotherSimpleEntity );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
statistics.clear();
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
OtherEntity otherEntity = session.
|
||||||
|
createQuery( "from OtherEntity o join o.simpleEntity", OtherEntity.class )
|
||||||
|
.uniqueResult();
|
||||||
|
// the eager association is not null so a second select is executed
|
||||||
|
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
||||||
|
assertThat( otherEntity.getName(), is( "Bar" ) );
|
||||||
|
|
||||||
|
SimpleEntity simpleEntity = otherEntity.getSimpleEntity();
|
||||||
|
assertFalse( Hibernate.isInitialized( simpleEntity ) );
|
||||||
|
assertThat( simpleEntity, notNullValue() );
|
||||||
|
assertThat( simpleEntity.getName(), is( "Fab" ) );
|
||||||
|
|
||||||
|
assertThat( statistics.getPrepareStatementCount(), is( 3L ) );
|
||||||
|
|
||||||
|
AnotherSimpleEntity anotherSimpleEntity = otherEntity.getAnotherSimpleEntity();
|
||||||
|
assertTrue( Hibernate.isInitialized( anotherSimpleEntity ) );
|
||||||
|
assertThat( anotherSimpleEntity.getName(), is( "other" ) );
|
||||||
|
|
||||||
|
assertThat( statistics.getPrepareStatementCount(), is( 3L ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHQLSelectWithFetchJoin(SessionFactoryScope scope) {
|
public void testHQLSelectWithFetchJoin(SessionFactoryScope scope) {
|
||||||
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
|
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
|
||||||
|
|
Loading…
Reference in New Issue