HHH-7841 - Redesign Loader
This commit is contained in:
parent
88d5c02d7f
commit
3f8699c913
|
@ -187,22 +187,31 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
|||
EntityPersister persister,
|
||||
EntityAliases entityAliases,
|
||||
EntityKey entityKey,
|
||||
Object entityInstance) throws SQLException {
|
||||
Object entityInstance) {
|
||||
final Object version = session.getPersistenceContext().getEntry( entityInstance ).getVersion();
|
||||
|
||||
if ( version != null ) {
|
||||
//null version means the object is in the process of being loaded somewhere else in the ResultSet
|
||||
VersionType versionType = persister.getVersionType();
|
||||
Object currentVersion = versionType.nullSafeGet(
|
||||
resultSet,
|
||||
entityAliases.getSuffixedVersionAliases(),
|
||||
session,
|
||||
null
|
||||
);
|
||||
if ( !versionType.isEqual(version, currentVersion) ) {
|
||||
final Object currentVersion;
|
||||
try {
|
||||
currentVersion = versionType.nullSafeGet(
|
||||
resultSet,
|
||||
entityAliases.getSuffixedVersionAliases(),
|
||||
session,
|
||||
null
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw getSession().getFactory().getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Could not read version value from result set"
|
||||
);
|
||||
}
|
||||
|
||||
if ( !versionType.isEqual( version, currentVersion ) ) {
|
||||
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
|
||||
session.getFactory().getStatisticsImplementor()
|
||||
.optimisticFailure( persister.getEntityName() );
|
||||
session.getFactory().getStatisticsImplementor().optimisticFailure( persister.getEntityName() );
|
||||
}
|
||||
throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() );
|
||||
}
|
||||
|
@ -214,19 +223,28 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
|||
final ResultSet rs,
|
||||
final EntityPersister persister,
|
||||
final EntityAliases entityAliases,
|
||||
final EntityKey entityKey) throws SQLException {
|
||||
final EntityKey entityKey) {
|
||||
|
||||
final Loadable loadable = (Loadable) persister;
|
||||
if ( ! loadable.hasSubclasses() ) {
|
||||
return persister.getEntityName();
|
||||
}
|
||||
|
||||
final Object discriminatorValue = loadable.getDiscriminatorType().nullSafeGet(
|
||||
rs,
|
||||
entityAliases.getSuffixedDiscriminatorAlias(),
|
||||
session,
|
||||
null
|
||||
);
|
||||
final Object discriminatorValue;
|
||||
try {
|
||||
discriminatorValue = loadable.getDiscriminatorType().nullSafeGet(
|
||||
rs,
|
||||
entityAliases.getSuffixedDiscriminatorAlias(),
|
||||
session,
|
||||
null
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw getSession().getFactory().getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Could not read discriminator value from ResultSet"
|
||||
);
|
||||
}
|
||||
|
||||
final String result = loadable.getSubclassForDiscriminatorValue( discriminatorValue );
|
||||
|
||||
|
@ -242,6 +260,90 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveEntityKey(EntityKey entityKey, EntityKeyResolutionContext entityKeyContext) {
|
||||
final Object existing = getSession().getEntityUsingInterceptor( entityKey );
|
||||
|
||||
if ( existing != null ) {
|
||||
if ( !entityKeyContext.getEntityPersister().isInstance( existing ) ) {
|
||||
throw new WrongClassException(
|
||||
"loaded object was of wrong class " + existing.getClass(),
|
||||
entityKey.getIdentifier(),
|
||||
entityKeyContext.getEntityPersister().getEntityName()
|
||||
);
|
||||
}
|
||||
|
||||
final LockMode requestedLockMode = entityKeyContext.getLockMode() == null
|
||||
? LockMode.NONE
|
||||
: entityKeyContext.getLockMode();
|
||||
|
||||
if ( requestedLockMode != LockMode.NONE ) {
|
||||
final LockMode currentLockMode = getSession().getPersistenceContext().getEntry( existing ).getLockMode();
|
||||
final boolean isVersionCheckNeeded = entityKeyContext.getEntityPersister().isVersioned()
|
||||
&& currentLockMode.lessThan( requestedLockMode );
|
||||
|
||||
// we don't need to worry about existing version being uninitialized because this block isn't called
|
||||
// by a re-entrant load (re-entrant loads *always* have lock mode NONE)
|
||||
if ( isVersionCheckNeeded ) {
|
||||
//we only check the version when *upgrading* lock modes
|
||||
checkVersion(
|
||||
resultSet,
|
||||
entityKeyContext.getEntityPersister(),
|
||||
entityKeyContext.getEntityAliases(),
|
||||
entityKey,
|
||||
existing
|
||||
);
|
||||
//we need to upgrade the lock mode to the mode requested
|
||||
getSession().getPersistenceContext().getEntry( existing ).setLockMode( requestedLockMode );
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
else {
|
||||
final String concreteEntityTypeName = getConcreteEntityTypeName(
|
||||
resultSet,
|
||||
entityKeyContext.getEntityPersister(),
|
||||
entityKeyContext.getEntityAliases(),
|
||||
entityKey
|
||||
);
|
||||
|
||||
final Object entityInstance = getSession().instantiate(
|
||||
concreteEntityTypeName,
|
||||
entityKey.getIdentifier()
|
||||
);
|
||||
|
||||
//need to hydrate it.
|
||||
|
||||
// grab its state from the ResultSet and keep it in the Session
|
||||
// (but don't yet initialize the object itself)
|
||||
// note that we acquire LockMode.READ even if it was not requested
|
||||
final LockMode requestedLockMode = entityKeyContext.getLockMode() == null
|
||||
? LockMode.NONE
|
||||
: entityKeyContext.getLockMode();
|
||||
final LockMode acquiredLockMode = requestedLockMode == LockMode.NONE
|
||||
? LockMode.READ
|
||||
: requestedLockMode;
|
||||
|
||||
loadFromResultSet(
|
||||
resultSet,
|
||||
entityInstance,
|
||||
concreteEntityTypeName,
|
||||
entityKey,
|
||||
entityKeyContext.getEntityAliases(),
|
||||
acquiredLockMode,
|
||||
entityKeyContext.getEntityPersister(),
|
||||
true,
|
||||
entityKeyContext.getEntityPersister().getEntityMetamodel().getEntityType()
|
||||
);
|
||||
|
||||
// materialize associations (and initialize the object) later
|
||||
registerHydratedEntity( entityKeyContext.getEntityPersister(), entityKey, entityInstance );
|
||||
|
||||
return entityInstance;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFromResultSet(
|
||||
ResultSet resultSet,
|
||||
|
@ -252,7 +354,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
|||
LockMode acquiredLockMode,
|
||||
EntityPersister rootPersister,
|
||||
boolean eagerFetch,
|
||||
EntityType associationType) throws SQLException {
|
||||
EntityType associationType) {
|
||||
|
||||
final Serializable id = entityKey.getIdentifier();
|
||||
|
||||
|
@ -287,17 +389,35 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
|||
entityAliases.getSuffixedPropertyAliases() :
|
||||
entityAliases.getSuffixedPropertyAliases(persister);
|
||||
|
||||
final Object[] values = persister.hydrate(
|
||||
resultSet,
|
||||
id,
|
||||
entityInstance,
|
||||
(Loadable) rootPersister,
|
||||
cols,
|
||||
eagerFetch,
|
||||
session
|
||||
);
|
||||
final Object[] values;
|
||||
try {
|
||||
values = persister.hydrate(
|
||||
resultSet,
|
||||
id,
|
||||
entityInstance,
|
||||
(Loadable) rootPersister,
|
||||
cols,
|
||||
eagerFetch,
|
||||
session
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw getSession().getFactory().getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Could not read entity state from ResultSet : " + entityKey
|
||||
);
|
||||
}
|
||||
|
||||
final Object rowId = persister.hasRowId() ? resultSet.getObject( entityAliases.getRowIdAlias() ) : null;
|
||||
final Object rowId;
|
||||
try {
|
||||
rowId = persister.hasRowId() ? resultSet.getObject( entityAliases.getRowIdAlias() ) : null;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw getSession().getFactory().getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Could not read entity row-id from ResultSet : " + entityKey
|
||||
);
|
||||
}
|
||||
|
||||
if ( associationType != null ) {
|
||||
String ukName = associationType.getRHSUniqueKeyPropertyName();
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.sql.SQLException;
|
|||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -45,7 +44,10 @@ import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierReso
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwner, EntityReference {
|
||||
public class EntityReturn
|
||||
extends AbstractFetchOwner
|
||||
implements Return, FetchOwner, EntityReference, ResultSetProcessingContext.EntityKeyResolutionContext {
|
||||
|
||||
private final EntityAliases entityAliases;
|
||||
private final String sqlTableAlias;
|
||||
|
||||
|
@ -180,76 +182,7 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
|
|||
throw new AssertionFailure( "Could not locate resolved EntityKey");
|
||||
}
|
||||
|
||||
final Object existing = context.getSession().getEntityUsingInterceptor( entityKey );
|
||||
|
||||
if ( existing != null ) {
|
||||
if ( !persister.isInstance( existing ) ) {
|
||||
throw new WrongClassException(
|
||||
"loaded object was of wrong class " + existing.getClass(),
|
||||
entityKey.getIdentifier(),
|
||||
persister.getEntityName()
|
||||
);
|
||||
}
|
||||
|
||||
if ( getLockMode() != null && getLockMode() != LockMode.NONE ) {
|
||||
final boolean isVersionCheckNeeded = persister.isVersioned()
|
||||
&& context.getSession().getPersistenceContext().getEntry( existing ).getLockMode().lessThan( getLockMode() );
|
||||
|
||||
// we don't need to worry about existing version being uninitialized because this block isn't called
|
||||
// by a re-entrant load (re-entrant loads _always_ have lock mode NONE)
|
||||
if ( isVersionCheckNeeded ) {
|
||||
//we only check the version when _upgrading_ lock modes
|
||||
context.checkVersion(
|
||||
resultSet,
|
||||
persister,
|
||||
entityAliases,
|
||||
entityKey,
|
||||
existing
|
||||
);
|
||||
//we need to upgrade the lock mode to the mode requested
|
||||
context.getSession().getPersistenceContext().getEntry( existing ).setLockMode( getLockMode() );
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
else {
|
||||
final String concreteEntityTypeName = context.getConcreteEntityTypeName(
|
||||
resultSet,
|
||||
persister,
|
||||
entityAliases,
|
||||
entityKey
|
||||
);
|
||||
|
||||
final Object entityInstance = context.getSession().instantiate(
|
||||
concreteEntityTypeName,
|
||||
entityKey.getIdentifier()
|
||||
);
|
||||
|
||||
//need to hydrate it.
|
||||
|
||||
// grab its state from the ResultSet and keep it in the Session
|
||||
// (but don't yet initialize the object itself)
|
||||
// note that we acquire LockMode.READ even if it was not requested
|
||||
LockMode acquiredLockMode = getLockMode() == LockMode.NONE ? LockMode.READ : getLockMode();
|
||||
|
||||
context.loadFromResultSet(
|
||||
resultSet,
|
||||
entityInstance,
|
||||
concreteEntityTypeName,
|
||||
entityKey,
|
||||
entityAliases,
|
||||
acquiredLockMode,
|
||||
persister,
|
||||
true,
|
||||
persister.getEntityMetamodel().getEntityType()
|
||||
);
|
||||
|
||||
// materialize associations (and initialize the object) later
|
||||
context.registerHydratedEntity( persister, entityKey, entityInstance );
|
||||
|
||||
return entityInstance;
|
||||
}
|
||||
return context.resolveEntityKey( entityKey, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,7 +27,7 @@ package org.hibernate.loader.spi;
|
|||
* The context for named parameters.
|
||||
* <p/>
|
||||
* NOTE : the hope with the SQL-redesign stuff is that this whole concept goes away, the idea being that
|
||||
* the parameters are encoded into the query tree and "bind themselves".
|
||||
* the parameters are encoded into the query tree and "bind themselves"; see {@link org.hibernate.param.ParameterSpecification}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package org.hibernate.loader.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResultBuilder {
|
||||
}
|
|
@ -23,10 +23,8 @@
|
|||
*/
|
||||
package org.hibernate.loader.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
|
@ -34,9 +32,7 @@ import org.hibernate.engine.spi.QueryParameters;
|
|||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.plan.spi.EntityReference;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
||||
/**
|
||||
|
@ -49,8 +45,6 @@ public interface ResultSetProcessingContext {
|
|||
|
||||
public EntityKey getDictatedRootEntityKey();
|
||||
|
||||
public IdentifierResolutionContext getIdentifierResolutionContext(EntityReference entityReference);
|
||||
|
||||
public static interface IdentifierResolutionContext {
|
||||
public EntityReference getEntityReference();
|
||||
|
||||
|
@ -63,8 +57,21 @@ public interface ResultSetProcessingContext {
|
|||
public EntityKey getEntityKey();
|
||||
}
|
||||
|
||||
public IdentifierResolutionContext getIdentifierResolutionContext(EntityReference entityReference);
|
||||
|
||||
public void registerHydratedEntity(EntityPersister persister, EntityKey entityKey, Object entityInstance);
|
||||
|
||||
public static interface EntityKeyResolutionContext {
|
||||
public EntityPersister getEntityPersister();
|
||||
public LockMode getLockMode();
|
||||
public EntityAliases getEntityAliases();
|
||||
}
|
||||
|
||||
public Object resolveEntityKey(EntityKey entityKey, EntityKeyResolutionContext entityKeyContext);
|
||||
|
||||
|
||||
// should be able to get rid of the methods below here from the interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
public void checkVersion(
|
||||
ResultSet resultSet,
|
||||
EntityPersister persister,
|
||||
|
|
Loading…
Reference in New Issue