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,
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();

View File

@ -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

View File

@ -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
*/

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;
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,