HHH-7841 - Redesign Loader

This commit is contained in:
Steve Ebersole 2013-03-27 09:11:11 -05:00
parent 88d5c02d7f
commit 3f8699c913
5 changed files with 167 additions and 114 deletions

View File

@ -187,22 +187,31 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
EntityPersister persister, EntityPersister persister,
EntityAliases entityAliases, EntityAliases entityAliases,
EntityKey entityKey, EntityKey entityKey,
Object entityInstance) throws SQLException { Object entityInstance) {
final Object version = session.getPersistenceContext().getEntry( entityInstance ).getVersion(); final Object version = session.getPersistenceContext().getEntry( entityInstance ).getVersion();
if ( version != null ) { if ( version != null ) {
//null version means the object is in the process of being loaded somewhere else in the ResultSet //null version means the object is in the process of being loaded somewhere else in the ResultSet
VersionType versionType = persister.getVersionType(); VersionType versionType = persister.getVersionType();
Object currentVersion = versionType.nullSafeGet( final Object currentVersion;
resultSet, try {
entityAliases.getSuffixedVersionAliases(), currentVersion = versionType.nullSafeGet(
session, resultSet,
null entityAliases.getSuffixedVersionAliases(),
); session,
if ( !versionType.isEqual(version, currentVersion) ) { 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() ) { if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor() session.getFactory().getStatisticsImplementor().optimisticFailure( persister.getEntityName() );
.optimisticFailure( persister.getEntityName() );
} }
throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() ); throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() );
} }
@ -214,19 +223,28 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
final ResultSet rs, final ResultSet rs,
final EntityPersister persister, final EntityPersister persister,
final EntityAliases entityAliases, final EntityAliases entityAliases,
final EntityKey entityKey) throws SQLException { final EntityKey entityKey) {
final Loadable loadable = (Loadable) persister; final Loadable loadable = (Loadable) persister;
if ( ! loadable.hasSubclasses() ) { if ( ! loadable.hasSubclasses() ) {
return persister.getEntityName(); return persister.getEntityName();
} }
final Object discriminatorValue = loadable.getDiscriminatorType().nullSafeGet( final Object discriminatorValue;
rs, try {
entityAliases.getSuffixedDiscriminatorAlias(), discriminatorValue = loadable.getDiscriminatorType().nullSafeGet(
session, rs,
null 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 ); final String result = loadable.getSubclassForDiscriminatorValue( discriminatorValue );
@ -242,6 +260,90 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
return result; 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 @Override
public void loadFromResultSet( public void loadFromResultSet(
ResultSet resultSet, ResultSet resultSet,
@ -252,7 +354,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
LockMode acquiredLockMode, LockMode acquiredLockMode,
EntityPersister rootPersister, EntityPersister rootPersister,
boolean eagerFetch, boolean eagerFetch,
EntityType associationType) throws SQLException { EntityType associationType) {
final Serializable id = entityKey.getIdentifier(); final Serializable id = entityKey.getIdentifier();
@ -287,17 +389,35 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
entityAliases.getSuffixedPropertyAliases() : entityAliases.getSuffixedPropertyAliases() :
entityAliases.getSuffixedPropertyAliases(persister); entityAliases.getSuffixedPropertyAliases(persister);
final Object[] values = persister.hydrate( final Object[] values;
resultSet, try {
id, values = persister.hydrate(
entityInstance, resultSet,
(Loadable) rootPersister, id,
cols, entityInstance,
eagerFetch, (Loadable) rootPersister,
session 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 ) { if ( associationType != null ) {
String ukName = associationType.getRHSUniqueKeyPropertyName(); String ukName = associationType.getRHSUniqueKeyPropertyName();

View File

@ -28,7 +28,6 @@ import java.sql.SQLException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.WrongClassException;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -45,7 +44,10 @@ import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierReso
/** /**
* @author Steve Ebersole * @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 EntityAliases entityAliases;
private final String sqlTableAlias; private final String sqlTableAlias;
@ -180,76 +182,7 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
throw new AssertionFailure( "Could not locate resolved EntityKey"); throw new AssertionFailure( "Could not locate resolved EntityKey");
} }
final Object existing = context.getSession().getEntityUsingInterceptor( entityKey ); return context.resolveEntityKey( entityKey, this );
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;
}
} }
@Override @Override

View File

@ -27,7 +27,7 @@ package org.hibernate.loader.spi;
* The context for named parameters. * The context for named parameters.
* <p/> * <p/>
* NOTE : the hope with the SQL-redesign stuff is that this whole concept goes away, the idea being that * 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 * @author Steve Ebersole
*/ */

View File

@ -1,7 +0,0 @@
package org.hibernate.loader.spi;
/**
* @author Steve Ebersole
*/
public class ResultBuilder {
}

View File

@ -23,10 +23,8 @@
*/ */
package org.hibernate.loader.spi; package org.hibernate.loader.spi;
import java.io.Serializable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.spi.EntityKey; 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.engine.spi.SessionImplementor;
import org.hibernate.loader.EntityAliases; import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.plan.spi.EntityReference; import org.hibernate.loader.plan.spi.EntityReference;
import org.hibernate.loader.plan.spi.Return;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
/** /**
@ -49,8 +45,6 @@ public interface ResultSetProcessingContext {
public EntityKey getDictatedRootEntityKey(); public EntityKey getDictatedRootEntityKey();
public IdentifierResolutionContext getIdentifierResolutionContext(EntityReference entityReference);
public static interface IdentifierResolutionContext { public static interface IdentifierResolutionContext {
public EntityReference getEntityReference(); public EntityReference getEntityReference();
@ -63,8 +57,21 @@ public interface ResultSetProcessingContext {
public EntityKey getEntityKey(); public EntityKey getEntityKey();
} }
public IdentifierResolutionContext getIdentifierResolutionContext(EntityReference entityReference);
public void registerHydratedEntity(EntityPersister persister, EntityKey entityKey, Object entityInstance); 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( public void checkVersion(
ResultSet resultSet, ResultSet resultSet,
EntityPersister persister, EntityPersister persister,