/* * 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.loader.entity.plan; import java.io.Serializable; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.LockOptions; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.loader.entity.UniqueEntityLoader; import org.hibernate.loader.plan.build.internal.FetchGraphLoadPlanBuildingStrategy; import org.hibernate.loader.plan.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy; import org.hibernate.loader.plan.build.internal.LoadGraphLoadPlanBuildingStrategy; import org.hibernate.loader.plan.build.spi.LoadPlanBuildingAssociationVisitationStrategy; import org.hibernate.loader.plan.build.spi.MetamodelDrivenLoadPlanBuilder; import org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader; import org.hibernate.loader.plan.exec.internal.BatchingLoadQueryDetailsFactory; import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters; import org.hibernate.loader.plan.exec.spi.LoadQueryDetails; import org.hibernate.loader.plan.spi.LoadPlan; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.pretty.MessageHelper; import org.hibernate.type.Type; /** * A UniqueEntityLoader implementation based on using LoadPlans * * @author Steve Ebersole */ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlanBasedLoader implements UniqueEntityLoader { private static final CoreMessageLogger log = CoreLogging.messageLogger( AbstractLoadPlanBasedEntityLoader.class ); private final OuterJoinLoadable entityPersister; private final Type uniqueKeyType; private final String entityName; private final LoadQueryDetails staticLoadQuery; public AbstractLoadPlanBasedEntityLoader( OuterJoinLoadable entityPersister, SessionFactoryImplementor factory, String[] uniqueKeyColumnNames, Type uniqueKeyType, QueryBuildingParameters buildingParameters) { super( factory ); this.entityPersister = entityPersister; this.uniqueKeyType = uniqueKeyType; this.entityName = entityPersister.getEntityName(); final LoadPlanBuildingAssociationVisitationStrategy strategy; if ( buildingParameters.getQueryInfluencers().getFetchGraph() != null ) { strategy = new FetchGraphLoadPlanBuildingStrategy( factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode() ); } else if ( buildingParameters.getQueryInfluencers().getLoadGraph() != null ) { strategy = new LoadGraphLoadPlanBuildingStrategy( factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode() ); } else { strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy( factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode() ); } final LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister ); this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails( plan, uniqueKeyColumnNames, buildingParameters, factory ); } @Override protected LoadQueryDetails getStaticLoadQuery() { return staticLoadQuery; } protected String getEntityName() { return entityName; } /** * Called by wrappers that batch load entities * @param persister only needed for logging * @param lockOptions */ public final List loadEntityBatch( final SharedSessionContractImplementor session, final Serializable[] ids, final Type idType, final Object optionalObject, final String optionalEntityName, final Serializable optionalId, final EntityPersister persister, LockOptions lockOptions) throws HibernateException { if ( log.isDebugEnabled() ) { log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister, ids, getFactory() ) ); } final Type[] types = new Type[ids.length]; Arrays.fill( types, idType ); List result; try { final QueryParameters qp = new QueryParameters(); qp.setPositionalParameterTypes( types ); qp.setPositionalParameterValues( ids ); qp.setLockOptions( lockOptions ); result = executeLoad( session, qp, staticLoadQuery, false, null ); } catch ( SQLException sqle ) { throw getFactory().getSQLExceptionHelper().convert( sqle, "could not load an entity batch: " + MessageHelper.infoString( entityPersister, ids, getFactory() ), staticLoadQuery.getSqlStatement() ); } log.debug( "Done entity batch load" ); return result; } @Override public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) throws HibernateException { return load( id, optionalObject, session, LockOptions.NONE ); } @Override public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) { final Object result; try { final QueryParameters qp = new QueryParameters(); qp.setPositionalParameterTypes( new Type[] { entityPersister.getIdentifierType() } ); qp.setPositionalParameterValues( new Object[] { id } ); qp.setOptionalObject( optionalObject ); qp.setOptionalEntityName( entityPersister.getEntityName() ); qp.setOptionalId( id ); qp.setLockOptions( lockOptions ); final List results = executeLoad( session, qp, staticLoadQuery, false, null ); result = extractEntityResult( results ); } catch ( SQLException sqle ) { throw session.getJdbcServices().getSqlExceptionHelper().convert( sqle, "could not load an entity: " + MessageHelper.infoString( entityPersister, id, entityPersister.getIdentifierType(), getFactory() ), staticLoadQuery.getSqlStatement() ); } log.debugf( "Done entity load : %s#%s", getEntityName(), id ); return result; } protected Object extractEntityResult(List results) { if ( results.size() == 0 ) { return null; } else if ( results.size() == 1 ) { return results.get( 0 ); } else { final Object row = results.get( 0 ); if ( row.getClass().isArray() ) { // the logical type of the result list is List<Object[]>. See if the contained // array contains just one element, and return that if so final Object[] rowArray = (Object[]) row; if ( rowArray.length == 1 ) { return rowArray[0]; } } else { return row; } } throw new HibernateException( "Unable to interpret given query results in terms of a load-entity query" ); } protected int[] getNamedParameterLocs(String name) { throw new AssertionFailure("no named parameters"); } protected void autoDiscoverTypes(ResultSet rs) { throw new AssertionFailure("Auto discover types not supported in this loader"); } }