HHH-7841 - Redesign Loader
This commit is contained in:
parent
c75dafbedd
commit
3d332371bd
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate;
|
||||
|
||||
/**
|
||||
* Marks a group of exceptions that generally indicate an internal Hibernate error or bug.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class HibernateError extends HibernateException {
|
||||
public HibernateError(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public HibernateError(Throwable root) {
|
||||
super( root );
|
||||
}
|
||||
|
||||
public HibernateError(String message, Throwable root) {
|
||||
super( message, root );
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.BasicLoader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
|
|
@ -79,6 +79,7 @@ import org.hibernate.internal.CoreMessageLogger;
|
|||
import org.hibernate.internal.FetchingScrollableResultsImpl;
|
||||
import org.hibernate.internal.ScrollableResultsImpl;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
@ -245,10 +246,6 @@ public abstract class Loader {
|
|||
: sql;
|
||||
}
|
||||
|
||||
protected static interface AfterLoadAction {
|
||||
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
|
||||
}
|
||||
|
||||
protected boolean shouldUseFollowOnLocking(
|
||||
QueryParameters parameters,
|
||||
Dialect dialect,
|
||||
|
@ -509,7 +506,7 @@ public abstract class Loader {
|
|||
}
|
||||
|
||||
// We call getKeyFromResultSet() here so that we can know the
|
||||
// key value upon which to doAfterTransactionCompletion the breaking logic. However,
|
||||
// key value upon which to perform the breaking logic. However,
|
||||
// it is also then called from getRowFromResultSet() which is certainly
|
||||
// not the most efficient. But the call here is needed, and there
|
||||
// currently is no other way without refactoring of the doQuery()/getRowFromResultSet()
|
||||
|
@ -527,7 +524,7 @@ public abstract class Loader {
|
|||
catch ( SQLException sqle ) {
|
||||
throw factory.getSQLExceptionHelper().convert(
|
||||
sqle,
|
||||
"could not doAfterTransactionCompletion sequential read of results (forward)",
|
||||
"could not perform sequential read of results (forward)",
|
||||
getSQLString()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.internal.util.StringHelper;
|
|||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.JoinWalker;
|
||||
import org.hibernate.loader.Loader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.type.Type;
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
import org.hibernate.internal.CriteriaImpl;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.OuterJoinLoader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.sql.ResultSet;
|
|||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -41,10 +40,7 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitHelper;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.RowSelection;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.hql.internal.HolderInstantiator;
|
||||
|
@ -53,10 +49,10 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
|||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.Loader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
import org.hibernate.transform.ResultTransformer;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.hibernate.hql.internal.ast.tree.SelectClause;
|
|||
import org.hibernate.internal.IteratorImpl;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.BasicLoader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.internal;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.loader.spi.OnDemandResultSetProcessor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OnDemandResultSetProcessorImpl implements OnDemandResultSetProcessor {
|
||||
@Override
|
||||
public Object extractSingleRow(
|
||||
ResultSet resultSet,
|
||||
SessionImplementor session,
|
||||
QueryParameters queryParameters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object extractSequentialRowsForward(
|
||||
ResultSet resultSet, SessionImplementor session, QueryParameters queryParameters) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object extractSequentialRowsReverse(
|
||||
ResultSet resultSet,
|
||||
SessionImplementor session,
|
||||
QueryParameters queryParameters,
|
||||
boolean isLogicallyAfterLast) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.engine.internal.TwoPhaseLoad;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PreLoadEvent;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan.spi.CollectionReturn;
|
||||
import org.hibernate.loader.plan.spi.EntityReference;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.LoadPlanVisitationStrategyAdapter;
|
||||
import org.hibernate.loader.plan.spi.LoadPlanVisitor;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.loader.spi.NamedParameterContext;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.persister.entity.UniqueKeyLoadable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.VersionType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResultSetProcessingContextImpl implements ResultSetProcessingContext {
|
||||
private static final Logger LOG = Logger.getLogger( ResultSetProcessingContextImpl.class );
|
||||
|
||||
private final ResultSet resultSet;
|
||||
private final SessionImplementor session;
|
||||
private final LoadPlan loadPlan;
|
||||
private final boolean readOnly;
|
||||
private final QueryParameters queryParameters;
|
||||
private final NamedParameterContext namedParameterContext;
|
||||
private final boolean hadSubselectFetches;
|
||||
|
||||
private final EntityKey dictatedRootEntityKey;
|
||||
|
||||
private List<HydratedEntityRegistration> currentRowHydratedEntityRegistrationList;
|
||||
|
||||
private Map<EntityPersister,Set<EntityKey>> subselectLoadableEntityKeyMap;
|
||||
private List<HydratedEntityRegistration> hydratedEntityRegistrationList;
|
||||
|
||||
public ResultSetProcessingContextImpl(
|
||||
ResultSet resultSet,
|
||||
SessionImplementor session,
|
||||
LoadPlan loadPlan,
|
||||
boolean readOnly,
|
||||
boolean useOptionalEntityKey,
|
||||
QueryParameters queryParameters,
|
||||
NamedParameterContext namedParameterContext,
|
||||
boolean hadSubselectFetches) {
|
||||
this.resultSet = resultSet;
|
||||
this.session = session;
|
||||
this.loadPlan = loadPlan;
|
||||
this.readOnly = readOnly;
|
||||
this.queryParameters = queryParameters;
|
||||
this.namedParameterContext = namedParameterContext;
|
||||
this.hadSubselectFetches = hadSubselectFetches;
|
||||
|
||||
if ( useOptionalEntityKey ) {
|
||||
this.dictatedRootEntityKey = ResultSetProcessorHelper.getOptionalObjectKey( queryParameters, session );
|
||||
if ( this.dictatedRootEntityKey == null ) {
|
||||
throw new HibernateException( "Unable to resolve optional entity-key" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.dictatedRootEntityKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionImplementor getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryParameters getQueryParameters() {
|
||||
return queryParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityKey getDictatedRootEntityKey() {
|
||||
return dictatedRootEntityKey;
|
||||
}
|
||||
|
||||
private Map<EntityReference,IdentifierResolutionContext> identifierResolutionContextMap;
|
||||
|
||||
@Override
|
||||
public IdentifierResolutionContext getIdentifierResolutionContext(final EntityReference entityReference) {
|
||||
if ( identifierResolutionContextMap == null ) {
|
||||
identifierResolutionContextMap = new HashMap<EntityReference, IdentifierResolutionContext>();
|
||||
}
|
||||
IdentifierResolutionContext context = identifierResolutionContextMap.get( entityReference );
|
||||
if ( context == null ) {
|
||||
context = new IdentifierResolutionContext() {
|
||||
private Serializable hydratedForm;
|
||||
private EntityKey entityKey;
|
||||
|
||||
@Override
|
||||
public EntityReference getEntityReference() {
|
||||
return entityReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHydratedForm(Serializable hydratedForm) {
|
||||
if ( this.hydratedForm != null ) {
|
||||
// this could be bad...
|
||||
}
|
||||
this.hydratedForm = hydratedForm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getHydratedForm() {
|
||||
return hydratedForm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEntityKey(EntityKey entityKey) {
|
||||
if ( this.entityKey != null ) {
|
||||
// again, could be trouble...
|
||||
}
|
||||
this.entityKey = entityKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
return entityKey;
|
||||
}
|
||||
};
|
||||
identifierResolutionContextMap.put( entityReference, context );
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkVersion(
|
||||
ResultSet resultSet,
|
||||
EntityPersister persister,
|
||||
EntityAliases entityAliases,
|
||||
EntityKey entityKey,
|
||||
Object entityInstance) throws SQLException {
|
||||
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) ) {
|
||||
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
|
||||
session.getFactory().getStatisticsImplementor()
|
||||
.optimisticFailure( persister.getEntityName() );
|
||||
}
|
||||
throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConcreteEntityTypeName(
|
||||
final ResultSet rs,
|
||||
final EntityPersister persister,
|
||||
final EntityAliases entityAliases,
|
||||
final EntityKey entityKey) throws SQLException {
|
||||
|
||||
final Loadable loadable = (Loadable) persister;
|
||||
if ( ! loadable.hasSubclasses() ) {
|
||||
return persister.getEntityName();
|
||||
}
|
||||
|
||||
final Object discriminatorValue = loadable.getDiscriminatorType().nullSafeGet(
|
||||
rs,
|
||||
entityAliases.getSuffixedDiscriminatorAlias(),
|
||||
session,
|
||||
null
|
||||
);
|
||||
|
||||
final String result = loadable.getSubclassForDiscriminatorValue( discriminatorValue );
|
||||
|
||||
if ( result == null ) {
|
||||
// whoops! we got an instance of another class hierarchy branch
|
||||
throw new WrongClassException(
|
||||
"Discriminator: " + discriminatorValue,
|
||||
entityKey.getIdentifier(),
|
||||
persister.getEntityName()
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFromResultSet(
|
||||
ResultSet resultSet,
|
||||
Object entityInstance,
|
||||
String concreteEntityTypeName,
|
||||
EntityKey entityKey,
|
||||
EntityAliases entityAliases,
|
||||
LockMode acquiredLockMode,
|
||||
EntityPersister rootPersister,
|
||||
boolean eagerFetch,
|
||||
EntityType associationType) throws SQLException {
|
||||
|
||||
final Serializable id = entityKey.getIdentifier();
|
||||
|
||||
// Get the persister for the _subclass_
|
||||
final Loadable persister = (Loadable) getSession().getFactory().getEntityPersister( concreteEntityTypeName );
|
||||
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev(
|
||||
"Initializing object from ResultSet: {0}",
|
||||
MessageHelper.infoString(
|
||||
persister,
|
||||
id,
|
||||
getSession().getFactory()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// add temp entry so that the next step is circular-reference
|
||||
// safe - only needed because some types don't take proper
|
||||
// advantage of two-phase-load (esp. components)
|
||||
TwoPhaseLoad.addUninitializedEntity(
|
||||
entityKey,
|
||||
entityInstance,
|
||||
persister,
|
||||
acquiredLockMode,
|
||||
!eagerFetch,
|
||||
session
|
||||
);
|
||||
|
||||
// This is not very nice (and quite slow):
|
||||
final String[][] cols = persister == rootPersister ?
|
||||
entityAliases.getSuffixedPropertyAliases() :
|
||||
entityAliases.getSuffixedPropertyAliases(persister);
|
||||
|
||||
final Object[] values = persister.hydrate(
|
||||
resultSet,
|
||||
id,
|
||||
entityInstance,
|
||||
(Loadable) rootPersister,
|
||||
cols,
|
||||
eagerFetch,
|
||||
session
|
||||
);
|
||||
|
||||
final Object rowId = persister.hasRowId() ? resultSet.getObject( entityAliases.getRowIdAlias() ) : null;
|
||||
|
||||
if ( associationType != null ) {
|
||||
String ukName = associationType.getRHSUniqueKeyPropertyName();
|
||||
if ( ukName != null ) {
|
||||
final int index = ( (UniqueKeyLoadable) persister ).getPropertyIndex( ukName );
|
||||
final Type type = persister.getPropertyTypes()[index];
|
||||
|
||||
// polymorphism not really handled completely correctly,
|
||||
// perhaps...well, actually its ok, assuming that the
|
||||
// entity name used in the lookup is the same as the
|
||||
// the one used here, which it will be
|
||||
|
||||
EntityUniqueKey euk = new EntityUniqueKey(
|
||||
rootPersister.getEntityName(), //polymorphism comment above
|
||||
ukName,
|
||||
type.semiResolve( values[index], session, entityInstance ),
|
||||
type,
|
||||
persister.getEntityMode(),
|
||||
session.getFactory()
|
||||
);
|
||||
session.getPersistenceContext().addEntity( euk, entityInstance );
|
||||
}
|
||||
}
|
||||
|
||||
TwoPhaseLoad.postHydrate(
|
||||
persister,
|
||||
id,
|
||||
values,
|
||||
rowId,
|
||||
entityInstance,
|
||||
acquiredLockMode,
|
||||
!eagerFetch,
|
||||
session
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHydratedEntity(EntityPersister persister, EntityKey entityKey, Object entityInstance) {
|
||||
if ( currentRowHydratedEntityRegistrationList == null ) {
|
||||
currentRowHydratedEntityRegistrationList = new ArrayList<HydratedEntityRegistration>();
|
||||
}
|
||||
currentRowHydratedEntityRegistrationList.add( new HydratedEntityRegistration( persister, entityKey, entityInstance ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-protected
|
||||
*/
|
||||
void finishUpRow() {
|
||||
if ( currentRowHydratedEntityRegistrationList == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// managing the running list of registrations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
if ( hydratedEntityRegistrationList == null ) {
|
||||
hydratedEntityRegistrationList = new ArrayList<HydratedEntityRegistration>();
|
||||
}
|
||||
hydratedEntityRegistrationList.addAll( currentRowHydratedEntityRegistrationList );
|
||||
|
||||
|
||||
// managing the map forms needed for subselect fetch generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
if ( ! hadSubselectFetches ) {
|
||||
return;
|
||||
}
|
||||
if ( subselectLoadableEntityKeyMap == null ) {
|
||||
subselectLoadableEntityKeyMap = new HashMap<EntityPersister, Set<EntityKey>>();
|
||||
}
|
||||
for ( HydratedEntityRegistration registration : currentRowHydratedEntityRegistrationList ) {
|
||||
Set<EntityKey> entityKeys = subselectLoadableEntityKeyMap.get( registration.persister );
|
||||
if ( entityKeys == null ) {
|
||||
entityKeys = new HashSet<EntityKey>();
|
||||
subselectLoadableEntityKeyMap.put( registration.persister, entityKeys );
|
||||
}
|
||||
entityKeys.add( registration.key );
|
||||
}
|
||||
|
||||
// release the currentRowHydratedEntityRegistrationList entries
|
||||
currentRowHydratedEntityRegistrationList.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-protected
|
||||
*
|
||||
* @param afterLoadActionList List of after-load actions to perform
|
||||
*/
|
||||
void finishUp(List<AfterLoadAction> afterLoadActionList) {
|
||||
initializeEntitiesAndCollections( afterLoadActionList );
|
||||
createSubselects();
|
||||
|
||||
if ( hydratedEntityRegistrationList != null ) {
|
||||
hydratedEntityRegistrationList.clear();
|
||||
hydratedEntityRegistrationList = null;
|
||||
}
|
||||
|
||||
if ( subselectLoadableEntityKeyMap != null ) {
|
||||
subselectLoadableEntityKeyMap.clear();
|
||||
subselectLoadableEntityKeyMap = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeEntitiesAndCollections(List<AfterLoadAction> afterLoadActionList) {
|
||||
// for arrays, we should end the collection load before resolving the entities, since the
|
||||
// actual array instances are not instantiated during loading
|
||||
finishLoadingArrays();
|
||||
|
||||
|
||||
// IMPORTANT: reuse the same event instances for performance!
|
||||
final PreLoadEvent preLoadEvent;
|
||||
final PostLoadEvent postLoadEvent;
|
||||
if ( session.isEventSource() ) {
|
||||
preLoadEvent = new PreLoadEvent( (EventSource) session );
|
||||
postLoadEvent = new PostLoadEvent( (EventSource) session );
|
||||
}
|
||||
else {
|
||||
preLoadEvent = null;
|
||||
postLoadEvent = null;
|
||||
}
|
||||
|
||||
// now finish loading the entities (2-phase load)
|
||||
performTwoPhaseLoad( preLoadEvent, postLoadEvent );
|
||||
|
||||
// now we can finalize loading collections
|
||||
finishLoadingCollections();
|
||||
|
||||
// finally, perform post-load operations
|
||||
postLoad( postLoadEvent, afterLoadActionList );
|
||||
}
|
||||
|
||||
private void finishLoadingArrays() {
|
||||
LoadPlanVisitor.visit(
|
||||
loadPlan,
|
||||
new LoadPlanVisitationStrategyAdapter() {
|
||||
@Override
|
||||
public void handleCollectionReturn(CollectionReturn rootCollectionReturn) {
|
||||
endLoadingArray( rootCollectionReturn.getCollectionPersister() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
endLoadingArray( collectionFetch.getCollectionPersister() );
|
||||
}
|
||||
|
||||
private void endLoadingArray(CollectionPersister persister) {
|
||||
if ( persister.isArray() ) {
|
||||
session.getPersistenceContext()
|
||||
.getLoadContexts()
|
||||
.getCollectionLoadContext( resultSet )
|
||||
.endLoadingCollections( persister );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void performTwoPhaseLoad(PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent) {
|
||||
final int numberOfHydratedObjects = hydratedEntityRegistrationList == null
|
||||
? 0
|
||||
: hydratedEntityRegistrationList.size();
|
||||
LOG.tracev( "Total objects hydrated: {0}", numberOfHydratedObjects );
|
||||
|
||||
if ( hydratedEntityRegistrationList == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( HydratedEntityRegistration registration : hydratedEntityRegistrationList ) {
|
||||
TwoPhaseLoad.initializeEntity( registration.instance, readOnly, session, preLoadEvent, postLoadEvent );
|
||||
}
|
||||
}
|
||||
|
||||
private void finishLoadingCollections() {
|
||||
LoadPlanVisitor.visit(
|
||||
loadPlan,
|
||||
new LoadPlanVisitationStrategyAdapter() {
|
||||
@Override
|
||||
public void handleCollectionReturn(CollectionReturn rootCollectionReturn) {
|
||||
endLoadingArray( rootCollectionReturn.getCollectionPersister() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
endLoadingArray( collectionFetch.getCollectionPersister() );
|
||||
}
|
||||
|
||||
private void endLoadingArray(CollectionPersister persister) {
|
||||
if ( ! persister.isArray() ) {
|
||||
session.getPersistenceContext()
|
||||
.getLoadContexts()
|
||||
.getCollectionLoadContext( resultSet )
|
||||
.endLoadingCollections( persister );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void postLoad(PostLoadEvent postLoadEvent, List<AfterLoadAction> afterLoadActionList) {
|
||||
// Until this entire method is refactored w/ polymorphism, postLoad was
|
||||
// split off from initializeEntity. It *must* occur after
|
||||
// endCollectionLoad to ensure the collection is in the
|
||||
// persistence context.
|
||||
if ( hydratedEntityRegistrationList == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( HydratedEntityRegistration registration : hydratedEntityRegistrationList ) {
|
||||
TwoPhaseLoad.postLoad( registration.instance, session, postLoadEvent );
|
||||
if ( afterLoadActionList != null ) {
|
||||
for ( AfterLoadAction afterLoadAction : afterLoadActionList ) {
|
||||
afterLoadAction.afterLoad( session, registration.instance, (Loadable) registration.persister );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createSubselects() {
|
||||
if ( subselectLoadableEntityKeyMap.size() <= 1 ) {
|
||||
// if we only returned one entity, query by key is more efficient; so do nothing here
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, int[]> namedParameterLocMap =
|
||||
ResultSetProcessorHelper.buildNamedParameterLocMap( queryParameters, namedParameterContext );
|
||||
|
||||
for ( Map.Entry<EntityPersister, Set<EntityKey>> entry : subselectLoadableEntityKeyMap.entrySet() ) {
|
||||
if ( ! entry.getKey().hasSubselectLoadableCollections() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SubselectFetch subselectFetch = new SubselectFetch(
|
||||
//getSQLString(),
|
||||
null, // aliases[i],
|
||||
(Loadable) entry.getKey(),
|
||||
queryParameters,
|
||||
entry.getValue(),
|
||||
namedParameterLocMap
|
||||
);
|
||||
|
||||
for ( EntityKey key : entry.getValue() ) {
|
||||
session.getPersistenceContext().getBatchFetchQueue().addSubselect( key, subselectFetch );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static class HydratedEntityRegistration {
|
||||
private final EntityPersister persister;
|
||||
private final EntityKey key;
|
||||
private final Object instance;
|
||||
|
||||
private HydratedEntityRegistration(EntityPersister persister, EntityKey key, Object instance) {
|
||||
this.persister = persister;
|
||||
this.key = key;
|
||||
this.instance = instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
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.Fetch;
|
||||
import org.hibernate.loader.spi.NamedParameterContext;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResultSetProcessorHelper {
|
||||
public static EntityKey getOptionalObjectKey(QueryParameters queryParameters, SessionImplementor session) {
|
||||
final Object optionalObject = queryParameters.getOptionalObject();
|
||||
final Serializable optionalId = queryParameters.getOptionalId();
|
||||
final String optionalEntityName = queryParameters.getOptionalEntityName();
|
||||
|
||||
if ( optionalObject != null && optionalEntityName != null ) {
|
||||
return session.generateEntityKey( optionalId, session.getEntityPersister( optionalEntityName, optionalObject ) );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, int[]> buildNamedParameterLocMap(
|
||||
QueryParameters queryParameters,
|
||||
NamedParameterContext namedParameterContext) {
|
||||
if ( queryParameters.getNamedParameters() == null || queryParameters.getNamedParameters().isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, int[]> namedParameterLocMap = new HashMap<String, int[]>();
|
||||
for ( String name : queryParameters.getNamedParameters().keySet() ) {
|
||||
namedParameterLocMap.put(
|
||||
name,
|
||||
namedParameterContext.getNamedParameterLocations( name )
|
||||
);
|
||||
}
|
||||
return namedParameterLocMap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.dialect.pagination.LimitHelper;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.RowSelection;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan.spi.CollectionReturn;
|
||||
import org.hibernate.loader.plan.spi.EntityFetch;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.LoadPlanVisitationStrategyAdapter;
|
||||
import org.hibernate.loader.plan.spi.LoadPlanVisitor;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.loader.spi.NamedParameterContext;
|
||||
import org.hibernate.loader.spi.OnDemandResultSetProcessor;
|
||||
import org.hibernate.loader.spi.ResultSetProcessor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.transform.ResultTransformer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResultSetProcessorImpl implements ResultSetProcessor {
|
||||
private static final Logger LOG = Logger.getLogger( ResultSetProcessorImpl.class );
|
||||
|
||||
private final LoadPlan loadPlan;
|
||||
|
||||
private final boolean hadSubselectFetches;
|
||||
|
||||
public ResultSetProcessorImpl(LoadPlan loadPlan) {
|
||||
this.loadPlan = loadPlan;
|
||||
|
||||
LocalVisitationStrategy strategy = new LocalVisitationStrategy();
|
||||
LoadPlanVisitor.visit( loadPlan, strategy );
|
||||
this.hadSubselectFetches = strategy.hadSubselectFetches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OnDemandResultSetProcessor toOnDemandForm() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public List extractResults(
|
||||
ResultSet resultSet,
|
||||
final SessionImplementor session,
|
||||
QueryParameters queryParameters,
|
||||
NamedParameterContext namedParameterContext,
|
||||
boolean returnProxies,
|
||||
boolean readOnly,
|
||||
ResultTransformer forcedResultTransformer,
|
||||
List<AfterLoadAction> afterLoadActionList) throws SQLException {
|
||||
|
||||
handlePotentiallyEmptyCollectionRootReturns( queryParameters.getCollectionKeys(), resultSet, session );
|
||||
|
||||
final int maxRows;
|
||||
final RowSelection selection = queryParameters.getRowSelection();
|
||||
if ( LimitHelper.hasMaxRows( selection ) ) {
|
||||
maxRows = selection.getMaxRows();
|
||||
LOG.tracef( "Limiting ResultSet processing to just %s rows", maxRows );
|
||||
}
|
||||
else {
|
||||
maxRows = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
final ResultSetProcessingContextImpl context = new ResultSetProcessingContextImpl(
|
||||
resultSet,
|
||||
session,
|
||||
loadPlan,
|
||||
readOnly,
|
||||
true, // use optional entity key? for now, always say yes
|
||||
queryParameters,
|
||||
namedParameterContext,
|
||||
hadSubselectFetches
|
||||
);
|
||||
|
||||
final List loadResults = new ArrayList();
|
||||
|
||||
final int rootReturnCount = loadPlan.getReturns().size();
|
||||
|
||||
LOG.trace( "Processing result set" );
|
||||
int count;
|
||||
for ( count = 0; count < maxRows && resultSet.next(); count++ ) {
|
||||
LOG.debugf( "Starting ResultSet row #%s", count );
|
||||
|
||||
Object logicalRow;
|
||||
if ( rootReturnCount == 1 ) {
|
||||
loadPlan.getReturns().get( 0 ).hydrate( resultSet, context );
|
||||
loadPlan.getReturns().get( 0 ).resolve( resultSet, context );
|
||||
|
||||
logicalRow = loadPlan.getReturns().get( 0 ).read( resultSet, context );
|
||||
}
|
||||
else {
|
||||
for ( Return rootReturn : loadPlan.getReturns() ) {
|
||||
rootReturn.hydrate( resultSet, context );
|
||||
}
|
||||
for ( Return rootReturn : loadPlan.getReturns() ) {
|
||||
rootReturn.resolve( resultSet, context );
|
||||
}
|
||||
|
||||
logicalRow = new Object[ rootReturnCount ];
|
||||
int pos = 0;
|
||||
for ( Return rootReturn : loadPlan.getReturns() ) {
|
||||
( (Object[]) logicalRow )[pos] = rootReturn.read( resultSet, context );
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
// todo : apply transformers here?
|
||||
|
||||
loadResults.add( logicalRow );
|
||||
|
||||
context.finishUpRow();
|
||||
}
|
||||
|
||||
LOG.tracev( "Done processing result set ({0} rows)", count );
|
||||
|
||||
context.finishUp( afterLoadActionList );
|
||||
|
||||
session.getPersistenceContext().initializeNonLazyCollections();
|
||||
|
||||
return loadResults;
|
||||
}
|
||||
|
||||
|
||||
private void handlePotentiallyEmptyCollectionRootReturns(
|
||||
Serializable[] collectionKeys,
|
||||
ResultSet resultSet,
|
||||
SessionImplementor session) {
|
||||
if ( collectionKeys == null ) {
|
||||
// this is not a collection initializer (and empty collections will be detected by looking for
|
||||
// the owner's identifier in the result set)
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a collection initializer, so we must create a collection
|
||||
// for each of the passed-in keys, to account for the possibility
|
||||
// that the collection is empty and has no rows in the result set
|
||||
//
|
||||
// todo : move this inside CollectionReturn ?
|
||||
CollectionPersister persister = ( (CollectionReturn) loadPlan.getReturns().get( 0 ) ).getCollectionPersister();
|
||||
for ( Serializable key : collectionKeys ) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf(
|
||||
"Preparing collection intializer : %s",
|
||||
MessageHelper.collectionInfoString( persister, key, session.getFactory() )
|
||||
);
|
||||
session.getPersistenceContext()
|
||||
.getLoadContexts()
|
||||
.getCollectionLoadContext( resultSet )
|
||||
.getLoadingCollection( persister, key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class LocalVisitationStrategy extends LoadPlanVisitationStrategyAdapter {
|
||||
private boolean hadSubselectFetches = false;
|
||||
|
||||
@Override
|
||||
public void startingEntityFetch(EntityFetch entityFetch) {
|
||||
// only collections are currently supported for subselect fetching.
|
||||
// hadSubselectFetches = hadSubselectFetches
|
||||
// | entityFetch.getFetchStrategy().getStyle() == FetchStyle.SUBSELECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
hadSubselectFetches = hadSubselectFetches
|
||||
| collectionFetch.getFetchStrategy().getStyle() == FetchStyle.SUBSELECT;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.internal;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.plan.spi.AbstractFetchOwner;
|
||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan.spi.EntityFetch;
|
||||
import org.hibernate.loader.plan.spi.FetchOwner;
|
||||
import org.hibernate.loader.plan.spi.LoadPlanBuildingContext;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LoadPlanBuildingHelper {
|
||||
public static CollectionFetch buildStandardCollectionFetch(
|
||||
FetchOwner fetchOwner,
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
final CollectionAliases collectionAliases = loadPlanBuildingContext.resolveCollectionColumnAliases( attributeDefinition );
|
||||
final EntityAliases elementEntityAliases = loadPlanBuildingContext.resolveEntityColumnAliases( attributeDefinition );
|
||||
|
||||
return new CollectionFetch(
|
||||
loadPlanBuildingContext.getSessionFactory(),
|
||||
loadPlanBuildingContext.resolveFetchSourceAlias( attributeDefinition ),
|
||||
LockMode.NONE, // todo : for now
|
||||
fetchOwner,
|
||||
fetchStrategy,
|
||||
attributeDefinition.getName(),
|
||||
collectionAliases,
|
||||
elementEntityAliases
|
||||
);
|
||||
}
|
||||
|
||||
public static EntityFetch buildStandardEntityFetch(
|
||||
FetchOwner fetchOwner,
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
|
||||
return new EntityFetch(
|
||||
loadPlanBuildingContext.getSessionFactory(),
|
||||
loadPlanBuildingContext.resolveFetchSourceAlias( attributeDefinition ),
|
||||
LockMode.NONE, // todo : for now
|
||||
fetchOwner,
|
||||
attributeDefinition.getName(),
|
||||
fetchStrategy,
|
||||
null, // sql table alias
|
||||
loadPlanBuildingContext.resolveEntityColumnAliases( attributeDefinition )
|
||||
);
|
||||
}
|
||||
|
||||
public static CompositeFetch buildStandardCompositeFetch(
|
||||
FetchOwner fetchOwner,
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return new CompositeFetch(
|
||||
loadPlanBuildingContext.getSessionFactory(),
|
||||
loadPlanBuildingContext.resolveFetchSourceAlias( attributeDefinition ),
|
||||
(AbstractFetchOwner) fetchOwner,
|
||||
attributeDefinition.getName()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -32,26 +32,18 @@ import org.hibernate.engine.spi.LoadQueryInfluencers;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.DefaultEntityAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.GeneratedCollectionAliases;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.spi.AbstractFetchOwner;
|
||||
import org.hibernate.loader.plan.spi.AbstractLoadPlanBuilderStrategy;
|
||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan.spi.CollectionReturn;
|
||||
import org.hibernate.loader.plan.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan.spi.EntityFetch;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.plan.spi.FetchOwner;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.LoadPlanBuilderStrategy;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -74,7 +66,6 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
|||
private final LoadQueryInfluencers loadQueryInfluencers;
|
||||
|
||||
private final String rootAlias;
|
||||
private int currentSuffixBase;
|
||||
|
||||
private Return rootReturn;
|
||||
|
||||
|
@ -85,10 +76,9 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
|||
LoadQueryInfluencers loadQueryInfluencers,
|
||||
String rootAlias,
|
||||
int suffixSeed) {
|
||||
super( sessionFactory );
|
||||
super( sessionFactory, suffixSeed );
|
||||
this.loadQueryInfluencers = loadQueryInfluencers;
|
||||
this.rootAlias = rootAlias;
|
||||
this.currentSuffixBase = suffixSeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,10 +143,7 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
|||
LockMode.NONE, // todo : for now
|
||||
entityName,
|
||||
StringHelper.generateAlias( StringHelper.unqualifyEntityName( entityName ), currentDepth() ),
|
||||
new DefaultEntityAliases(
|
||||
(Loadable) entityDefinition.getEntityPersister(),
|
||||
Integer.toString( currentSuffixBase++ ) + '_'
|
||||
)
|
||||
generateEntityColumnAliases( entityDefinition.getEntityPersister() )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -165,17 +152,16 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
|||
final CollectionPersister persister = collectionDefinition.getCollectionPersister();
|
||||
final String collectionRole = persister.getRole();
|
||||
|
||||
final CollectionAliases collectionAliases = new GeneratedCollectionAliases(
|
||||
collectionDefinition.getCollectionPersister(),
|
||||
Integer.toString( currentSuffixBase++ ) + '_'
|
||||
final CollectionAliases collectionAliases = generateCollectionColumnAliases(
|
||||
collectionDefinition.getCollectionPersister()
|
||||
);
|
||||
|
||||
final Type elementType = collectionDefinition.getCollectionPersister().getElementType();
|
||||
final EntityAliases elementAliases;
|
||||
if ( elementType.isEntityType() ) {
|
||||
final EntityType entityElementType = (EntityType) elementType;
|
||||
elementAliases = new DefaultEntityAliases(
|
||||
(Loadable) entityElementType.getAssociatedJoinable( sessionFactory() ),
|
||||
Integer.toString( currentSuffixBase++ ) + '_'
|
||||
elementAliases = generateEntityColumnAliases(
|
||||
(EntityPersister) entityElementType.getAssociatedJoinable( sessionFactory() )
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
@ -193,76 +179,16 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CollectionFetch buildCollectionFetch(
|
||||
FetchOwner fetchOwner,
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy) {
|
||||
final CollectionDefinition collectionDefinition = attributeDefinition.toCollectionDefinition();
|
||||
final CollectionAliases collectionAliases = new GeneratedCollectionAliases(
|
||||
collectionDefinition.getCollectionPersister(),
|
||||
Integer.toString( currentSuffixBase++ ) + '_'
|
||||
);
|
||||
final Type elementType = collectionDefinition.getCollectionPersister().getElementType();
|
||||
final EntityAliases elementAliases;
|
||||
if ( elementType.isEntityType() ) {
|
||||
final EntityType entityElementType = (EntityType) elementType;
|
||||
elementAliases = new DefaultEntityAliases(
|
||||
(Loadable) entityElementType.getAssociatedJoinable( sessionFactory() ),
|
||||
Integer.toString( currentSuffixBase++ ) + '_'
|
||||
);
|
||||
}
|
||||
else {
|
||||
elementAliases = null;
|
||||
}
|
||||
|
||||
return new CollectionFetch(
|
||||
sessionFactory(),
|
||||
createImplicitAlias(),
|
||||
LockMode.NONE, // todo : for now
|
||||
(AbstractFetchOwner) fetchOwner,
|
||||
fetchStrategy,
|
||||
attributeDefinition.getName(),
|
||||
collectionAliases,
|
||||
elementAliases
|
||||
);
|
||||
// LoadPlanBuildingContext impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public String resolveRootSourceAlias(EntityDefinition definition) {
|
||||
return rootAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityFetch buildEntityFetch(
|
||||
FetchOwner fetchOwner,
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy) {
|
||||
final EntityDefinition entityDefinition = attributeDefinition.toEntityDefinition();
|
||||
|
||||
return new EntityFetch(
|
||||
sessionFactory(),
|
||||
createImplicitAlias(),
|
||||
LockMode.NONE, // todo : for now
|
||||
(AbstractFetchOwner) fetchOwner,
|
||||
attributeDefinition.getName(),
|
||||
fetchStrategy,
|
||||
StringHelper.generateAlias( entityDefinition.getEntityPersister().getEntityName(), currentDepth() ),
|
||||
new DefaultEntityAliases(
|
||||
(Loadable) entityDefinition.getEntityPersister(),
|
||||
Integer.toString( currentSuffixBase++ ) + '_'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompositeFetch buildCompositeFetch(FetchOwner fetchOwner, CompositeDefinition attributeDefinition) {
|
||||
return new CompositeFetch(
|
||||
sessionFactory(),
|
||||
createImplicitAlias(),
|
||||
(AbstractFetchOwner) fetchOwner,
|
||||
attributeDefinition.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private int implicitAliasUniqueness = 0;
|
||||
|
||||
private String createImplicitAlias() {
|
||||
return "ia" + implicitAliasUniqueness++;
|
||||
public String resolveRootSourceAlias(CollectionDefinition definition) {
|
||||
return rootAlias;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractCollectionReference extends AbstractPlanNode implements CollectionReference {
|
||||
private final String alias;
|
||||
private final LockMode lockMode;
|
||||
private final CollectionPersister collectionPersister;
|
||||
private final PropertyPath propertyPath;
|
||||
|
||||
private final CollectionAliases collectionAliases;
|
||||
private final EntityAliases elementEntityAliases;
|
||||
|
||||
private final FetchOwner indexGraph;
|
||||
private final FetchOwner elementGraph;
|
||||
|
||||
protected AbstractCollectionReference(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
String alias,
|
||||
LockMode lockMode,
|
||||
CollectionPersister collectionPersister,
|
||||
PropertyPath propertyPath,
|
||||
CollectionAliases collectionAliases,
|
||||
EntityAliases elementEntityAliases) {
|
||||
super( sessionFactory );
|
||||
this.alias = alias;
|
||||
this.lockMode = lockMode;
|
||||
this.collectionPersister = collectionPersister;
|
||||
this.propertyPath = propertyPath;
|
||||
|
||||
this.collectionAliases = collectionAliases;
|
||||
this.elementEntityAliases = elementEntityAliases;
|
||||
|
||||
this.indexGraph = buildIndexGraph( getCollectionPersister() );
|
||||
this.elementGraph = buildElementGraph( getCollectionPersister() );
|
||||
}
|
||||
|
||||
private FetchOwner buildIndexGraph(CollectionPersister persister) {
|
||||
if ( persister.hasIndex() ) {
|
||||
final Type type = persister.getIndexType();
|
||||
if ( type.isAssociationType() ) {
|
||||
if ( type.isEntityType() ) {
|
||||
return new EntityIndexGraph( sessionFactory(), this, propertyPath() );
|
||||
}
|
||||
}
|
||||
else if ( type.isComponentType() ) {
|
||||
return new CompositeIndexGraph( sessionFactory(), this, propertyPath() );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private FetchOwner buildElementGraph(CollectionPersister persister) {
|
||||
final Type type = persister.getElementType();
|
||||
if ( type.isAssociationType() ) {
|
||||
if ( type.isEntityType() ) {
|
||||
return new EntityElementGraph( sessionFactory(), this, propertyPath() );
|
||||
}
|
||||
}
|
||||
else if ( type.isComponentType() ) {
|
||||
return new CompositeElementGraph( sessionFactory(), this, propertyPath() );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public PropertyPath propertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockMode getLockMode() {
|
||||
return lockMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionAliases getCollectionAliases() {
|
||||
return collectionAliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases getElementEntityAliases() {
|
||||
return elementEntityAliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionPersister getCollectionPersister() {
|
||||
return collectionPersister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOwner getIndexGraph() {
|
||||
return indexGraph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchOwner getElementGraph() {
|
||||
return elementGraph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEntityElements() {
|
||||
return getCollectionPersister().isOneToMany() || getCollectionPersister().isManyToMany();
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ public abstract class AbstractFetch extends AbstractFetchOwner implements Fetch
|
|||
SessionFactoryImplementor factory,
|
||||
String alias,
|
||||
LockMode lockMode,
|
||||
AbstractFetchOwner owner,
|
||||
FetchOwner owner,
|
||||
String ownerProperty,
|
||||
FetchStrategy fetchStrategy) {
|
||||
super( factory, alias, lockMode );
|
||||
|
@ -85,4 +85,9 @@ public abstract class AbstractFetch extends AbstractFetchOwner implements Fetch
|
|||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Fetch(" + propertyPath.getFullPath() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,8 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
|
|||
return lockMode;
|
||||
}
|
||||
|
||||
void addFetch(Fetch fetch) {
|
||||
@Override
|
||||
public void addFetch(Fetch fetch) {
|
||||
if ( fetch.getOwner() != this ) {
|
||||
throw new IllegalArgumentException( "Fetch and owner did not match" );
|
||||
}
|
||||
|
|
|
@ -23,29 +23,62 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.DefaultEntityAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.GeneratedCollectionAliases;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
import org.hibernate.persister.walking.spi.WalkingException;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilderStrategy {
|
||||
public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilderStrategy, LoadPlanBuildingContext {
|
||||
private static final Logger log = Logger.getLogger( AbstractLoadPlanBuilderStrategy.class );
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private ArrayDeque<FetchOwner> fetchOwnerStack = new ArrayDeque<FetchOwner>();
|
||||
private ArrayDeque<CollectionReference> collectionReferenceStack = new ArrayDeque<CollectionReference>();
|
||||
|
||||
protected AbstractLoadPlanBuilderStrategy(SessionFactoryImplementor sessionFactory) {
|
||||
protected AbstractLoadPlanBuilderStrategy(SessionFactoryImplementor sessionFactory, int suffixSeed) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.currentSuffixBase = suffixSeed;
|
||||
}
|
||||
|
||||
public SessionFactoryImplementor sessionFactory() {
|
||||
|
@ -53,21 +86,39 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
}
|
||||
|
||||
protected FetchOwner currentFetchOwner() {
|
||||
return fetchOwnerStack.peekLast();
|
||||
return fetchOwnerStack.peekFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// nothing to do
|
||||
if ( ! fetchOwnerStack.isEmpty() ) {
|
||||
throw new WalkingException(
|
||||
"Fetch owner stack was not empty on start; " +
|
||||
"be sure to not use LoadPlanBuilderStrategy instances concurrently"
|
||||
);
|
||||
}
|
||||
if ( ! collectionReferenceStack.isEmpty() ) {
|
||||
throw new WalkingException(
|
||||
"Collection reference stack was not empty on start; " +
|
||||
"be sure to not use LoadPlanBuilderStrategy instances concurrently"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
// nothing to do
|
||||
fetchOwnerStack.clear();
|
||||
collectionReferenceStack.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingEntity(EntityDefinition entityDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting entity : %s",
|
||||
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
entityDefinition.getEntityPersister().getEntityName()
|
||||
);
|
||||
|
||||
if ( fetchOwnerStack.isEmpty() ) {
|
||||
// this is a root...
|
||||
if ( ! supportsRootEntityReturns() ) {
|
||||
|
@ -75,7 +126,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
}
|
||||
final EntityReturn entityReturn = buildRootEntityReturn( entityDefinition );
|
||||
addRootReturn( entityReturn );
|
||||
fetchOwnerStack.push( entityReturn );
|
||||
pushToStack( entityReturn );
|
||||
}
|
||||
// otherwise this call should represent a fetch which should have been handled in #startingAttribute
|
||||
}
|
||||
|
@ -88,11 +139,112 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
|
||||
@Override
|
||||
public void finishingEntity(EntityDefinition entityDefinition) {
|
||||
// nothing to do
|
||||
// pop the current fetch owner, and make sure what we just popped represents this entity
|
||||
final FetchOwner poppedFetchOwner = popFromStack();
|
||||
|
||||
if ( ! EntityReference.class.isInstance( poppedFetchOwner ) ) {
|
||||
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
|
||||
}
|
||||
|
||||
final EntityReference entityReference = (EntityReference) poppedFetchOwner;
|
||||
// NOTE : this is not the most exhaustive of checks because of hierarchical associations (employee/manager)
|
||||
if ( ! entityReference.getEntityPersister().equals( entityDefinition.getEntityPersister() ) ) {
|
||||
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
|
||||
}
|
||||
|
||||
log.tracef(
|
||||
"%s Finished entity : %s",
|
||||
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
entityDefinition.getEntityPersister().getEntityName()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting entity identifier : %s",
|
||||
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
|
||||
);
|
||||
|
||||
final EntityReference entityReference = (EntityReference) currentFetchOwner();
|
||||
|
||||
// perform some stack validation
|
||||
if ( ! entityReference.getEntityPersister().equals( entityIdentifierDefinition.getEntityDefinition().getEntityPersister() ) ) {
|
||||
throw new WalkingException(
|
||||
String.format(
|
||||
"Encountered unexpected fetch owner [%s] in stack while processing entity identifier for [%s]",
|
||||
entityReference.getEntityPersister().getEntityName(),
|
||||
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final FetchOwner identifierAttributeCollector;
|
||||
if ( entityIdentifierDefinition.isEncapsulated() ) {
|
||||
identifierAttributeCollector = new EncapsulatedIdentifierAttributeCollector( entityReference );
|
||||
}
|
||||
else {
|
||||
identifierAttributeCollector = new NonEncapsulatedIdentifierAttributeCollector( entityReference );
|
||||
}
|
||||
pushToStack( identifierAttributeCollector );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
|
||||
// perform some stack validation on exit, first on the current stack element we want to pop
|
||||
{
|
||||
final FetchOwner poppedFetchOwner = popFromStack();
|
||||
|
||||
if ( ! AbstractIdentifierAttributeCollector.class.isInstance( poppedFetchOwner ) ) {
|
||||
throw new WalkingException( "Unexpected state in FetchOwner stack" );
|
||||
}
|
||||
|
||||
final EntityReference entityReference = (EntityReference) poppedFetchOwner;
|
||||
if ( ! entityReference.getEntityPersister().equals( entityIdentifierDefinition.getEntityDefinition().getEntityPersister() ) ) {
|
||||
throw new WalkingException(
|
||||
String.format(
|
||||
"Encountered unexpected fetch owner [%s] in stack while processing entity identifier for [%s]",
|
||||
entityReference.getEntityPersister().getEntityName(),
|
||||
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// and then on the element before it
|
||||
{
|
||||
final FetchOwner currentFetchOwner = currentFetchOwner();
|
||||
if ( ! EntityReference.class.isInstance( currentFetchOwner ) ) {
|
||||
throw new WalkingException( "Unexpected state in FetchOwner stack" );
|
||||
}
|
||||
final EntityReference entityReference = (EntityReference) currentFetchOwner;
|
||||
if ( ! entityReference.getEntityPersister().equals( entityIdentifierDefinition.getEntityDefinition().getEntityPersister() ) ) {
|
||||
throw new WalkingException(
|
||||
String.format(
|
||||
"Encountered unexpected fetch owner [%s] in stack while processing entity identifier for [%s]",
|
||||
entityReference.getEntityPersister().getEntityName(),
|
||||
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
log.tracef(
|
||||
"%s Finished entity identifier : %s",
|
||||
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
entityIdentifierDefinition.getEntityDefinition().getEntityPersister().getEntityName()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollection(CollectionDefinition collectionDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting collection : %s",
|
||||
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
collectionDefinition.getCollectionPersister().getRole()
|
||||
);
|
||||
|
||||
if ( fetchOwnerStack.isEmpty() ) {
|
||||
// this is a root...
|
||||
if ( ! supportsRootCollectionReturns() ) {
|
||||
|
@ -100,7 +252,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
}
|
||||
final CollectionReturn collectionReturn = buildRootCollectionReturn( collectionDefinition );
|
||||
addRootReturn( collectionReturn );
|
||||
fetchOwnerStack.push( collectionReturn );
|
||||
pushToCollectionStack( collectionReturn );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,24 +261,96 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollection(CollectionDefinition collectionDefinition) {
|
||||
// nothing to do
|
||||
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
final Type indexType = collectionIndexDefinition.getType();
|
||||
if ( indexType.isAssociationType() || indexType.isComponentType() ) {
|
||||
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
|
||||
final FetchOwner indexGraph = collectionReference.getIndexGraph();
|
||||
if ( indexGraph == null ) {
|
||||
throw new WalkingException( "Collection reference did not return index handler" );
|
||||
}
|
||||
pushToStack( indexGraph );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingComposite(CompositeDefinition compositeDefinition) {
|
||||
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
// nothing to do here
|
||||
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionElements(CollectionElementDefinition elementDefinition) {
|
||||
if ( elementDefinition.getType().isAssociationType() || elementDefinition.getType().isComponentType() ) {
|
||||
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
|
||||
final FetchOwner elementGraph = collectionReference.getElementGraph();
|
||||
if ( elementGraph == null ) {
|
||||
throw new WalkingException( "Collection reference did not return element handler" );
|
||||
}
|
||||
pushToStack( elementGraph );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollectionElements(CollectionElementDefinition elementDefinition) {
|
||||
// nothing to do here
|
||||
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollection(CollectionDefinition collectionDefinition) {
|
||||
// pop the current fetch owner, and make sure what we just popped represents this collection
|
||||
final CollectionReference collectionReference = popFromCollectionStack();
|
||||
if ( ! collectionReference.getCollectionPersister().equals( collectionDefinition.getCollectionPersister() ) ) {
|
||||
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
|
||||
}
|
||||
|
||||
log.tracef(
|
||||
"%s Finished collection : %s",
|
||||
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
collectionDefinition.getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingComposite(CompositionDefinition compositionDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting composition : %s",
|
||||
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
compositionDefinition.getName()
|
||||
);
|
||||
|
||||
if ( fetchOwnerStack.isEmpty() ) {
|
||||
throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingComposite(CompositeDefinition compositeDefinition) {
|
||||
// nothing to do
|
||||
public void finishingComposite(CompositionDefinition compositionDefinition) {
|
||||
// pop the current fetch owner, and make sure what we just popped represents this composition
|
||||
final FetchOwner poppedFetchOwner = popFromStack();
|
||||
|
||||
if ( ! CompositeFetch.class.isInstance( poppedFetchOwner ) ) {
|
||||
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
|
||||
}
|
||||
|
||||
// NOTE : not much else we can really check here atm since on the walking spi side we do not have path
|
||||
|
||||
log.tracef(
|
||||
"%s Finished composition : %s",
|
||||
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
compositionDefinition.getName()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting attribute %s",
|
||||
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
attributeDefinition
|
||||
);
|
||||
|
||||
final Type attributeType = attributeDefinition.getType();
|
||||
|
||||
final boolean isComponentType = attributeType.isComponentType();
|
||||
|
@ -136,30 +360,26 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
return true;
|
||||
}
|
||||
else if ( isComponentType ) {
|
||||
return handleCompositeAttribute( (CompositeDefinition) attributeDefinition );
|
||||
return handleCompositeAttribute( (CompositionDefinition) attributeDefinition );
|
||||
}
|
||||
else {
|
||||
return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void finishingAttribute(AttributeDefinition attributeDefinition) {
|
||||
final Type attributeType = attributeDefinition.getType();
|
||||
|
||||
final boolean isComponentType = attributeType.isComponentType();
|
||||
final boolean isBasicType = ! ( isComponentType || attributeType.isAssociationType() );
|
||||
|
||||
if ( ! isBasicType ) {
|
||||
fetchOwnerStack.removeLast();
|
||||
}
|
||||
log.tracef(
|
||||
"%s Finishing up attribute : %s",
|
||||
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
attributeDefinition
|
||||
);
|
||||
}
|
||||
|
||||
protected boolean handleCompositeAttribute(CompositeDefinition attributeDefinition) {
|
||||
final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
|
||||
final CompositeFetch fetch = buildCompositeFetch( fetchOwner, attributeDefinition );
|
||||
fetchOwnerStack.addLast( fetch );
|
||||
protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) {
|
||||
final FetchOwner fetchOwner = currentFetchOwner();
|
||||
final CompositeFetch fetch = fetchOwner.buildCompositeFetch( attributeDefinition, this );
|
||||
pushToStack( fetch );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -169,17 +389,20 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
return false;
|
||||
}
|
||||
|
||||
final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
|
||||
final FetchOwner fetchOwner = currentFetchOwner();
|
||||
fetchOwner.validateFetchPlan( fetchStrategy );
|
||||
|
||||
final Fetch associationFetch;
|
||||
if ( attributeDefinition.isCollection() ) {
|
||||
associationFetch = buildCollectionFetch( fetchOwner, attributeDefinition, fetchStrategy );
|
||||
associationFetch = fetchOwner.buildCollectionFetch( attributeDefinition, fetchStrategy, this );
|
||||
}
|
||||
else {
|
||||
associationFetch = buildEntityFetch( fetchOwner, attributeDefinition, fetchStrategy );
|
||||
associationFetch = fetchOwner.buildEntityFetch( attributeDefinition, fetchStrategy, this );
|
||||
}
|
||||
|
||||
if ( FetchOwner.class.isInstance( associationFetch ) ) {
|
||||
pushToStack( (FetchOwner) associationFetch );
|
||||
}
|
||||
fetchOwnerStack.addLast( associationFetch );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -194,19 +417,309 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
return false;
|
||||
}
|
||||
|
||||
private void pushToStack(FetchOwner fetchOwner) {
|
||||
log.trace( "Pushing fetch owner to stack : " + fetchOwner );
|
||||
fetchOwnerStack.addFirst( fetchOwner );
|
||||
}
|
||||
|
||||
private FetchOwner popFromStack() {
|
||||
final FetchOwner last = fetchOwnerStack.removeFirst();
|
||||
log.trace( "Popped fetch owner from stack : " + last );
|
||||
if ( FetchStackAware.class.isInstance( last ) ) {
|
||||
( (FetchStackAware) last ).poppedFromStack();
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
private void pushToCollectionStack(CollectionReference collectionReference) {
|
||||
log.trace( "Pushing collection reference to stack : " + collectionReference );
|
||||
collectionReferenceStack.addFirst( collectionReference );
|
||||
}
|
||||
|
||||
private CollectionReference popFromCollectionStack() {
|
||||
final CollectionReference last = collectionReferenceStack.removeFirst();
|
||||
log.trace( "Popped collection reference from stack : " + last );
|
||||
if ( FetchStackAware.class.isInstance( last ) ) {
|
||||
( (FetchStackAware) last ).poppedFromStack();
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
protected abstract EntityReturn buildRootEntityReturn(EntityDefinition entityDefinition);
|
||||
|
||||
protected abstract CollectionReturn buildRootCollectionReturn(CollectionDefinition collectionDefinition);
|
||||
|
||||
protected abstract CollectionFetch buildCollectionFetch(
|
||||
FetchOwner fetchOwner,
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy);
|
||||
|
||||
protected abstract EntityFetch buildEntityFetch(
|
||||
FetchOwner fetchOwner,
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy);
|
||||
|
||||
protected abstract CompositeFetch buildCompositeFetch(FetchOwner fetchOwner, CompositeDefinition attributeDefinition);
|
||||
// LoadPlanBuildingContext impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private int currentSuffixBase;
|
||||
private int implicitAliasUniqueness = 0;
|
||||
|
||||
private String createImplicitAlias() {
|
||||
return "ia" + implicitAliasUniqueness++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases resolveEntityColumnAliases(AssociationAttributeDefinition attributeDefinition) {
|
||||
return generateEntityColumnAliases( attributeDefinition.toEntityDefinition().getEntityPersister() );
|
||||
}
|
||||
|
||||
protected EntityAliases generateEntityColumnAliases(EntityPersister persister) {
|
||||
return new DefaultEntityAliases( (Loadable) persister, Integer.toString( currentSuffixBase++ ) + '_' );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionAliases resolveCollectionColumnAliases(AssociationAttributeDefinition attributeDefinition) {
|
||||
return generateCollectionColumnAliases( attributeDefinition.toCollectionDefinition().getCollectionPersister() );
|
||||
}
|
||||
|
||||
protected CollectionAliases generateCollectionColumnAliases(CollectionPersister persister) {
|
||||
return new GeneratedCollectionAliases( persister, Integer.toString( currentSuffixBase++ ) + '_' );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveRootSourceAlias(EntityDefinition definition) {
|
||||
return createImplicitAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveRootSourceAlias(CollectionDefinition definition) {
|
||||
return createImplicitAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveFetchSourceAlias(AssociationAttributeDefinition attributeDefinition) {
|
||||
return createImplicitAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveFetchSourceAlias(CompositionDefinition compositionDefinition) {
|
||||
return createImplicitAlias();
|
||||
}
|
||||
|
||||
public static interface FetchStackAware {
|
||||
public void poppedFromStack();
|
||||
}
|
||||
|
||||
protected static abstract class AbstractIdentifierAttributeCollector
|
||||
implements FetchOwner, EntityReference, FetchStackAware {
|
||||
|
||||
protected final EntityReference entityReference;
|
||||
private final PropertyPath propertyPath;
|
||||
|
||||
protected final List<EntityFetch> identifierFetches = new ArrayList<EntityFetch>();
|
||||
protected final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap
|
||||
= new HashMap<EntityFetch, HydratedCompoundValueHandler>();
|
||||
|
||||
public AbstractIdentifierAttributeCollector(EntityReference entityReference) {
|
||||
this.entityReference = entityReference;
|
||||
this.propertyPath = ( (FetchOwner) entityReference ).getPropertyPath().append( "<id>" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return entityReference.getAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockMode getLockMode() {
|
||||
return entityReference.getLockMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister getEntityPersister() {
|
||||
return entityReference.getEntityPersister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDescription getIdentifierDescription() {
|
||||
return entityReference.getIdentifierDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
throw new WalkingException( "Entity identifier cannot contain persistent collections" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
// we have a key-many-to-one
|
||||
//
|
||||
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch
|
||||
// impl. We collect them there and later build the IdentifierDescription
|
||||
final EntityFetch fetch = LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
fetchToHydratedStateExtractorMap.put( fetch, attributeDefinition.getHydratedCompoundValueExtractor() );
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
// nested composition. Unusual, but not disallowed.
|
||||
//
|
||||
// IMPL NOTE: we pass ourselves as the FetchOwner which will route the fetch back throw our #addFetch
|
||||
// impl. We collect them there and later build the IdentifierDescription
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void poppedFromStack() {
|
||||
final IdentifierDescription identifierDescription = buildIdentifierDescription();
|
||||
entityReference.injectIdentifierDescription( identifierDescription );
|
||||
}
|
||||
|
||||
protected abstract IdentifierDescription buildIdentifierDescription();
|
||||
|
||||
@Override
|
||||
public void addFetch(Fetch fetch) {
|
||||
identifierFetches.add( (EntityFetch) fetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch[] getFetches() {
|
||||
return ( (FetchOwner) entityReference ).getFetches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
||||
( (FetchOwner) entityReference ).validateFetchPlan( fetchStrategy );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return ( (FetchOwner) entityReference ).retrieveFetchSourcePersister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
|
||||
throw new WalkingException(
|
||||
"IdentifierDescription collector should not get injected with IdentifierDescription"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class EncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector {
|
||||
public EncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
|
||||
super( entityReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdentifierDescription buildIdentifierDescription() {
|
||||
return new IdentifierDescriptionImpl(
|
||||
entityReference,
|
||||
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ),
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class NonEncapsulatedIdentifierAttributeCollector extends AbstractIdentifierAttributeCollector {
|
||||
public NonEncapsulatedIdentifierAttributeCollector(EntityReference entityReference) {
|
||||
super( entityReference );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdentifierDescription buildIdentifierDescription() {
|
||||
return new IdentifierDescriptionImpl(
|
||||
entityReference,
|
||||
identifierFetches.toArray( new EntityFetch[ identifierFetches.size() ] ),
|
||||
fetchToHydratedStateExtractorMap
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static class IdentifierDescriptionImpl implements IdentifierDescription {
|
||||
private final EntityReference entityReference;
|
||||
private final EntityFetch[] identifierFetches;
|
||||
private final Map<EntityFetch,HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap;
|
||||
|
||||
private IdentifierDescriptionImpl(
|
||||
EntityReference entityReference, EntityFetch[] identifierFetches,
|
||||
Map<EntityFetch, HydratedCompoundValueHandler> fetchToHydratedStateExtractorMap) {
|
||||
this.entityReference = entityReference;
|
||||
this.identifierFetches = identifierFetches;
|
||||
this.fetchToHydratedStateExtractorMap = fetchToHydratedStateExtractorMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch[] getFetches() {
|
||||
return identifierFetches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
final IdentifierResolutionContext ownerIdentifierResolutionContext =
|
||||
context.getIdentifierResolutionContext( entityReference );
|
||||
final Serializable ownerIdentifierHydratedState = ownerIdentifierResolutionContext.getHydratedForm();
|
||||
|
||||
for ( EntityFetch fetch : identifierFetches ) {
|
||||
final IdentifierResolutionContext identifierResolutionContext =
|
||||
context.getIdentifierResolutionContext( fetch );
|
||||
// if the identifier was already hydrated, nothing to do
|
||||
if ( identifierResolutionContext.getHydratedForm() != null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// try to extract the sub-hydrated value from the owners tuple array
|
||||
if ( fetchToHydratedStateExtractorMap != null && ownerIdentifierHydratedState != null ) {
|
||||
Serializable extracted = (Serializable) fetchToHydratedStateExtractorMap.get( fetch )
|
||||
.extract( ownerIdentifierHydratedState );
|
||||
identifierResolutionContext.registerHydratedForm( extracted );
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we can't, then read from result set
|
||||
fetch.hydrate( resultSet, context );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
for ( EntityFetch fetch : identifierFetches ) {
|
||||
final IdentifierResolutionContext identifierResolutionContext =
|
||||
context.getIdentifierResolutionContext( fetch );
|
||||
if ( identifierResolutionContext.getEntityKey() != null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityKey fetchKey = fetch.resolveInIdentifier( resultSet, context );
|
||||
identifierResolutionContext.registerEntityKey( fetchKey );
|
||||
}
|
||||
|
||||
final IdentifierResolutionContext ownerIdentifierResolutionContext =
|
||||
context.getIdentifierResolutionContext( entityReference );
|
||||
Serializable hydratedState = ownerIdentifierResolutionContext.getHydratedForm();
|
||||
Serializable resolvedId = (Serializable) entityReference.getEntityPersister()
|
||||
.getIdentifierType()
|
||||
.resolve( hydratedState, context.getSession(), null );
|
||||
return context.getSession().generateEntityKey( resolvedId, entityReference.getEntityPersister() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,58 +23,75 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionFetch extends AbstractFetch implements CollectionReference {
|
||||
private final CollectionAliases collectionAliases;
|
||||
private final EntityAliases elementEntityAliases;
|
||||
|
||||
private final CollectionPersister persister;
|
||||
public class CollectionFetch extends AbstractCollectionReference implements CollectionReference, Fetch {
|
||||
private final FetchOwner fetchOwner;
|
||||
private final FetchStrategy fetchStrategy;
|
||||
|
||||
public CollectionFetch(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
String alias,
|
||||
LockMode lockMode,
|
||||
AbstractFetchOwner owner,
|
||||
FetchOwner fetchOwner,
|
||||
FetchStrategy fetchStrategy,
|
||||
String ownerProperty,
|
||||
CollectionAliases collectionAliases,
|
||||
EntityAliases elementEntityAliases) {
|
||||
super( sessionFactory, alias, lockMode, owner, ownerProperty, fetchStrategy );
|
||||
this.collectionAliases = collectionAliases;
|
||||
this.elementEntityAliases = elementEntityAliases;
|
||||
|
||||
final String role = owner.retrieveFetchSourcePersister().getEntityName() + '.' + getOwnerPropertyName();
|
||||
this.persister = sessionFactory.getCollectionPersister( role );
|
||||
super(
|
||||
sessionFactory,
|
||||
alias,
|
||||
lockMode,
|
||||
sessionFactory.getCollectionPersister(
|
||||
fetchOwner.retrieveFetchSourcePersister().getEntityName() + '.' + ownerProperty
|
||||
),
|
||||
fetchOwner.getPropertyPath().append( ownerProperty ),
|
||||
collectionAliases,
|
||||
elementEntityAliases
|
||||
);
|
||||
this.fetchOwner = fetchOwner;
|
||||
this.fetchStrategy = fetchStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionAliases getCollectionAliases() {
|
||||
return collectionAliases;
|
||||
public FetchOwner getOwner() {
|
||||
return fetchOwner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases getElementEntityAliases() {
|
||||
return elementEntityAliases;
|
||||
public String getOwnerPropertyName() {
|
||||
return getPropertyPath().getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionPersister getCollectionPersister() {
|
||||
return persister;
|
||||
public FetchStrategy getFetchStrategy() {
|
||||
return fetchStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return ( (QueryableCollection) getCollectionPersister() ).getElementPersister();
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,12 @@ public interface CollectionReference {
|
|||
*/
|
||||
public CollectionPersister getCollectionPersister();
|
||||
|
||||
public FetchOwner getIndexGraph();
|
||||
|
||||
public FetchOwner getElementGraph();
|
||||
|
||||
public boolean hasEntityElements();
|
||||
|
||||
/**
|
||||
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the
|
||||
* this collection.
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface CollectionReferenceImplementor {
|
||||
}
|
|
@ -23,28 +23,22 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionReturn extends AbstractFetchOwner implements Return, FetchOwner, CollectionReference {
|
||||
public class CollectionReturn extends AbstractCollectionReference implements Return, CollectionReference {
|
||||
private final String ownerEntityName;
|
||||
private final String ownerProperty;
|
||||
private final CollectionAliases collectionAliases;
|
||||
private final EntityAliases elementEntityAliases;
|
||||
|
||||
private final CollectionPersister persister;
|
||||
|
||||
private final PropertyPath propertyPath = new PropertyPath(); // its a root
|
||||
|
||||
public CollectionReturn(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
|
@ -54,14 +48,17 @@ public class CollectionReturn extends AbstractFetchOwner implements Return, Fetc
|
|||
String ownerProperty,
|
||||
CollectionAliases collectionAliases,
|
||||
EntityAliases elementEntityAliases) {
|
||||
super( sessionFactory, alias, lockMode );
|
||||
super(
|
||||
sessionFactory,
|
||||
alias,
|
||||
lockMode,
|
||||
sessionFactory.getCollectionPersister( ownerEntityName + '.' + ownerProperty ),
|
||||
new PropertyPath(), // its a root
|
||||
collectionAliases,
|
||||
elementEntityAliases
|
||||
);
|
||||
this.ownerEntityName = ownerEntityName;
|
||||
this.ownerProperty = ownerProperty;
|
||||
this.collectionAliases = collectionAliases;
|
||||
this.elementEntityAliases = elementEntityAliases;
|
||||
|
||||
final String role = ownerEntityName + '.' + ownerProperty;
|
||||
this.persister = sessionFactory.getCollectionPersister( role );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,31 +80,22 @@ public class CollectionReturn extends AbstractFetchOwner implements Return, Fetc
|
|||
}
|
||||
|
||||
@Override
|
||||
public CollectionAliases getCollectionAliases() {
|
||||
return collectionAliases;
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
// todo : anything to do here?
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases getElementEntityAliases() {
|
||||
return elementEntityAliases;
|
||||
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
// todo : anything to do here?
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionPersister getCollectionPersister() {
|
||||
return persister;
|
||||
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return ( (QueryableCollection) persister ).getElementPersister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
public String toString() {
|
||||
return "CollectionReturn(" + getCollectionPersister().getRole() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CompositeElementGraph extends AbstractPlanNode implements FetchOwner {
|
||||
private final CollectionReference collectionReference;
|
||||
private final PropertyPath propertyPath;
|
||||
private final CollectionPersister collectionPersister;
|
||||
|
||||
private List<Fetch> fetches;
|
||||
public CompositeElementGraph(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
CollectionReference collectionReference,
|
||||
PropertyPath collectionPath) {
|
||||
super( sessionFactory );
|
||||
|
||||
this.collectionReference = collectionReference;
|
||||
this.collectionPersister = collectionReference.getCollectionPersister();
|
||||
this.propertyPath = collectionPath.append( "<elements>" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFetch(Fetch fetch) {
|
||||
if ( fetches == null ) {
|
||||
fetches = new ArrayList<Fetch>();
|
||||
}
|
||||
fetches.add( fetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch[] getFetches() {
|
||||
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return collectionPersister.getOwnerEntityPersister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
throw new HibernateException( "Collection composite element cannot define collections" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
}
|
|
@ -23,12 +23,18 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -48,4 +54,36 @@ public class CompositeFetch extends AbstractFetch implements Fetch {
|
|||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return getOwner().retrieveFetchSourcePersister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CompositeIndexGraph extends AbstractPlanNode implements FetchOwner {
|
||||
private final CollectionReference collectionReference;
|
||||
private final PropertyPath propertyPath;
|
||||
private final CollectionPersister collectionPersister;
|
||||
|
||||
private List<Fetch> fetches;
|
||||
|
||||
public CompositeIndexGraph(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
CollectionReference collectionReference,
|
||||
PropertyPath propertyPath) {
|
||||
super( sessionFactory );
|
||||
this.collectionReference = collectionReference;
|
||||
this.collectionPersister = collectionReference.getCollectionPersister();
|
||||
this.propertyPath = propertyPath.append( "<index>" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFetch(Fetch fetch) {
|
||||
if ( fetches == null ) {
|
||||
fetches = new ArrayList<Fetch>();
|
||||
}
|
||||
fetches.add( fetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch[] getFetches() {
|
||||
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return collectionPersister.getOwnerEntityPersister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
throw new HibernateException( "Composite index cannot define collections" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.type.AssociationType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityElementGraph extends AbstractPlanNode implements FetchOwner, EntityReference {
|
||||
private final CollectionReference collectionReference;
|
||||
private final CollectionPersister collectionPersister;
|
||||
private final AssociationType elementType;
|
||||
private final EntityPersister elementPersister;
|
||||
private final PropertyPath propertyPath;
|
||||
|
||||
private List<Fetch> fetches;
|
||||
|
||||
private IdentifierDescription identifierDescription;
|
||||
|
||||
public EntityElementGraph(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
CollectionReference collectionReference,
|
||||
PropertyPath collectionPath) {
|
||||
super( sessionFactory );
|
||||
|
||||
this.collectionReference = collectionReference;
|
||||
this.collectionPersister = collectionReference.getCollectionPersister();
|
||||
this.elementType = (AssociationType) collectionPersister.getElementType();
|
||||
this.elementPersister = (EntityPersister) this.elementType.getAssociatedJoinable( sessionFactory() );
|
||||
this.propertyPath = collectionPath.append( "<elements>" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockMode getLockMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister getEntityPersister() {
|
||||
return elementPersister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDescription getIdentifierDescription() {
|
||||
return identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFetch(Fetch fetch) {
|
||||
if ( fetches == null ) {
|
||||
fetches = new ArrayList<Fetch>();
|
||||
}
|
||||
fetches.add( fetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch[] getFetches() {
|
||||
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return elementPersister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
|
||||
this.identifierDescription = identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityElementGraph(collection=" + collectionPersister.getRole() + ", type=" + elementPersister.getEntityName() + ")";
|
||||
}
|
||||
}
|
|
@ -23,27 +23,40 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityFetch extends AbstractFetch implements EntityReference {
|
||||
public class EntityFetch extends AbstractFetch implements EntityReference, FetchOwner {
|
||||
private final String sqlTableAlias;
|
||||
private final EntityAliases entityAliases;
|
||||
|
||||
private final EntityType associationType;
|
||||
private final EntityPersister persister;
|
||||
|
||||
private IdentifierDescription identifierDescription;
|
||||
|
||||
public EntityFetch(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
String alias,
|
||||
LockMode lockMode,
|
||||
AbstractFetchOwner owner,
|
||||
FetchOwner owner,
|
||||
String ownerProperty,
|
||||
FetchStrategy fetchStrategy,
|
||||
String sqlTableAlias,
|
||||
|
@ -52,8 +65,8 @@ public class EntityFetch extends AbstractFetch implements EntityReference {
|
|||
this.sqlTableAlias = sqlTableAlias;
|
||||
this.entityAliases = entityAliases;
|
||||
|
||||
final EntityType type = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
|
||||
this.persister = sessionFactory.getEntityPersister( type.getAssociatedEntityName() );
|
||||
this.associationType = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
|
||||
this.persister = sessionFactory.getEntityPersister( associationType.getAssociatedEntityName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,17 +75,174 @@ public class EntityFetch extends AbstractFetch implements EntityReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases getEntityAliases() {
|
||||
return entityAliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlTableAlias() {
|
||||
return sqlTableAlias;
|
||||
public IdentifierDescription getIdentifierDescription() {
|
||||
return identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return persister;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
|
||||
this.identifierDescription = identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
EntityKey entityKey = context.getDictatedRootEntityKey();
|
||||
if ( entityKey != null ) {
|
||||
context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey );
|
||||
return;
|
||||
}
|
||||
|
||||
identifierDescription.hydrate( resultSet, context );
|
||||
|
||||
for ( Fetch fetch : getFetches() ) {
|
||||
fetch.hydrate( resultSet, context );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
final ResultSetProcessingContext.IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this );
|
||||
EntityKey entityKey = identifierResolutionContext.getEntityKey();
|
||||
if ( entityKey == null ) {
|
||||
entityKey = identifierDescription.resolve( resultSet, context );
|
||||
if ( entityKey == null ) {
|
||||
// register the non-existence (though only for one-to-one associations)
|
||||
if ( associationType.isOneToOne() ) {
|
||||
// first, find our owner's entity-key...
|
||||
final EntityKey ownersEntityKey = context.getIdentifierResolutionContext( (EntityReference) getOwner() ).getEntityKey();
|
||||
if ( ownersEntityKey != null ) {
|
||||
context.getSession().getPersistenceContext()
|
||||
.addNullProperty( ownersEntityKey, associationType.getPropertyName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
identifierResolutionContext.registerEntityKey( entityKey );
|
||||
|
||||
for ( Fetch fetch : getFetches() ) {
|
||||
fetch.resolve( resultSet, context );
|
||||
}
|
||||
}
|
||||
|
||||
return entityKey;
|
||||
}
|
||||
|
||||
public EntityKey resolveInIdentifier(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
// todo : may not need to do this if entitykey is already part of the resolution context
|
||||
|
||||
final EntityKey entityKey = resolve( resultSet, context );
|
||||
|
||||
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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
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,
|
||||
getFetchStrategy().getTiming() == FetchTiming.IMMEDIATE,
|
||||
associationType
|
||||
);
|
||||
|
||||
// materialize associations (and initialize the object) later
|
||||
context.registerHydratedEntity( persister, entityKey, entityInstance );
|
||||
}
|
||||
|
||||
return entityKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityFetch(" + getPropertyPath().getFullPath() + " -> " + persister.getEntityName() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.type.AssociationType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityIndexGraph extends AbstractPlanNode implements FetchOwner, EntityReference {
|
||||
private final CollectionReference collectionReference;
|
||||
private final CollectionPersister collectionPersister;
|
||||
private final AssociationType indexType;
|
||||
private final EntityPersister indexPersister;
|
||||
private final PropertyPath propertyPath;
|
||||
|
||||
private List<Fetch> fetches;
|
||||
|
||||
private IdentifierDescription identifierDescription;
|
||||
|
||||
public EntityIndexGraph(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
CollectionReference collectionReference,
|
||||
PropertyPath collectionPath) {
|
||||
super( sessionFactory );
|
||||
this.collectionReference = collectionReference;
|
||||
this.collectionPersister = collectionReference.getCollectionPersister();
|
||||
this.indexType = (AssociationType) collectionPersister.getIndexType();
|
||||
this.indexPersister = (EntityPersister) this.indexType.getAssociatedJoinable( sessionFactory() );
|
||||
this.propertyPath = collectionPath.append( "<index>" ); // todo : do we want the <index> part?
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockMode getLockMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister getEntityPersister() {
|
||||
return indexPersister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierDescription getIdentifierDescription() {
|
||||
return identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFetch(Fetch fetch) {
|
||||
if ( fetches == null ) {
|
||||
fetches = new ArrayList<Fetch>();
|
||||
}
|
||||
fetches.add( fetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch[] getFetches() {
|
||||
return fetches == null ? NO_FETCHES : fetches.toArray( new Fetch[ fetches.size() ] );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister retrieveFetchSourcePersister() {
|
||||
return indexPersister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
|
||||
this.identifierDescription = identifierDescription;
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@
|
|||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +31,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EntityReference {
|
||||
public interface EntityReference extends IdentifierDescriptionInjectable {
|
||||
/**
|
||||
* Retrieve the alias associated with the persister (entity/collection).
|
||||
*
|
||||
|
@ -54,20 +53,5 @@ public interface EntityReference {
|
|||
*/
|
||||
public EntityPersister getEntityPersister();
|
||||
|
||||
/**
|
||||
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the this entity.
|
||||
*
|
||||
* @return The ResultSet alias descriptor.
|
||||
*/
|
||||
public EntityAliases getEntityAliases();
|
||||
|
||||
/**
|
||||
* Obtain the SQL table alias associated with this entity.
|
||||
*
|
||||
* TODO : eventually this needs to not be a String, but a representation like I did for the Antlr3 branch
|
||||
* (AliasRoot, I think it was called)
|
||||
*
|
||||
* @return The SQL table alias for this entity
|
||||
*/
|
||||
public String getSqlTableAlias();
|
||||
public IdentifierDescription getIdentifierDescription();
|
||||
}
|
||||
|
|
|
@ -23,12 +23,25 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.internal.ResultSetProcessorHelper;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
|
||||
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -41,6 +54,8 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
|
|||
|
||||
private final PropertyPath propertyPath = new PropertyPath(); // its a root
|
||||
|
||||
private IdentifierDescription identifierDescription;
|
||||
|
||||
public EntityReturn(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
String alias,
|
||||
|
@ -71,13 +86,8 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases getEntityAliases() {
|
||||
return entityAliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlTableAlias() {
|
||||
return sqlTableAlias;
|
||||
public IdentifierDescription getIdentifierDescription() {
|
||||
return identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,4 +103,83 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
|
|||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCollectionFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardEntityFetch(
|
||||
this,
|
||||
attributeDefinition,
|
||||
fetchStrategy,
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
EntityKey entityKey = context.getDictatedRootEntityKey();
|
||||
if ( entityKey != null ) {
|
||||
context.getIdentifierResolutionContext( this ).registerEntityKey( entityKey );
|
||||
return;
|
||||
}
|
||||
|
||||
identifierDescription.hydrate( resultSet, context );
|
||||
|
||||
for ( Fetch fetch : getFetches() ) {
|
||||
fetch.hydrate( resultSet, context );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
final IdentifierResolutionContext identifierResolutionContext = context.getIdentifierResolutionContext( this );
|
||||
EntityKey entityKey = identifierResolutionContext.getEntityKey();
|
||||
if ( entityKey == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
entityKey = identifierDescription.resolve( resultSet, context );
|
||||
identifierResolutionContext.registerEntityKey( entityKey );
|
||||
|
||||
for ( Fetch fetch : getFetches() ) {
|
||||
fetch.resolve( resultSet, context );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectIdentifierDescription(IdentifierDescription identifierDescription) {
|
||||
this.identifierDescription = identifierDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityReturn(" + persister.getEntityName() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,12 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
|
||||
/**
|
||||
* Contract for associations that are being fetched.
|
||||
|
@ -33,7 +37,7 @@ import org.hibernate.loader.PropertyPath;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Fetch extends FetchOwner {
|
||||
public interface Fetch {
|
||||
/**
|
||||
* Obtain the owner of this fetch.
|
||||
*
|
||||
|
@ -56,4 +60,8 @@ public interface Fetch extends FetchOwner {
|
|||
* @return The property path
|
||||
*/
|
||||
public PropertyPath getPropertyPath();
|
||||
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
|
||||
public Object resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ package org.hibernate.loader.plan.spi;
|
|||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
|
||||
/**
|
||||
* Contract for owners of fetches. Any non-scalar return could be a fetch owner.
|
||||
|
@ -38,6 +40,14 @@ public interface FetchOwner {
|
|||
*/
|
||||
public static final Fetch[] NO_FETCHES = new Fetch[0];
|
||||
|
||||
/**
|
||||
* Contract to add fetches to this owner. Care should be taken in calling this method; it is intended
|
||||
* for Hibernate usage
|
||||
*
|
||||
* @param fetch The fetch to add
|
||||
*/
|
||||
public void addFetch(Fetch fetch);
|
||||
|
||||
/**
|
||||
* Retrieve the fetches owned by this return.
|
||||
*
|
||||
|
@ -65,4 +75,19 @@ public interface FetchOwner {
|
|||
* @return The property path
|
||||
*/
|
||||
public PropertyPath getPropertyPath();
|
||||
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext);
|
||||
|
||||
public EntityFetch buildEntityFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext);
|
||||
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IdentifierDescription {
|
||||
public Fetch[] getFetches();
|
||||
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
|
||||
public EntityKey resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
/**
|
||||
* Ugh
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IdentifierDescriptionInjectable {
|
||||
public void injectIdentifierDescription(IdentifierDescription identifierDescription);
|
||||
}
|
|
@ -55,6 +55,7 @@ public interface LoadPlan {
|
|||
|
||||
public List<Return> getReturns();
|
||||
|
||||
|
||||
// todo : would also like to see "call back" style access for handling "subsequent actions" such as:
|
||||
// 1) follow-on locking
|
||||
// 2) join fetch conversions to subselect fetches
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface LoadPlanBuildingContext {
|
||||
public SessionFactoryImplementor getSessionFactory();
|
||||
|
||||
public CollectionAliases resolveCollectionColumnAliases(AssociationAttributeDefinition attributeDefinition);
|
||||
public EntityAliases resolveEntityColumnAliases(AssociationAttributeDefinition attributeDefinition);
|
||||
|
||||
public String resolveRootSourceAlias(EntityDefinition definition);
|
||||
public String resolveRootSourceAlias(CollectionDefinition definition);
|
||||
|
||||
public String resolveFetchSourceAlias(AssociationAttributeDefinition attributeDefinition);
|
||||
public String resolveFetchSourceAlias(CompositionDefinition compositionDefinition);
|
||||
}
|
|
@ -26,16 +26,16 @@ package org.hibernate.loader.plan.spi;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ReturnVisitationStrategy {
|
||||
public interface LoadPlanVisitationStrategy {
|
||||
/**
|
||||
* Notification we are preparing to start visitation.
|
||||
*/
|
||||
public void start();
|
||||
public void start(LoadPlan loadPlan);
|
||||
|
||||
/**
|
||||
* Notification we are finished visitation.
|
||||
*/
|
||||
public void finish();
|
||||
public void finish(LoadPlan loadPlan);
|
||||
|
||||
/**
|
||||
* Notification that a new root return branch is being started. Will be followed by calls to one of the following
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LoadPlanVisitationStrategyAdapter implements LoadPlanVisitationStrategy {
|
||||
@Override
|
||||
public void start(LoadPlan loadPlan) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish(LoadPlan loadPlan) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingRootReturn(Return rootReturn) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingRootReturn(Return rootReturn) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleScalarReturn(ScalarReturn scalarReturn) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEntityReturn(EntityReturn rootEntityReturn) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCollectionReturn(CollectionReturn rootCollectionReturn) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingFetches(FetchOwner fetchOwner) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingFetches(FetchOwner fetchOwner) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingEntityFetch(EntityFetch entityFetch) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingEntityFetch(EntityFetch entityFetch) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCompositeFetch(CompositeFetch fetch) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCompositeFetch(CompositeFetch fetch) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
|
@ -28,25 +28,25 @@ package org.hibernate.loader.plan.spi;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ReturnVisitor {
|
||||
public static void visit(Return[] rootReturns, ReturnVisitationStrategy strategy) {
|
||||
new ReturnVisitor( strategy ).visitReturns( rootReturns );
|
||||
public class LoadPlanVisitor {
|
||||
public static void visit(LoadPlan loadPlan, LoadPlanVisitationStrategy strategy) {
|
||||
new LoadPlanVisitor( strategy ).visit( loadPlan );
|
||||
}
|
||||
|
||||
private final ReturnVisitationStrategy strategy;
|
||||
private final LoadPlanVisitationStrategy strategy;
|
||||
|
||||
public ReturnVisitor(ReturnVisitationStrategy strategy) {
|
||||
public LoadPlanVisitor(LoadPlanVisitationStrategy strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
private void visitReturns(Return[] rootReturns) {
|
||||
strategy.start();
|
||||
private void visit(LoadPlan loadPlan) {
|
||||
strategy.start( loadPlan );
|
||||
|
||||
for ( Return rootReturn : rootReturns ) {
|
||||
for ( Return rootReturn : loadPlan.getReturns() ) {
|
||||
visitRootReturn( rootReturn );
|
||||
}
|
||||
|
||||
strategy.finish();
|
||||
strategy.finish( loadPlan );
|
||||
}
|
||||
|
||||
private void visitRootReturn(Return rootReturn) {
|
||||
|
@ -69,7 +69,9 @@ public class ReturnVisitor {
|
|||
}
|
||||
else if ( CollectionReturn.class.isInstance( rootReturn ) ) {
|
||||
strategy.handleCollectionReturn( (CollectionReturn) rootReturn );
|
||||
visitFetches( (CollectionReturn) rootReturn );
|
||||
final CollectionReturn collectionReturn = (CollectionReturn) rootReturn;
|
||||
visitFetches( collectionReturn.getIndexGraph() );
|
||||
visitFetches( collectionReturn.getElementGraph() );
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
|
@ -92,17 +94,18 @@ public class ReturnVisitor {
|
|||
private void visitFetch(Fetch fetch) {
|
||||
if ( EntityFetch.class.isInstance( fetch ) ) {
|
||||
strategy.startingEntityFetch( (EntityFetch) fetch );
|
||||
visitFetches( fetch );
|
||||
visitFetches( (EntityFetch) fetch );
|
||||
strategy.finishingEntityFetch( (EntityFetch) fetch );
|
||||
}
|
||||
else if ( CollectionFetch.class.isInstance( fetch ) ) {
|
||||
strategy.startingCollectionFetch( (CollectionFetch) fetch );
|
||||
visitFetches( fetch );
|
||||
visitFetches( ( (CollectionFetch) fetch ).getIndexGraph() );
|
||||
visitFetches( ( (CollectionFetch) fetch ).getElementGraph() );
|
||||
strategy.finishingCollectionFetch( (CollectionFetch) fetch );
|
||||
}
|
||||
else if ( CompositeFetch.class.isInstance( fetch ) ) {
|
||||
strategy.startingCompositeFetch( (CompositeFetch) fetch );
|
||||
visitFetches( fetch );
|
||||
visitFetches( (CompositeFetch) fetch );
|
||||
strategy.finishingCompositeFetch( (CompositeFetch) fetch );
|
||||
}
|
||||
else {
|
|
@ -23,12 +23,15 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
|
||||
/**
|
||||
* Represents a return value in the query results. Not the same as a result (column) in the JDBC ResultSet!
|
||||
* <p/>
|
||||
* This is merely a unifying contract; it defines no behavior.
|
||||
* <p/>
|
||||
* Return is distinctly different from a {@link Fetch}.
|
||||
* Return is distinctly different from a {@link Fetch} and so modeled as completely separate hierarchy.
|
||||
*
|
||||
* @see ScalarReturn
|
||||
* @see EntityReturn
|
||||
|
@ -37,4 +40,28 @@ package org.hibernate.loader.plan.spi;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Return {
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Effectively performs first phase of two-phase loading. For scalar results first/second phase is one. For
|
||||
* entities, first phase is to resolve identifiers; second phase is to resolve the entity instances.
|
||||
*
|
||||
* @param resultSet The result set being processed
|
||||
* @param context The context for the processing
|
||||
*
|
||||
* @throws SQLException Indicates a problem access the JDBC result set
|
||||
*/
|
||||
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Essentially performs the second phase of two-phase loading.
|
||||
*
|
||||
* @param resultSet The result set being processed
|
||||
* @param context The context for the processing
|
||||
*
|
||||
* @return The read object
|
||||
*
|
||||
* @throws SQLException Indicates a problem access the JDBC result set
|
||||
*/
|
||||
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,12 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.internal.ResultSetProcessingContextImpl;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
|
@ -34,19 +39,30 @@ import org.hibernate.type.Type;
|
|||
*/
|
||||
public class ScalarReturn extends AbstractPlanNode implements Return {
|
||||
private final Type type;
|
||||
private final String columnAlias;
|
||||
private final String[] columnAliases;
|
||||
|
||||
public ScalarReturn(SessionFactoryImplementor factory, Type type, String columnAlias) {
|
||||
public ScalarReturn(SessionFactoryImplementor factory, Type type, String[] columnAliases) {
|
||||
super( factory );
|
||||
this.type = type;
|
||||
this.columnAlias = columnAlias;
|
||||
this.columnAliases = columnAliases;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getColumnAlias() {
|
||||
return columnAlias;
|
||||
@Override
|
||||
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||
return type.nullSafeGet( resultSet, columnAliases, context.getSession(), null );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.spi;
|
||||
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface AfterLoadAction {
|
||||
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
|
||||
}
|
|
@ -33,28 +33,22 @@ import org.hibernate.loader.plan.spi.LoadPlan;
|
|||
import org.hibernate.transform.ResultTransformer;
|
||||
|
||||
/**
|
||||
* Definition of the Loader contract.
|
||||
* <p/>
|
||||
* Capabilities I'd like to see added (todo):<ul>
|
||||
* <li>
|
||||
* expose the underlying "query" (although what I see here relies heavily on
|
||||
* https://github.com/hibernate/hibernate-orm/wiki/Proposal---SQL-generation)
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* Definition of the Loader contract. A Loader is intended to perform loading based on a query and a load-plan.
|
||||
* Under the covers it uses many delegates to perform that work that might be better used individually in
|
||||
* different situations. In general, Loader is intended for being fed a set of results and processing through
|
||||
* all of those result rows in one swoop. For cases that do not fit that template, it is probably better to
|
||||
* individually use the delegates to perform the work.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Loader {
|
||||
public LoadPlan getLoadPlan();
|
||||
|
||||
/**
|
||||
* Obtain the on-demand form of this loader, if possible.
|
||||
* Obtain the LoadPlan this Loader is following.
|
||||
*
|
||||
* @return The on-demand version of this loader
|
||||
* @return
|
||||
*/
|
||||
public OnDemandLoader asOnDemandLoader();
|
||||
public LoadPlan getLoadPlan();
|
||||
|
||||
public List extractResults(
|
||||
ResultSet resultSet,
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
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".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface NamedParameterContext {
|
||||
public int[] getNamedParameterLocations(String name);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
|
@ -25,22 +25,24 @@ package org.hibernate.loader.spi;
|
|||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
||||
/**
|
||||
* Represents an on-demand loading strategy as need for processing single *logical* rows one at a time as required
|
||||
* for {@link org.hibernate.ScrollableResults} implementations.
|
||||
* Contract for processing JDBC ResultSets a single logical row at a time. These are intended for use by
|
||||
* {@link org.hibernate.ScrollableResults} implementations.
|
||||
*
|
||||
* NOTE : these methods initially taken directly from {@link org.hibernate.loader.Loader} counterparts in an effort
|
||||
* to break Loader into manageable pieces, especially in regards to the processing of result sets.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface OnDemandLoader {
|
||||
public interface OnDemandResultSetProcessor {
|
||||
|
||||
/**
|
||||
* Given a ResultSet, extract just a single result row.
|
||||
* Give a ResultSet, extract just a single result row.
|
||||
*
|
||||
* Copy of {@link org.hibernate.loader.Loader#loadSingleRow(ResultSet, SessionImplementor, QueryParameters, boolean)}
|
||||
* Copy of {@link org.hibernate.loader.Loader#loadSingleRow(java.sql.ResultSet, org.hibernate.engine.spi.SessionImplementor, org.hibernate.engine.spi.QueryParameters, boolean)}
|
||||
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
|
||||
* false...)
|
||||
*
|
||||
|
@ -50,19 +52,19 @@ public interface OnDemandLoader {
|
|||
*
|
||||
* @return The extracted result row
|
||||
*
|
||||
* @throws HibernateException Indicates a problem extracting values from the result set.
|
||||
* @throws org.hibernate.HibernateException Indicates a problem extracting values from the result set.
|
||||
*/
|
||||
public Object extractSingleRow(
|
||||
ResultSet resultSet,
|
||||
SessionImplementor session,
|
||||
QueryParameters queryParameters) throws HibernateException;
|
||||
QueryParameters queryParameters);
|
||||
|
||||
/**
|
||||
* Given a ResultSet extract "sequential rows". This is used in cases where we have multi-row fetches that
|
||||
* are sequential within the ResultSet due to ordering. Multiple ResultSet rows are read into a single query
|
||||
* result "row".
|
||||
*
|
||||
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsForward(ResultSet, SessionImplementor, QueryParameters, boolean)}
|
||||
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsForward(java.sql.ResultSet, org.hibernate.engine.spi.SessionImplementor, org.hibernate.engine.spi.QueryParameters, boolean)}
|
||||
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
|
||||
* false...)
|
||||
*
|
||||
|
@ -77,12 +79,12 @@ public interface OnDemandLoader {
|
|||
public Object extractSequentialRowsForward(
|
||||
final ResultSet resultSet,
|
||||
final SessionImplementor session,
|
||||
final QueryParameters queryParameters) throws HibernateException;
|
||||
final QueryParameters queryParameters);
|
||||
|
||||
/**
|
||||
* Like {@link #extractSequentialRowsForward} but here moving back through the ResultSet.
|
||||
*
|
||||
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsReverse(ResultSet, SessionImplementor, QueryParameters, boolean, boolean)}
|
||||
* Copy of {@link org.hibernate.loader.Loader#loadSequentialRowsReverse(java.sql.ResultSet, org.hibernate.engine.spi.SessionImplementor, org.hibernate.engine.spi.QueryParameters, boolean, boolean)}
|
||||
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
|
||||
* false...).
|
||||
*
|
||||
|
@ -101,5 +103,5 @@ public interface OnDemandLoader {
|
|||
ResultSet resultSet,
|
||||
SessionImplementor session,
|
||||
QueryParameters queryParameters,
|
||||
boolean isLogicallyAfterLast) throws HibernateException;
|
||||
boolean isLogicallyAfterLast);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.hibernate.loader.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResultBuilder {
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ResultSetProcessingContext {
|
||||
public SessionImplementor getSession();
|
||||
|
||||
public QueryParameters getQueryParameters();
|
||||
|
||||
public EntityKey getDictatedRootEntityKey();
|
||||
|
||||
public IdentifierResolutionContext getIdentifierResolutionContext(EntityReference entityReference);
|
||||
|
||||
public static interface IdentifierResolutionContext {
|
||||
public EntityReference getEntityReference();
|
||||
|
||||
public void registerHydratedForm(Serializable hydratedForm);
|
||||
|
||||
public Serializable getHydratedForm();
|
||||
|
||||
public void registerEntityKey(EntityKey entityKey);
|
||||
|
||||
public EntityKey getEntityKey();
|
||||
}
|
||||
|
||||
public void registerHydratedEntity(EntityPersister persister, EntityKey entityKey, Object entityInstance);
|
||||
|
||||
public void checkVersion(
|
||||
ResultSet resultSet,
|
||||
EntityPersister persister,
|
||||
EntityAliases entityAliases,
|
||||
EntityKey entityKey,
|
||||
Object entityInstance) throws SQLException;
|
||||
|
||||
public String getConcreteEntityTypeName(
|
||||
ResultSet resultSet,
|
||||
EntityPersister persister,
|
||||
EntityAliases entityAliases,
|
||||
EntityKey entityKey) throws SQLException;
|
||||
|
||||
public void loadFromResultSet(
|
||||
ResultSet resultSet,
|
||||
Object entityInstance,
|
||||
String concreteEntityTypeName,
|
||||
EntityKey entityKey,
|
||||
EntityAliases entityAliases,
|
||||
LockMode acquiredLockMode,
|
||||
EntityPersister persister,
|
||||
boolean eagerFetch,
|
||||
EntityType associationType) throws SQLException;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader.spi;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.transform.ResultTransformer;
|
||||
|
||||
/**
|
||||
* Contract for processing JDBC ResultSets. Separated because ResultSets can be chained and we'd really like to
|
||||
* reuse this logic across all result sets.
|
||||
* <p/>
|
||||
* todo : investigate having this work with non-JDBC results; maybe just typed as Object? or a special Result contract?
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ResultSetProcessor {
|
||||
|
||||
public OnDemandResultSetProcessor toOnDemandForm();
|
||||
|
||||
/**
|
||||
* Process an entire ResultSet, performing all extractions.
|
||||
*
|
||||
* Semi-copy of {@link org.hibernate.loader.Loader#doQuery}, with focus on just the ResultSet processing bit.
|
||||
*
|
||||
* @param resultSet The result set being processed.
|
||||
* @param session The originating session
|
||||
* @param queryParameters The "parameters" used to build the query
|
||||
* @param returnProxies Can proxies be returned (not the same as can they be created!)
|
||||
* @param forcedResultTransformer My old "friend" ResultTransformer...
|
||||
*
|
||||
* @return The extracted results list.
|
||||
*
|
||||
* @throws java.sql.SQLException Indicates a problem access the JDBC ResultSet
|
||||
*/
|
||||
public List extractResults(
|
||||
ResultSet resultSet,
|
||||
SessionImplementor session,
|
||||
QueryParameters queryParameters,
|
||||
NamedParameterContext namedParameterContext,
|
||||
boolean returnProxies,
|
||||
boolean readOnly,
|
||||
ResultTransformer forcedResultTransformer,
|
||||
List<AfterLoadAction> afterLoadActions) throws SQLException;
|
||||
}
|
|
@ -82,7 +82,7 @@ import org.hibernate.persister.entity.Queryable;
|
|||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.sql.Alias;
|
||||
|
@ -1974,7 +1974,7 @@ public abstract class AbstractCollectionPersister
|
|||
}
|
||||
|
||||
@Override
|
||||
public CompositeDefinition toCompositeDefinition() {
|
||||
public CompositionDefinition toCompositeDefinition() {
|
||||
if ( ! getType().isComponentType() ) {
|
||||
throw new IllegalStateException( "Cannot treat entity collection index type as composite" );
|
||||
}
|
||||
|
@ -2006,7 +2006,7 @@ public abstract class AbstractCollectionPersister
|
|||
}
|
||||
|
||||
@Override
|
||||
public CompositeDefinition toCompositeDefinition() {
|
||||
public CompositionDefinition toCompositeDefinition() {
|
||||
if ( ! getType().isComponentType() ) {
|
||||
throw new IllegalStateException( "Cannot treat entity collection element type as composite" );
|
||||
}
|
||||
|
|
|
@ -110,6 +110,11 @@ import org.hibernate.metamodel.binding.SingularAttributeBinding;
|
|||
import org.hibernate.metamodel.relational.DerivedValue;
|
||||
import org.hibernate.metamodel.relational.Value;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AttributeSource;
|
||||
import org.hibernate.persister.walking.spi.EncapsulatedEntityIdentifierDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
import org.hibernate.persister.walking.spi.NonEncapsulatedEntityIdentifierDefinition;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.property.BackrefPropertyAccessor;
|
||||
import org.hibernate.sql.Alias;
|
||||
|
@ -5076,11 +5081,12 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// EntityDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private EntityIdentifierDefinition entityIdentifierDefinition;
|
||||
private Iterable<AttributeDefinition> embeddedCompositeIdentifierAttributes;
|
||||
private Iterable<AttributeDefinition> attributeDefinitions;
|
||||
|
||||
protected void generateEntityDefinition() {
|
||||
collectEmbeddedCompositeIdentifierAttributeDefinitions();
|
||||
prepareEntityIdentifierDefinition();
|
||||
collectAttributeDefinitions();
|
||||
}
|
||||
|
||||
|
@ -5090,8 +5096,8 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
|
||||
return embeddedCompositeIdentifierAttributes;
|
||||
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||
return entityIdentifierDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5099,52 +5105,85 @@ public abstract class AbstractEntityPersister
|
|||
return attributeDefinitions;
|
||||
}
|
||||
|
||||
private synchronized void collectEmbeddedCompositeIdentifierAttributeDefinitions() {
|
||||
|
||||
private void prepareEntityIdentifierDefinition() {
|
||||
final Type idType = getIdentifierType();
|
||||
|
||||
if ( !idType.isComponentType() ) {
|
||||
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
|
||||
return;
|
||||
}
|
||||
|
||||
final CompositeType cidType = (CompositeType) idType;
|
||||
if ( !cidType.isEmbedded() ) {
|
||||
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
|
||||
return;
|
||||
}
|
||||
|
||||
// we have an embedded composite identifier. Most likely we need to process the composite
|
||||
// properties separately, although there is an edge case where the identifier is really
|
||||
// a simple identifier (single value) wrapped in a JPA @IdClass or even in the case of a
|
||||
// a simple identifier (single value) wrapped in a Hibernate composite type.
|
||||
//
|
||||
// We really do not have a built-in method to determine that. However, generally the
|
||||
// persister would report that there is single, physical identifier property which is
|
||||
// explicitly at odds with the notion of "embedded composite". So we use that for now
|
||||
if ( getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
|
||||
this.embeddedCompositeIdentifierAttributes = new Iterable<AttributeDefinition>() {
|
||||
entityIdentifierDefinition = new NonEncapsulatedEntityIdentifierDefinition() {
|
||||
@Override
|
||||
public Iterator<AttributeDefinition> iterator() {
|
||||
return new Iterator<AttributeDefinition>() {
|
||||
private final int numberOfAttributes = countSubclassProperties();
|
||||
private int currentAttributeNumber = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return currentAttributeNumber < numberOfAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeDefinition next() {
|
||||
public Iterable<AttributeDefinition> getAttributes() {
|
||||
// todo : implement
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException( "Remove operation not supported here" );
|
||||
public Class getSeparateIdentifierMappingClass() {
|
||||
// todo : implement
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncapsulated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDefinition getEntityDefinition() {
|
||||
return AbstractEntityPersister.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
private EntityIdentifierDefinition buildEncapsulatedIdentifierDefinition() {
|
||||
final AttributeDefinition simpleIdentifierAttributeAdapter = new AttributeDefinition() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return entityMetamodel.getIdentifierProperty().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return entityMetamodel.getIdentifierProperty().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeSource getSource() {
|
||||
return AbstractEntityPersister.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<identifier-property:" + getName() + ">";
|
||||
}
|
||||
};
|
||||
|
||||
return new EncapsulatedEntityIdentifierDefinition() {
|
||||
@Override
|
||||
public AttributeDefinition getAttributeDefinition() {
|
||||
return simpleIdentifierAttributeAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncapsulated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDefinition getEntityDefinition() {
|
||||
return AbstractEntityPersister.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void collectAttributeDefinitions() {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.spi;
|
||||
|
||||
/**
|
||||
* Where to begin... :)
|
||||
*
|
||||
* This gets to the internal concept of 2-phase loading of entity data and how specifically it is done. Essentially
|
||||
* for composite values, the process of hydration results in a tuple array comprising the composition "atomic" values.
|
||||
* For example, a Name component's hydrated state might look like {@code ["Steve", "L", "Ebersole"]}.
|
||||
*
|
||||
* There are times when we need to be able to extract individual pieces out of the hydrated tuple array. For example,
|
||||
* for an entity with a composite identifier part of which is an association (a key-many-to-one) we often need to
|
||||
* attempt 2-phase processing on the association portion of the identifier's hydrated tuple array.
|
||||
*
|
||||
* This contract allows us access to portions of the hydrated tuple state.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface HydratedCompoundValueHandler {
|
||||
public Object extract(Object hydratedState);
|
||||
public void inject(Object hydratedState, Object value);
|
||||
}
|
|
@ -27,6 +27,7 @@ import org.hibernate.engine.FetchStrategy;
|
|||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -43,4 +44,6 @@ public interface AssociationAttributeDefinition extends AttributeDefinition {
|
|||
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath);
|
||||
|
||||
public CascadeStyle determineCascadeStyle();
|
||||
|
||||
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor();
|
||||
}
|
||||
|
|
|
@ -40,11 +40,20 @@ public interface AssociationVisitationStrategy {
|
|||
public void startingEntity(EntityDefinition entityDefinition);
|
||||
public void finishingEntity(EntityDefinition entityDefinition);
|
||||
|
||||
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
|
||||
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
|
||||
|
||||
public void startingCollection(CollectionDefinition collectionDefinition);
|
||||
public void finishingCollection(CollectionDefinition collectionDefinition);
|
||||
|
||||
public void startingComposite(CompositeDefinition compositeDefinition);
|
||||
public void finishingComposite(CompositeDefinition compositeDefinition);
|
||||
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
|
||||
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
|
||||
|
||||
public void startingCollectionElements(CollectionElementDefinition elementDefinition);
|
||||
public void finishingCollectionElements(CollectionElementDefinition elementDefinition);
|
||||
|
||||
public void startingComposite(CompositionDefinition compositionDefinition);
|
||||
public void finishingComposite(CompositionDefinition compositionDefinition);
|
||||
|
||||
public boolean startingAttribute(AttributeDefinition attributeDefinition);
|
||||
public void finishingAttribute(AttributeDefinition attributeDefinition);
|
||||
|
|
|
@ -35,5 +35,5 @@ public interface CollectionElementDefinition {
|
|||
|
||||
public EntityDefinition toEntityDefinition();
|
||||
|
||||
public CompositeDefinition toCompositeDefinition();
|
||||
public CompositionDefinition toCompositeDefinition();
|
||||
}
|
||||
|
|
|
@ -35,5 +35,5 @@ public interface CollectionIndexDefinition {
|
|||
|
||||
public EntityDefinition toEntityDefinition();
|
||||
|
||||
public CompositeDefinition toCompositeDefinition();
|
||||
public CompositionDefinition toCompositeDefinition();
|
||||
}
|
||||
|
|
|
@ -26,5 +26,5 @@ package org.hibernate.persister.walking.spi;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface CompositeDefinition extends AttributeDefinition, AttributeSource {
|
||||
public interface CompositionDefinition extends AttributeDefinition, AttributeSource {
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.walking.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition {
|
||||
public AttributeDefinition getAttributeDefinition();
|
||||
}
|
|
@ -32,5 +32,5 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
*/
|
||||
public interface EntityDefinition extends AttributeSource {
|
||||
public EntityPersister getEntityPersister();
|
||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes();
|
||||
public EntityIdentifierDefinition getEntityKeyDefinition();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.walking.spi;
|
||||
|
||||
/**
|
||||
* Describes aspects of the identifier for an entity
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface EntityIdentifierDefinition {
|
||||
/**
|
||||
* Is the entity identifier encapsulated? Meaning, is it represented by a single attribute?
|
||||
*
|
||||
* @return {@code true} indicates the identifier is encapsulated (and therefore this is castable to
|
||||
* {@link EncapsulatedEntityIdentifierDefinition}); {@code false} means it is not encapsulated (and therefore
|
||||
* castable to {@link NonEncapsulatedEntityIdentifierDefinition}).
|
||||
*
|
||||
*/
|
||||
public boolean isEncapsulated();
|
||||
|
||||
public EntityDefinition getEntityDefinition();
|
||||
}
|
|
@ -81,28 +81,28 @@ public class MetadataDrivenModelGraphVisitor {
|
|||
|
||||
private void visitEntityDefinition(EntityDefinition entityDefinition) {
|
||||
strategy.startingEntity( entityDefinition );
|
||||
try {
|
||||
|
||||
visitAttributes( entityDefinition );
|
||||
optionallyVisitEmbeddedCompositeIdentifier( entityDefinition );
|
||||
}
|
||||
finally {
|
||||
visitIdentifierDefinition( entityDefinition.getEntityKeyDefinition() );
|
||||
|
||||
strategy.finishingEntity( entityDefinition );
|
||||
}
|
||||
}
|
||||
|
||||
private void optionallyVisitEmbeddedCompositeIdentifier(EntityDefinition entityDefinition) {
|
||||
// if the entity has a composite identifier, see if we need to handle its sub-properties separately
|
||||
final Iterable<AttributeDefinition> embeddedCompositeIdentifierAttributes =
|
||||
entityDefinition.getEmbeddedCompositeIdentifierAttributes();
|
||||
if ( embeddedCompositeIdentifierAttributes == null ) {
|
||||
return;
|
||||
}
|
||||
private void visitIdentifierDefinition(EntityIdentifierDefinition entityIdentifierDefinition) {
|
||||
strategy.startingEntityIdentifier( entityIdentifierDefinition );
|
||||
|
||||
for ( AttributeDefinition attributeDefinition : embeddedCompositeIdentifierAttributes ) {
|
||||
if ( entityIdentifierDefinition.isEncapsulated() ) {
|
||||
visitAttributeDefinition( ( (EncapsulatedEntityIdentifierDefinition) entityIdentifierDefinition).getAttributeDefinition() );
|
||||
}
|
||||
else {
|
||||
for ( AttributeDefinition attributeDefinition : ( (NonEncapsulatedEntityIdentifierDefinition) entityIdentifierDefinition).getAttributes() ) {
|
||||
visitAttributeDefinition( attributeDefinition );
|
||||
}
|
||||
}
|
||||
|
||||
strategy.finishingEntityIdentifier( entityIdentifierDefinition );
|
||||
}
|
||||
|
||||
private void visitAttributes(AttributeSource attributeSource) {
|
||||
for ( AttributeDefinition attributeDefinition : attributeSource.getAttributes() ) {
|
||||
visitAttributeDefinition( attributeDefinition );
|
||||
|
@ -122,7 +122,7 @@ public class MetadataDrivenModelGraphVisitor {
|
|||
visitAssociation( (AssociationAttributeDefinition) attributeDefinition );
|
||||
}
|
||||
else if ( attributeDefinition.getType().isComponentType() ) {
|
||||
visitCompositeDefinition( (CompositeDefinition) attributeDefinition );
|
||||
visitCompositeDefinition( (CompositionDefinition) attributeDefinition );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -148,42 +148,34 @@ public class MetadataDrivenModelGraphVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
private void visitCompositeDefinition(CompositeDefinition compositeDefinition) {
|
||||
strategy.startingComposite( compositeDefinition );
|
||||
try {
|
||||
visitAttributes( compositeDefinition );
|
||||
}
|
||||
finally {
|
||||
strategy.finishingComposite( compositeDefinition );
|
||||
}
|
||||
private void visitCompositeDefinition(CompositionDefinition compositionDefinition) {
|
||||
strategy.startingComposite( compositionDefinition );
|
||||
|
||||
visitAttributes( compositionDefinition );
|
||||
|
||||
strategy.finishingComposite( compositionDefinition );
|
||||
}
|
||||
|
||||
private void visitCollectionDefinition(CollectionDefinition collectionDefinition) {
|
||||
strategy.startingCollection( collectionDefinition );
|
||||
|
||||
try {
|
||||
visitCollectionIndex( collectionDefinition.getIndexDefinition() );
|
||||
visitCollectionIndex( collectionDefinition );
|
||||
visitCollectionElements( collectionDefinition );
|
||||
|
||||
final CollectionElementDefinition elementDefinition = collectionDefinition.getElementDefinition();
|
||||
if ( elementDefinition.getType().isComponentType() ) {
|
||||
visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
|
||||
}
|
||||
else {
|
||||
visitEntityDefinition( elementDefinition.toEntityDefinition() );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
strategy.finishingCollection( collectionDefinition );
|
||||
}
|
||||
}
|
||||
|
||||
private void visitCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
private void visitCollectionIndex(CollectionDefinition collectionDefinition) {
|
||||
final CollectionIndexDefinition collectionIndexDefinition = collectionDefinition.getIndexDefinition();
|
||||
if ( collectionIndexDefinition == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug( "Visiting collection index : " + currentPropertyPath.getFullPath() );
|
||||
currentPropertyPath = currentPropertyPath.append( "<key>" );
|
||||
strategy.startingCollectionIndex( collectionIndexDefinition );
|
||||
|
||||
log.debug( "Visiting index for collection : " + currentPropertyPath.getFullPath() );
|
||||
currentPropertyPath = currentPropertyPath.append( "<index>" );
|
||||
|
||||
try {
|
||||
final Type collectionIndexType = collectionIndexDefinition.getType();
|
||||
if ( collectionIndexType.isComponentType() ) {
|
||||
|
@ -196,6 +188,22 @@ public class MetadataDrivenModelGraphVisitor {
|
|||
finally {
|
||||
currentPropertyPath = currentPropertyPath.getParent();
|
||||
}
|
||||
|
||||
strategy.finishingCollectionIndex( collectionIndexDefinition );
|
||||
}
|
||||
|
||||
private void visitCollectionElements(CollectionDefinition collectionDefinition) {
|
||||
final CollectionElementDefinition elementDefinition = collectionDefinition.getElementDefinition();
|
||||
strategy.startingCollectionElements( elementDefinition );
|
||||
|
||||
if ( elementDefinition.getType().isComponentType() ) {
|
||||
visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
|
||||
}
|
||||
else {
|
||||
visitEntityDefinition( elementDefinition.toEntityDefinition() );
|
||||
}
|
||||
|
||||
strategy.finishingCollectionElements( elementDefinition );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.walking.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface NonEncapsulatedEntityIdentifierDefinition extends EntityIdentifierDefinition {
|
||||
public Iterable<AttributeDefinition> getAttributes();
|
||||
|
||||
public Class getSeparateIdentifierMappingClass();
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.walking.spi;
|
||||
|
||||
import org.hibernate.HibernateError;
|
||||
|
||||
/**
|
||||
* Indicates a problem walking the domain tree. Almost always this indicates an internal error in Hibernate
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class WalkingException extends HibernateError {
|
||||
public WalkingException(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public WalkingException(String message, Throwable root) {
|
||||
super( message, root );
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
import org.hibernate.result.Result;
|
||||
import org.hibernate.result.Return;
|
||||
|
|
|
@ -126,8 +126,12 @@ public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute i
|
|||
return attributeInformation.getFetchMode();
|
||||
}
|
||||
|
||||
protected String loggableMetadata() {
|
||||
return "non-identifier";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Attribute[non-identifier]( " + getName() + ")";
|
||||
return "Attribute(name=" + getName() + ", type=" + getType().getName() + " [" + loggableMetadata() + "])";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ import org.hibernate.property.PropertyAccessor;
|
|||
import org.hibernate.property.PropertyAccessorFactory;
|
||||
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
|
||||
import org.hibernate.tuple.entity.EntityBasedBasicAttribute;
|
||||
import org.hibernate.tuple.entity.EntityBasedCompositeAttribute;
|
||||
import org.hibernate.tuple.entity.EntityBasedCompositionAttribute;
|
||||
import org.hibernate.tuple.entity.VersionProperty;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
@ -282,7 +282,7 @@ public class PropertyFactory {
|
|||
);
|
||||
}
|
||||
case COMPOSITE: {
|
||||
return new EntityBasedCompositeAttribute(
|
||||
return new EntityBasedCompositionAttribute(
|
||||
persister,
|
||||
sessionFactory,
|
||||
attributeNumber,
|
||||
|
|
|
@ -39,7 +39,7 @@ public abstract class AbstractCompositeBasedAttribute
|
|||
private final int ownerAttributeNumber;
|
||||
|
||||
public AbstractCompositeBasedAttribute(
|
||||
AbstractCompositeDefinition source,
|
||||
AbstractCompositionDefinition source,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
int attributeNumber,
|
||||
String attributeName,
|
||||
|
@ -55,7 +55,7 @@ public abstract class AbstractCompositeBasedAttribute
|
|||
}
|
||||
|
||||
@Override
|
||||
public AbstractCompositeDefinition getSource() {
|
||||
return (AbstractCompositeDefinition) super.getSource();
|
||||
public AbstractCompositionDefinition getSource() {
|
||||
return (AbstractCompositionDefinition) super.getSource();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.hibernate.persister.entity.OuterJoinLoadable;
|
|||
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AttributeSource;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.tuple.AbstractNonIdentifierAttribute;
|
||||
import org.hibernate.tuple.BaselineAttributeInformation;
|
||||
|
@ -48,8 +48,9 @@ import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierAttribute implements CompositeDefinition {
|
||||
protected AbstractCompositeDefinition(
|
||||
public abstract class AbstractCompositionDefinition extends AbstractNonIdentifierAttribute implements
|
||||
CompositionDefinition {
|
||||
protected AbstractCompositionDefinition(
|
||||
AttributeSource source,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
int attributeNumber,
|
||||
|
@ -119,41 +120,41 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
|
|||
}
|
||||
|
||||
return new CompositeBasedAssociationAttribute(
|
||||
AbstractCompositeDefinition.this,
|
||||
AbstractCompositionDefinition.this,
|
||||
sessionFactory(),
|
||||
currentAttributeNumber,
|
||||
name,
|
||||
(AssociationType) type,
|
||||
new BaselineAttributeInformation.Builder()
|
||||
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
|
||||
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
|
||||
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
|
||||
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||
.setDirtyCheckable( true )
|
||||
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
|
||||
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||
.createInformation(),
|
||||
AbstractCompositeDefinition.this.attributeNumber(),
|
||||
AbstractCompositionDefinition.this.attributeNumber(),
|
||||
associationKey
|
||||
);
|
||||
}
|
||||
else if ( type.isComponentType() ) {
|
||||
return new CompositeBasedCompositeAttribute(
|
||||
AbstractCompositeDefinition.this,
|
||||
return new CompositionBasedCompositionAttribute(
|
||||
AbstractCompositionDefinition.this,
|
||||
sessionFactory(),
|
||||
currentAttributeNumber,
|
||||
name,
|
||||
(CompositeType) type,
|
||||
new BaselineAttributeInformation.Builder()
|
||||
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
|
||||
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
|
||||
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
|
||||
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||
.setDirtyCheckable( true )
|
||||
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
|
||||
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||
.createInformation()
|
||||
|
@ -161,19 +162,19 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
|
|||
}
|
||||
else {
|
||||
return new CompositeBasedBasicAttribute(
|
||||
AbstractCompositeDefinition.this,
|
||||
AbstractCompositionDefinition.this,
|
||||
sessionFactory(),
|
||||
currentAttributeNumber,
|
||||
name,
|
||||
type,
|
||||
new BaselineAttributeInformation.Builder()
|
||||
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
|
||||
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
|
||||
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
|
||||
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||
.setDirtyCheckable( true )
|
||||
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
|
||||
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||
.createInformation()
|
||||
|
@ -195,8 +196,13 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
|
|||
return ( (EntityDefinition) getSource() ).getEntityPersister();
|
||||
}
|
||||
else {
|
||||
return ( (AbstractCompositeDefinition) getSource() ).locateOwningPersister();
|
||||
}
|
||||
return ( (AbstractCompositionDefinition) getSource() ).locateOwningPersister();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loggableMetadata() {
|
||||
return super.loggableMetadata() + ",composition";
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,8 @@
|
|||
*/
|
||||
package org.hibernate.tuple.component;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
|
@ -34,6 +36,7 @@ import org.hibernate.loader.PropertyPath;
|
|||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||
import org.hibernate.persister.walking.internal.Helper;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||
|
@ -54,7 +57,7 @@ public class CompositeBasedAssociationAttribute
|
|||
private Joinable joinable;
|
||||
|
||||
public CompositeBasedAssociationAttribute(
|
||||
AbstractCompositeDefinition source,
|
||||
AbstractCompositionDefinition source,
|
||||
SessionFactoryImplementor factory,
|
||||
int attributeNumber,
|
||||
String attributeName,
|
||||
|
@ -154,4 +157,29 @@ public class CompositeBasedAssociationAttribute
|
|||
final CompositeType compositeType = (CompositeType) locateOwningPersister().getPropertyType( getName() );
|
||||
return compositeType.getCascadeStyle( attributeNumber() );
|
||||
}
|
||||
|
||||
private HydratedCompoundValueHandler hydratedCompoundValueHandler;
|
||||
|
||||
@Override
|
||||
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor() {
|
||||
if ( hydratedCompoundValueHandler == null ) {
|
||||
hydratedCompoundValueHandler = new HydratedCompoundValueHandler() {
|
||||
@Override
|
||||
public Object extract(Object hydratedState) {
|
||||
return ( (Object[] ) hydratedState )[ attributeNumber() ];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(Object hydratedState, Object value) {
|
||||
( (Object[] ) hydratedState )[ attributeNumber() ] = value;
|
||||
}
|
||||
};
|
||||
}
|
||||
return hydratedCompoundValueHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loggableMetadata() {
|
||||
return super.loggableMetadata() + ",association";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,18 +24,18 @@
|
|||
package org.hibernate.tuple.component;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.tuple.BaselineAttributeInformation;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CompositeBasedCompositeAttribute
|
||||
extends AbstractCompositeDefinition
|
||||
implements CompositeDefinition {
|
||||
public CompositeBasedCompositeAttribute(
|
||||
CompositeDefinition source,
|
||||
public class CompositionBasedCompositionAttribute
|
||||
extends AbstractCompositionDefinition
|
||||
implements CompositionDefinition {
|
||||
public CompositionBasedCompositionAttribute(
|
||||
CompositionDefinition source,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
int attributeNumber,
|
||||
String attributeName,
|
|
@ -33,6 +33,7 @@ import org.hibernate.persister.collection.QueryableCollection;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||
import org.hibernate.persister.walking.internal.Helper;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||
|
@ -152,4 +153,29 @@ public class EntityBasedAssociationAttribute
|
|||
public CascadeStyle determineCascadeStyle() {
|
||||
return getSource().getEntityPersister().getPropertyCascadeStyles()[attributeNumber()];
|
||||
}
|
||||
|
||||
private HydratedCompoundValueHandler hydratedCompoundValueHandler;
|
||||
|
||||
@Override
|
||||
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor() {
|
||||
if ( hydratedCompoundValueHandler == null ) {
|
||||
hydratedCompoundValueHandler = new HydratedCompoundValueHandler() {
|
||||
@Override
|
||||
public Object extract(Object hydratedState) {
|
||||
return ( (Object[] ) hydratedState )[ attributeNumber() ];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(Object hydratedState, Object value) {
|
||||
( (Object[] ) hydratedState )[ attributeNumber() ] = value;
|
||||
}
|
||||
};
|
||||
}
|
||||
return hydratedCompoundValueHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loggableMetadata() {
|
||||
return super.loggableMetadata() + ",association";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,19 +25,19 @@ package org.hibernate.tuple.entity;
|
|||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.tuple.component.AbstractCompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.tuple.component.AbstractCompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.tuple.BaselineAttributeInformation;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityBasedCompositeAttribute
|
||||
extends AbstractCompositeDefinition
|
||||
implements CompositeDefinition {
|
||||
public class EntityBasedCompositionAttribute
|
||||
extends AbstractCompositionDefinition
|
||||
implements CompositionDefinition {
|
||||
|
||||
public EntityBasedCompositeAttribute(
|
||||
public EntityBasedCompositionAttribute(
|
||||
EntityPersister source,
|
||||
SessionFactoryImplementor factory,
|
||||
int attributeNumber,
|
|
@ -119,9 +119,9 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
|
|||
CollectionReturn collectionReturn = ExtraAssertions.assertTyping( CollectionReturn.class, rtn );
|
||||
assertEquals( "abc", collectionReturn.getAlias() );
|
||||
|
||||
assertNotNull( collectionReturn.getFetches() );
|
||||
assertEquals( 1, collectionReturn.getFetches().length ); // the collection elements are fetched
|
||||
Fetch fetch = collectionReturn.getFetches()[0];
|
||||
assertNotNull( collectionReturn.getElementGraph().getFetches() );
|
||||
assertEquals( 1, collectionReturn.getElementGraph().getFetches().length ); // the collection elements are fetched
|
||||
Fetch fetch = collectionReturn.getElementGraph().getFetches()[0];
|
||||
EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
|
||||
assertNotNull( entityFetch.getFetches() );
|
||||
assertEquals( 0, entityFetch.getFetches().length );
|
||||
|
@ -130,8 +130,8 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
|
|||
@Entity( name = "Message" )
|
||||
public static class Message {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
private Integer mid;
|
||||
private String msgTxt;
|
||||
@ManyToOne( cascade = CascadeType.MERGE )
|
||||
@JoinColumn
|
||||
private Poster poster;
|
||||
|
@ -140,7 +140,7 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
|
|||
@Entity( name = "Poster" )
|
||||
public static class Poster {
|
||||
@Id
|
||||
private Integer id;
|
||||
private Integer pid;
|
||||
private String name;
|
||||
@OneToMany(mappedBy = "poster")
|
||||
private List<Message> messages;
|
||||
|
|
|
@ -35,8 +35,11 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.persister.walking.spi.AssociationVisitationStrategy;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
|
||||
|
||||
import org.junit.Test;
|
||||
|
@ -91,6 +94,16 @@ public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollection(CollectionDefinition collectionDefinition) {
|
||||
System.out.println(
|
||||
|
@ -114,23 +127,43 @@ public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void startingComposite(CompositeDefinition compositeDefinition) {
|
||||
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionElements(CollectionElementDefinition elementDefinition) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollectionElements(CollectionElementDefinition elementDefinition) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingComposite(CompositionDefinition compositionDefinition) {
|
||||
System.out.println(
|
||||
String.format(
|
||||
"%s Starting composite (%s)",
|
||||
StringHelper.repeat( ">>", ++depth ),
|
||||
compositeDefinition.toString()
|
||||
compositionDefinition.toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingComposite(CompositeDefinition compositeDefinition) {
|
||||
public void finishingComposite(CompositionDefinition compositionDefinition) {
|
||||
System.out.println(
|
||||
String.format(
|
||||
"%s Finishing composite (%s)",
|
||||
StringHelper.repeat( ">>", depth-- ),
|
||||
compositeDefinition.toString()
|
||||
compositionDefinition.toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.hibernate.persister.spi.PersisterClassResolver;
|
|||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
||||
|
@ -590,8 +591,8 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
|
||||
throw new NotYetImplementedException();
|
||||
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.hibernate.mapping.PersistentClass;
|
|||
import org.hibernate.metadata.ClassMetadata;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
||||
|
@ -680,7 +681,7 @@ public class CustomPersister implements EntityPersister {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
|
||||
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||
throw new NotYetImplementedException();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ log4j.rootLogger=info, stdout
|
|||
log4j.logger.org.hibernate.tool.hbm2ddl=trace
|
||||
log4j.logger.org.hibernate.testing.cache=debug
|
||||
|
||||
log4j.logger.org.hibernate.loader.plan=trace
|
||||
|
||||
# SQL Logging - HHH-6833
|
||||
log4j.logger.org.hibernate.SQL=debug
|
||||
|
||||
|
|
Loading…
Reference in New Issue