/*
 * 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.internal.EntityLoadQueryDetails;
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
/** * 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 ); } protected AbstractLoadPlanBasedEntityLoader( OuterJoinLoadable entityPersister, SessionFactoryImplementor factory, EntityLoadQueryDetails entityLoaderQueryDetailsTemplate, Type uniqueKeyType, QueryBuildingParameters buildingParameters) { super( factory ); this.entityPersister = entityPersister; this.uniqueKeyType = uniqueKeyType; this.entityName = entityPersister.getEntityName(); this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails( entityLoaderQueryDetailsTemplate, buildingParameters ); } @Override protected LoadQueryDetails getStaticLoadQuery() { return staticLoadQuery; } protected String getEntityName() { return entityName; }
Called by wrappers that batch load entities
Params:
  • persister – only needed for logging
  • lockOptions –
/** * 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"); } }