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.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.BasicLoader;
|
import org.hibernate.loader.BasicLoader;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
|
|
|
@ -79,6 +79,7 @@ import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.FetchingScrollableResultsImpl;
|
import org.hibernate.internal.FetchingScrollableResultsImpl;
|
||||||
import org.hibernate.internal.ScrollableResultsImpl;
|
import org.hibernate.internal.ScrollableResultsImpl;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
|
@ -245,10 +246,6 @@ public abstract class Loader {
|
||||||
: sql;
|
: sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static interface AfterLoadAction {
|
|
||||||
public void afterLoad(SessionImplementor session, Object entity, Loadable persister);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean shouldUseFollowOnLocking(
|
protected boolean shouldUseFollowOnLocking(
|
||||||
QueryParameters parameters,
|
QueryParameters parameters,
|
||||||
Dialect dialect,
|
Dialect dialect,
|
||||||
|
@ -509,7 +506,7 @@ public abstract class Loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We call getKeyFromResultSet() here so that we can know the
|
// 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
|
// it is also then called from getRowFromResultSet() which is certainly
|
||||||
// not the most efficient. But the call here is needed, and there
|
// not the most efficient. But the call here is needed, and there
|
||||||
// currently is no other way without refactoring of the doQuery()/getRowFromResultSet()
|
// currently is no other way without refactoring of the doQuery()/getRowFromResultSet()
|
||||||
|
@ -527,7 +524,7 @@ public abstract class Loader {
|
||||||
catch ( SQLException sqle ) {
|
catch ( SQLException sqle ) {
|
||||||
throw factory.getSQLExceptionHelper().convert(
|
throw factory.getSQLExceptionHelper().convert(
|
||||||
sqle,
|
sqle,
|
||||||
"could not doAfterTransactionCompletion sequential read of results (forward)",
|
"could not perform sequential read of results (forward)",
|
||||||
getSQLString()
|
getSQLString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.JoinWalker;
|
import org.hibernate.loader.JoinWalker;
|
||||||
import org.hibernate.loader.Loader;
|
import org.hibernate.loader.Loader;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.internal.CriteriaImpl;
|
import org.hibernate.internal.CriteriaImpl;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.OuterJoinLoader;
|
import org.hibernate.loader.OuterJoinLoader;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.persister.entity.Lockable;
|
import org.hibernate.persister.entity.Lockable;
|
||||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||||
|
|
|
@ -27,7 +27,6 @@ import java.sql.ResultSet;
|
||||||
import java.sql.ResultSetMetaData;
|
import java.sql.ResultSetMetaData;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -41,10 +40,7 @@ import org.hibernate.QueryException;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.dialect.Dialect;
|
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.QueryParameters;
|
||||||
import org.hibernate.engine.spi.RowSelection;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.hql.internal.HolderInstantiator;
|
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.CollectionAliases;
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
import org.hibernate.loader.Loader;
|
import org.hibernate.loader.Loader;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.persister.entity.Lockable;
|
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.transform.ResultTransformer;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
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.IteratorImpl;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.BasicLoader;
|
import org.hibernate.loader.BasicLoader;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.param.ParameterSpecification;
|
import org.hibernate.param.ParameterSpecification;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
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.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.loader.CollectionAliases;
|
import org.hibernate.loader.CollectionAliases;
|
||||||
import org.hibernate.loader.DefaultEntityAliases;
|
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
import org.hibernate.loader.GeneratedCollectionAliases;
|
|
||||||
import org.hibernate.loader.PropertyPath;
|
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.AbstractLoadPlanBuilderStrategy;
|
||||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
|
||||||
import org.hibernate.loader.plan.spi.CollectionReturn;
|
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.EntityReturn;
|
||||||
import org.hibernate.loader.plan.spi.FetchOwner;
|
|
||||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||||
import org.hibernate.loader.plan.spi.LoadPlanBuilderStrategy;
|
import org.hibernate.loader.plan.spi.LoadPlanBuilderStrategy;
|
||||||
import org.hibernate.loader.plan.spi.Return;
|
import org.hibernate.loader.plan.spi.Return;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
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.AssociationAttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
|
||||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -74,7 +66,6 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
||||||
private final LoadQueryInfluencers loadQueryInfluencers;
|
private final LoadQueryInfluencers loadQueryInfluencers;
|
||||||
|
|
||||||
private final String rootAlias;
|
private final String rootAlias;
|
||||||
private int currentSuffixBase;
|
|
||||||
|
|
||||||
private Return rootReturn;
|
private Return rootReturn;
|
||||||
|
|
||||||
|
@ -85,10 +76,9 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
||||||
LoadQueryInfluencers loadQueryInfluencers,
|
LoadQueryInfluencers loadQueryInfluencers,
|
||||||
String rootAlias,
|
String rootAlias,
|
||||||
int suffixSeed) {
|
int suffixSeed) {
|
||||||
super( sessionFactory );
|
super( sessionFactory, suffixSeed );
|
||||||
this.loadQueryInfluencers = loadQueryInfluencers;
|
this.loadQueryInfluencers = loadQueryInfluencers;
|
||||||
this.rootAlias = rootAlias;
|
this.rootAlias = rootAlias;
|
||||||
this.currentSuffixBase = suffixSeed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -153,10 +143,7 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
||||||
LockMode.NONE, // todo : for now
|
LockMode.NONE, // todo : for now
|
||||||
entityName,
|
entityName,
|
||||||
StringHelper.generateAlias( StringHelper.unqualifyEntityName( entityName ), currentDepth() ),
|
StringHelper.generateAlias( StringHelper.unqualifyEntityName( entityName ), currentDepth() ),
|
||||||
new DefaultEntityAliases(
|
generateEntityColumnAliases( entityDefinition.getEntityPersister() )
|
||||||
(Loadable) entityDefinition.getEntityPersister(),
|
|
||||||
Integer.toString( currentSuffixBase++ ) + '_'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,17 +152,16 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
||||||
final CollectionPersister persister = collectionDefinition.getCollectionPersister();
|
final CollectionPersister persister = collectionDefinition.getCollectionPersister();
|
||||||
final String collectionRole = persister.getRole();
|
final String collectionRole = persister.getRole();
|
||||||
|
|
||||||
final CollectionAliases collectionAliases = new GeneratedCollectionAliases(
|
final CollectionAliases collectionAliases = generateCollectionColumnAliases(
|
||||||
collectionDefinition.getCollectionPersister(),
|
collectionDefinition.getCollectionPersister()
|
||||||
Integer.toString( currentSuffixBase++ ) + '_'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final Type elementType = collectionDefinition.getCollectionPersister().getElementType();
|
final Type elementType = collectionDefinition.getCollectionPersister().getElementType();
|
||||||
final EntityAliases elementAliases;
|
final EntityAliases elementAliases;
|
||||||
if ( elementType.isEntityType() ) {
|
if ( elementType.isEntityType() ) {
|
||||||
final EntityType entityElementType = (EntityType) elementType;
|
final EntityType entityElementType = (EntityType) elementType;
|
||||||
elementAliases = new DefaultEntityAliases(
|
elementAliases = generateEntityColumnAliases(
|
||||||
(Loadable) entityElementType.getAssociatedJoinable( sessionFactory() ),
|
(EntityPersister) entityElementType.getAssociatedJoinable( sessionFactory() )
|
||||||
Integer.toString( currentSuffixBase++ ) + '_'
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
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(
|
// LoadPlanBuildingContext impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
sessionFactory(),
|
|
||||||
createImplicitAlias(),
|
@Override
|
||||||
LockMode.NONE, // todo : for now
|
public String resolveRootSourceAlias(EntityDefinition definition) {
|
||||||
(AbstractFetchOwner) fetchOwner,
|
return rootAlias;
|
||||||
fetchStrategy,
|
|
||||||
attributeDefinition.getName(),
|
|
||||||
collectionAliases,
|
|
||||||
elementAliases
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected EntityFetch buildEntityFetch(
|
public String resolveRootSourceAlias(CollectionDefinition definition) {
|
||||||
FetchOwner fetchOwner,
|
return rootAlias;
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
SessionFactoryImplementor factory,
|
||||||
String alias,
|
String alias,
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
AbstractFetchOwner owner,
|
FetchOwner owner,
|
||||||
String ownerProperty,
|
String ownerProperty,
|
||||||
FetchStrategy fetchStrategy) {
|
FetchStrategy fetchStrategy) {
|
||||||
super( factory, alias, lockMode );
|
super( factory, alias, lockMode );
|
||||||
|
@ -85,4 +85,9 @@ public abstract class AbstractFetch extends AbstractFetchOwner implements Fetch
|
||||||
public PropertyPath getPropertyPath() {
|
public PropertyPath getPropertyPath() {
|
||||||
return propertyPath;
|
return propertyPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Fetch(" + propertyPath.getFullPath() + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,8 @@ public abstract class AbstractFetchOwner extends AbstractPlanNode implements Fet
|
||||||
return lockMode;
|
return lockMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFetch(Fetch fetch) {
|
@Override
|
||||||
|
public void addFetch(Fetch fetch) {
|
||||||
if ( fetch.getOwner() != this ) {
|
if ( fetch.getOwner() != this ) {
|
||||||
throw new IllegalArgumentException( "Fetch and owner did not match" );
|
throw new IllegalArgumentException( "Fetch and owner did not match" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,29 +23,62 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.plan.spi;
|
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.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.HibernateException;
|
||||||
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
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.AssociationAttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
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.EntityDefinition;
|
||||||
|
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||||
|
import org.hibernate.persister.walking.spi.WalkingException;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import static org.hibernate.loader.spi.ResultSetProcessingContext.IdentifierResolutionContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @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 final SessionFactoryImplementor sessionFactory;
|
||||||
|
|
||||||
private ArrayDeque<FetchOwner> fetchOwnerStack = new ArrayDeque<FetchOwner>();
|
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.sessionFactory = sessionFactory;
|
||||||
|
this.currentSuffixBase = suffixSeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SessionFactoryImplementor sessionFactory() {
|
public SessionFactoryImplementor sessionFactory() {
|
||||||
|
@ -53,21 +86,39 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FetchOwner currentFetchOwner() {
|
protected FetchOwner currentFetchOwner() {
|
||||||
return fetchOwnerStack.peekLast();
|
return fetchOwnerStack.peekFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
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
|
@Override
|
||||||
public void finish() {
|
public void finish() {
|
||||||
// nothing to do
|
fetchOwnerStack.clear();
|
||||||
|
collectionReferenceStack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startingEntity(EntityDefinition entityDefinition) {
|
public void startingEntity(EntityDefinition entityDefinition) {
|
||||||
|
log.tracef(
|
||||||
|
"%s Starting entity : %s",
|
||||||
|
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||||
|
entityDefinition.getEntityPersister().getEntityName()
|
||||||
|
);
|
||||||
|
|
||||||
if ( fetchOwnerStack.isEmpty() ) {
|
if ( fetchOwnerStack.isEmpty() ) {
|
||||||
// this is a root...
|
// this is a root...
|
||||||
if ( ! supportsRootEntityReturns() ) {
|
if ( ! supportsRootEntityReturns() ) {
|
||||||
|
@ -75,7 +126,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
}
|
}
|
||||||
final EntityReturn entityReturn = buildRootEntityReturn( entityDefinition );
|
final EntityReturn entityReturn = buildRootEntityReturn( entityDefinition );
|
||||||
addRootReturn( entityReturn );
|
addRootReturn( entityReturn );
|
||||||
fetchOwnerStack.push( entityReturn );
|
pushToStack( entityReturn );
|
||||||
}
|
}
|
||||||
// otherwise this call should represent a fetch which should have been handled in #startingAttribute
|
// 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
|
@Override
|
||||||
public void finishingEntity(EntityDefinition entityDefinition) {
|
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
|
@Override
|
||||||
public void startingCollection(CollectionDefinition collectionDefinition) {
|
public void startingCollection(CollectionDefinition collectionDefinition) {
|
||||||
|
log.tracef(
|
||||||
|
"%s Starting collection : %s",
|
||||||
|
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||||
|
collectionDefinition.getCollectionPersister().getRole()
|
||||||
|
);
|
||||||
|
|
||||||
if ( fetchOwnerStack.isEmpty() ) {
|
if ( fetchOwnerStack.isEmpty() ) {
|
||||||
// this is a root...
|
// this is a root...
|
||||||
if ( ! supportsRootCollectionReturns() ) {
|
if ( ! supportsRootCollectionReturns() ) {
|
||||||
|
@ -100,7 +252,7 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
}
|
}
|
||||||
final CollectionReturn collectionReturn = buildRootCollectionReturn( collectionDefinition );
|
final CollectionReturn collectionReturn = buildRootCollectionReturn( collectionDefinition );
|
||||||
addRootReturn( collectionReturn );
|
addRootReturn( collectionReturn );
|
||||||
fetchOwnerStack.push( collectionReturn );
|
pushToCollectionStack( collectionReturn );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,24 +261,96 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishingCollection(CollectionDefinition collectionDefinition) {
|
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||||
// nothing to do
|
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
|
@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() ) {
|
if ( fetchOwnerStack.isEmpty() ) {
|
||||||
throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
|
throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishingComposite(CompositeDefinition compositeDefinition) {
|
public void finishingComposite(CompositionDefinition compositionDefinition) {
|
||||||
// nothing to do
|
// 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
|
@Override
|
||||||
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
|
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
|
||||||
|
log.tracef(
|
||||||
|
"%s Starting attribute %s",
|
||||||
|
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||||
|
attributeDefinition
|
||||||
|
);
|
||||||
|
|
||||||
final Type attributeType = attributeDefinition.getType();
|
final Type attributeType = attributeDefinition.getType();
|
||||||
|
|
||||||
final boolean isComponentType = attributeType.isComponentType();
|
final boolean isComponentType = attributeType.isComponentType();
|
||||||
|
@ -136,30 +360,26 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ( isComponentType ) {
|
else if ( isComponentType ) {
|
||||||
return handleCompositeAttribute( (CompositeDefinition) attributeDefinition );
|
return handleCompositeAttribute( (CompositionDefinition) attributeDefinition );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition );
|
return handleAssociationAttribute( (AssociationAttributeDefinition) attributeDefinition );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishingAttribute(AttributeDefinition attributeDefinition) {
|
public void finishingAttribute(AttributeDefinition attributeDefinition) {
|
||||||
final Type attributeType = attributeDefinition.getType();
|
log.tracef(
|
||||||
|
"%s Finishing up attribute : %s",
|
||||||
final boolean isComponentType = attributeType.isComponentType();
|
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||||
final boolean isBasicType = ! ( isComponentType || attributeType.isAssociationType() );
|
attributeDefinition
|
||||||
|
);
|
||||||
if ( ! isBasicType ) {
|
|
||||||
fetchOwnerStack.removeLast();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean handleCompositeAttribute(CompositeDefinition attributeDefinition) {
|
protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) {
|
||||||
final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
|
final FetchOwner fetchOwner = currentFetchOwner();
|
||||||
final CompositeFetch fetch = buildCompositeFetch( fetchOwner, attributeDefinition );
|
final CompositeFetch fetch = fetchOwner.buildCompositeFetch( attributeDefinition, this );
|
||||||
fetchOwnerStack.addLast( fetch );
|
pushToStack( fetch );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,17 +389,20 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FetchOwner fetchOwner = fetchOwnerStack.peekLast();
|
final FetchOwner fetchOwner = currentFetchOwner();
|
||||||
fetchOwner.validateFetchPlan( fetchStrategy );
|
fetchOwner.validateFetchPlan( fetchStrategy );
|
||||||
|
|
||||||
final Fetch associationFetch;
|
final Fetch associationFetch;
|
||||||
if ( attributeDefinition.isCollection() ) {
|
if ( attributeDefinition.isCollection() ) {
|
||||||
associationFetch = buildCollectionFetch( fetchOwner, attributeDefinition, fetchStrategy );
|
associationFetch = fetchOwner.buildCollectionFetch( attributeDefinition, fetchStrategy, this );
|
||||||
}
|
}
|
||||||
else {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -194,19 +417,309 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
return false;
|
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 EntityReturn buildRootEntityReturn(EntityDefinition entityDefinition);
|
||||||
|
|
||||||
protected abstract CollectionReturn buildRootCollectionReturn(CollectionDefinition collectionDefinition);
|
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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.CollectionAliases;
|
import org.hibernate.loader.CollectionAliases;
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class CollectionFetch extends AbstractFetch implements CollectionReference {
|
public class CollectionFetch extends AbstractCollectionReference implements CollectionReference, Fetch {
|
||||||
private final CollectionAliases collectionAliases;
|
private final FetchOwner fetchOwner;
|
||||||
private final EntityAliases elementEntityAliases;
|
private final FetchStrategy fetchStrategy;
|
||||||
|
|
||||||
private final CollectionPersister persister;
|
|
||||||
|
|
||||||
public CollectionFetch(
|
public CollectionFetch(
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
String alias,
|
String alias,
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
AbstractFetchOwner owner,
|
FetchOwner fetchOwner,
|
||||||
FetchStrategy fetchStrategy,
|
FetchStrategy fetchStrategy,
|
||||||
String ownerProperty,
|
String ownerProperty,
|
||||||
CollectionAliases collectionAliases,
|
CollectionAliases collectionAliases,
|
||||||
EntityAliases elementEntityAliases) {
|
EntityAliases elementEntityAliases) {
|
||||||
super( sessionFactory, alias, lockMode, owner, ownerProperty, fetchStrategy );
|
super(
|
||||||
this.collectionAliases = collectionAliases;
|
sessionFactory,
|
||||||
this.elementEntityAliases = elementEntityAliases;
|
alias,
|
||||||
|
lockMode,
|
||||||
final String role = owner.retrieveFetchSourcePersister().getEntityName() + '.' + getOwnerPropertyName();
|
sessionFactory.getCollectionPersister(
|
||||||
this.persister = sessionFactory.getCollectionPersister( role );
|
fetchOwner.retrieveFetchSourcePersister().getEntityName() + '.' + ownerProperty
|
||||||
|
),
|
||||||
|
fetchOwner.getPropertyPath().append( ownerProperty ),
|
||||||
|
collectionAliases,
|
||||||
|
elementEntityAliases
|
||||||
|
);
|
||||||
|
this.fetchOwner = fetchOwner;
|
||||||
|
this.fetchStrategy = fetchStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionAliases getCollectionAliases() {
|
public FetchOwner getOwner() {
|
||||||
return collectionAliases;
|
return fetchOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityAliases getElementEntityAliases() {
|
public String getOwnerPropertyName() {
|
||||||
return elementEntityAliases;
|
return getPropertyPath().getProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionPersister getCollectionPersister() {
|
public FetchStrategy getFetchStrategy() {
|
||||||
return persister;
|
return fetchStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityPersister retrieveFetchSourcePersister() {
|
public PropertyPath getPropertyPath() {
|
||||||
return ( (QueryableCollection) getCollectionPersister() ).getElementPersister();
|
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 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
|
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the
|
||||||
* this collection.
|
* 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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.CollectionAliases;
|
import org.hibernate.loader.CollectionAliases;
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @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 ownerEntityName;
|
||||||
private final String ownerProperty;
|
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(
|
public CollectionReturn(
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
|
@ -54,14 +48,17 @@ public class CollectionReturn extends AbstractFetchOwner implements Return, Fetc
|
||||||
String ownerProperty,
|
String ownerProperty,
|
||||||
CollectionAliases collectionAliases,
|
CollectionAliases collectionAliases,
|
||||||
EntityAliases elementEntityAliases) {
|
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.ownerEntityName = ownerEntityName;
|
||||||
this.ownerProperty = ownerProperty;
|
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
|
@Override
|
||||||
public CollectionAliases getCollectionAliases() {
|
public void hydrate(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||||
return collectionAliases;
|
// todo : anything to do here?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityAliases getElementEntityAliases() {
|
public void resolve(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||||
return elementEntityAliases;
|
// todo : anything to do here?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionPersister getCollectionPersister() {
|
public Object read(ResultSet resultSet, ResultSetProcessingContext context) throws SQLException {
|
||||||
return persister;
|
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateFetchPlan(FetchStrategy fetchStrategy) {
|
public String toString() {
|
||||||
}
|
return "CollectionReturn(" + getCollectionPersister().getRole() + ")";
|
||||||
|
|
||||||
@Override
|
|
||||||
public EntityPersister retrieveFetchSourcePersister() {
|
|
||||||
return ( (QueryableCollection) persister ).getElementPersister();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PropertyPath getPropertyPath() {
|
|
||||||
return propertyPath;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
|
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -48,4 +54,36 @@ public class CompositeFetch extends AbstractFetch implements Fetch {
|
||||||
public EntityPersister retrieveFetchSourcePersister() {
|
public EntityPersister retrieveFetchSourcePersister() {
|
||||||
return getOwner().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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.WrongClassException;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.EntityAliases;
|
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.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
|
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EntityFetch extends AbstractFetch implements EntityReference {
|
public class EntityFetch extends AbstractFetch implements EntityReference, FetchOwner {
|
||||||
private final String sqlTableAlias;
|
private final String sqlTableAlias;
|
||||||
private final EntityAliases entityAliases;
|
private final EntityAliases entityAliases;
|
||||||
|
|
||||||
|
private final EntityType associationType;
|
||||||
private final EntityPersister persister;
|
private final EntityPersister persister;
|
||||||
|
|
||||||
|
private IdentifierDescription identifierDescription;
|
||||||
|
|
||||||
public EntityFetch(
|
public EntityFetch(
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
String alias,
|
String alias,
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
AbstractFetchOwner owner,
|
FetchOwner owner,
|
||||||
String ownerProperty,
|
String ownerProperty,
|
||||||
FetchStrategy fetchStrategy,
|
FetchStrategy fetchStrategy,
|
||||||
String sqlTableAlias,
|
String sqlTableAlias,
|
||||||
|
@ -52,8 +65,8 @@ public class EntityFetch extends AbstractFetch implements EntityReference {
|
||||||
this.sqlTableAlias = sqlTableAlias;
|
this.sqlTableAlias = sqlTableAlias;
|
||||||
this.entityAliases = entityAliases;
|
this.entityAliases = entityAliases;
|
||||||
|
|
||||||
final EntityType type = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
|
this.associationType = (EntityType) owner.retrieveFetchSourcePersister().getPropertyType( ownerProperty );
|
||||||
this.persister = sessionFactory.getEntityPersister( type.getAssociatedEntityName() );
|
this.persister = sessionFactory.getEntityPersister( associationType.getAssociatedEntityName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,17 +75,174 @@ public class EntityFetch extends AbstractFetch implements EntityReference {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityAliases getEntityAliases() {
|
public IdentifierDescription getIdentifierDescription() {
|
||||||
return entityAliases;
|
return identifierDescription;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSqlTableAlias() {
|
|
||||||
return sqlTableAlias;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityPersister retrieveFetchSourcePersister() {
|
public EntityPersister retrieveFetchSourcePersister() {
|
||||||
return persister;
|
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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.loader.EntityAliases;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +31,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface EntityReference {
|
public interface EntityReference extends IdentifierDescriptionInjectable {
|
||||||
/**
|
/**
|
||||||
* Retrieve the alias associated with the persister (entity/collection).
|
* Retrieve the alias associated with the persister (entity/collection).
|
||||||
*
|
*
|
||||||
|
@ -54,20 +53,5 @@ public interface EntityReference {
|
||||||
*/
|
*/
|
||||||
public EntityPersister getEntityPersister();
|
public EntityPersister getEntityPersister();
|
||||||
|
|
||||||
/**
|
public IdentifierDescription getIdentifierDescription();
|
||||||
* 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();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,25 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.plan.spi;
|
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.LockMode;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
import org.hibernate.loader.PropertyPath;
|
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.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
|
* @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 final PropertyPath propertyPath = new PropertyPath(); // its a root
|
||||||
|
|
||||||
|
private IdentifierDescription identifierDescription;
|
||||||
|
|
||||||
public EntityReturn(
|
public EntityReturn(
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
String alias,
|
String alias,
|
||||||
|
@ -71,13 +86,8 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityAliases getEntityAliases() {
|
public IdentifierDescription getIdentifierDescription() {
|
||||||
return entityAliases;
|
return identifierDescription;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSqlTableAlias() {
|
|
||||||
return sqlTableAlias;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,4 +103,83 @@ public class EntityReturn extends AbstractFetchOwner implements Return, FetchOwn
|
||||||
public PropertyPath getPropertyPath() {
|
public PropertyPath getPropertyPath() {
|
||||||
return propertyPath;
|
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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
|
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for associations that are being fetched.
|
* Contract for associations that are being fetched.
|
||||||
|
@ -33,7 +37,7 @@ import org.hibernate.loader.PropertyPath;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Fetch extends FetchOwner {
|
public interface Fetch {
|
||||||
/**
|
/**
|
||||||
* Obtain the owner of this fetch.
|
* Obtain the owner of this fetch.
|
||||||
*
|
*
|
||||||
|
@ -56,4 +60,8 @@ public interface Fetch extends FetchOwner {
|
||||||
* @return The property path
|
* @return The property path
|
||||||
*/
|
*/
|
||||||
public PropertyPath getPropertyPath();
|
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.engine.FetchStrategy;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
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.
|
* 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];
|
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.
|
* Retrieve the fetches owned by this return.
|
||||||
*
|
*
|
||||||
|
@ -65,4 +75,19 @@ public interface FetchOwner {
|
||||||
* @return The property path
|
* @return The property path
|
||||||
*/
|
*/
|
||||||
public PropertyPath getPropertyPath();
|
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();
|
public List<Return> getReturns();
|
||||||
|
|
||||||
|
|
||||||
// todo : would also like to see "call back" style access for handling "subsequent actions" such as:
|
// todo : would also like to see "call back" style access for handling "subsequent actions" such as:
|
||||||
// 1) follow-on locking
|
// 1) follow-on locking
|
||||||
// 2) join fetch conversions to subselect fetches
|
// 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
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ReturnVisitationStrategy {
|
public interface LoadPlanVisitationStrategy {
|
||||||
/**
|
/**
|
||||||
* Notification we are preparing to start visitation.
|
* Notification we are preparing to start visitation.
|
||||||
*/
|
*/
|
||||||
public void start();
|
public void start(LoadPlan loadPlan);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification we are finished visitation.
|
* 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
|
* 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
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ReturnVisitor {
|
public class LoadPlanVisitor {
|
||||||
public static void visit(Return[] rootReturns, ReturnVisitationStrategy strategy) {
|
public static void visit(LoadPlan loadPlan, LoadPlanVisitationStrategy strategy) {
|
||||||
new ReturnVisitor( strategy ).visitReturns( rootReturns );
|
new LoadPlanVisitor( strategy ).visit( loadPlan );
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ReturnVisitationStrategy strategy;
|
private final LoadPlanVisitationStrategy strategy;
|
||||||
|
|
||||||
public ReturnVisitor(ReturnVisitationStrategy strategy) {
|
public LoadPlanVisitor(LoadPlanVisitationStrategy strategy) {
|
||||||
this.strategy = strategy;
|
this.strategy = strategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitReturns(Return[] rootReturns) {
|
private void visit(LoadPlan loadPlan) {
|
||||||
strategy.start();
|
strategy.start( loadPlan );
|
||||||
|
|
||||||
for ( Return rootReturn : rootReturns ) {
|
for ( Return rootReturn : loadPlan.getReturns() ) {
|
||||||
visitRootReturn( rootReturn );
|
visitRootReturn( rootReturn );
|
||||||
}
|
}
|
||||||
|
|
||||||
strategy.finish();
|
strategy.finish( loadPlan );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitRootReturn(Return rootReturn) {
|
private void visitRootReturn(Return rootReturn) {
|
||||||
|
@ -69,7 +69,9 @@ public class ReturnVisitor {
|
||||||
}
|
}
|
||||||
else if ( CollectionReturn.class.isInstance( rootReturn ) ) {
|
else if ( CollectionReturn.class.isInstance( rootReturn ) ) {
|
||||||
strategy.handleCollectionReturn( (CollectionReturn) rootReturn );
|
strategy.handleCollectionReturn( (CollectionReturn) rootReturn );
|
||||||
visitFetches( (CollectionReturn) rootReturn );
|
final CollectionReturn collectionReturn = (CollectionReturn) rootReturn;
|
||||||
|
visitFetches( collectionReturn.getIndexGraph() );
|
||||||
|
visitFetches( collectionReturn.getElementGraph() );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
@ -92,17 +94,18 @@ public class ReturnVisitor {
|
||||||
private void visitFetch(Fetch fetch) {
|
private void visitFetch(Fetch fetch) {
|
||||||
if ( EntityFetch.class.isInstance( fetch ) ) {
|
if ( EntityFetch.class.isInstance( fetch ) ) {
|
||||||
strategy.startingEntityFetch( (EntityFetch) fetch );
|
strategy.startingEntityFetch( (EntityFetch) fetch );
|
||||||
visitFetches( fetch );
|
visitFetches( (EntityFetch) fetch );
|
||||||
strategy.finishingEntityFetch( (EntityFetch) fetch );
|
strategy.finishingEntityFetch( (EntityFetch) fetch );
|
||||||
}
|
}
|
||||||
else if ( CollectionFetch.class.isInstance( fetch ) ) {
|
else if ( CollectionFetch.class.isInstance( fetch ) ) {
|
||||||
strategy.startingCollectionFetch( (CollectionFetch) fetch );
|
strategy.startingCollectionFetch( (CollectionFetch) fetch );
|
||||||
visitFetches( fetch );
|
visitFetches( ( (CollectionFetch) fetch ).getIndexGraph() );
|
||||||
|
visitFetches( ( (CollectionFetch) fetch ).getElementGraph() );
|
||||||
strategy.finishingCollectionFetch( (CollectionFetch) fetch );
|
strategy.finishingCollectionFetch( (CollectionFetch) fetch );
|
||||||
}
|
}
|
||||||
else if ( CompositeFetch.class.isInstance( fetch ) ) {
|
else if ( CompositeFetch.class.isInstance( fetch ) ) {
|
||||||
strategy.startingCompositeFetch( (CompositeFetch) fetch );
|
strategy.startingCompositeFetch( (CompositeFetch) fetch );
|
||||||
visitFetches( fetch );
|
visitFetches( (CompositeFetch) fetch );
|
||||||
strategy.finishingCompositeFetch( (CompositeFetch) fetch );
|
strategy.finishingCompositeFetch( (CompositeFetch) fetch );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
|
@ -23,12 +23,15 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.plan.spi;
|
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!
|
* Represents a return value in the query results. Not the same as a result (column) in the JDBC ResultSet!
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is merely a unifying contract; it defines no behavior.
|
* Return is distinctly different from a {@link Fetch} and so modeled as completely separate hierarchy.
|
||||||
* <p/>
|
|
||||||
* Return is distinctly different from a {@link Fetch}.
|
|
||||||
*
|
*
|
||||||
* @see ScalarReturn
|
* @see ScalarReturn
|
||||||
* @see EntityReturn
|
* @see EntityReturn
|
||||||
|
@ -37,4 +40,28 @@ package org.hibernate.loader.plan.spi;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Return {
|
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;
|
package org.hibernate.loader.plan.spi;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.loader.internal.ResultSetProcessingContextImpl;
|
||||||
|
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,19 +39,30 @@ import org.hibernate.type.Type;
|
||||||
*/
|
*/
|
||||||
public class ScalarReturn extends AbstractPlanNode implements Return {
|
public class ScalarReturn extends AbstractPlanNode implements Return {
|
||||||
private final Type type;
|
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 );
|
super( factory );
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.columnAlias = columnAlias;
|
this.columnAliases = columnAliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getColumnAlias() {
|
@Override
|
||||||
return columnAlias;
|
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;
|
import org.hibernate.transform.ResultTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Definition of the Loader contract.
|
* Definition of the Loader contract. A Loader is intended to perform loading based on a query and a load-plan.
|
||||||
* <p/>
|
* Under the covers it uses many delegates to perform that work that might be better used individually in
|
||||||
* Capabilities I'd like to see added (todo):<ul>
|
* different situations. In general, Loader is intended for being fed a set of results and processing through
|
||||||
* <li>
|
* all of those result rows in one swoop. For cases that do not fit that template, it is probably better to
|
||||||
* expose the underlying "query" (although what I see here relies heavily on
|
* individually use the delegates to perform the work.
|
||||||
* https://github.com/hibernate/hibernate-orm/wiki/Proposal---SQL-generation)
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Loader {
|
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(
|
public List extractResults(
|
||||||
ResultSet resultSet,
|
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
|
* 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
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* statements applied by the authors. All third-party contributions are
|
||||||
* distributed under license by Red Hat Inc.
|
* distributed under license by Red Hat Inc.
|
||||||
|
@ -25,22 +25,24 @@ package org.hibernate.loader.spi;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.engine.spi.QueryParameters;
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
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
|
* Contract for processing JDBC ResultSets a single logical row at a time. These are intended for use by
|
||||||
* for {@link org.hibernate.ScrollableResults} implementations.
|
* {@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
|
* @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
|
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
|
||||||
* false...)
|
* false...)
|
||||||
*
|
*
|
||||||
|
@ -50,19 +52,19 @@ public interface OnDemandLoader {
|
||||||
*
|
*
|
||||||
* @return The extracted result row
|
* @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(
|
public Object extractSingleRow(
|
||||||
ResultSet resultSet,
|
ResultSet resultSet,
|
||||||
SessionImplementor session,
|
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
|
* 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
|
* are sequential within the ResultSet due to ordering. Multiple ResultSet rows are read into a single query
|
||||||
* result "row".
|
* 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
|
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
|
||||||
* false...)
|
* false...)
|
||||||
*
|
*
|
||||||
|
@ -77,12 +79,12 @@ public interface OnDemandLoader {
|
||||||
public Object extractSequentialRowsForward(
|
public Object extractSequentialRowsForward(
|
||||||
final ResultSet resultSet,
|
final ResultSet resultSet,
|
||||||
final SessionImplementor session,
|
final SessionImplementor session,
|
||||||
final QueryParameters queryParameters) throws HibernateException;
|
final QueryParameters queryParameters);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link #extractSequentialRowsForward} but here moving back through the ResultSet.
|
* 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
|
* but dropping the 'returnProxies' (that method has only one use in the entire codebase and it always passes in
|
||||||
* false...).
|
* false...).
|
||||||
*
|
*
|
||||||
|
@ -101,5 +103,5 @@ public interface OnDemandLoader {
|
||||||
ResultSet resultSet,
|
ResultSet resultSet,
|
||||||
SessionImplementor session,
|
SessionImplementor session,
|
||||||
QueryParameters queryParameters,
|
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.CollectionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
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.persister.walking.spi.EntityDefinition;
|
||||||
import org.hibernate.pretty.MessageHelper;
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.sql.Alias;
|
import org.hibernate.sql.Alias;
|
||||||
|
@ -1974,7 +1974,7 @@ public abstract class AbstractCollectionPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompositeDefinition toCompositeDefinition() {
|
public CompositionDefinition toCompositeDefinition() {
|
||||||
if ( ! getType().isComponentType() ) {
|
if ( ! getType().isComponentType() ) {
|
||||||
throw new IllegalStateException( "Cannot treat entity collection index type as composite" );
|
throw new IllegalStateException( "Cannot treat entity collection index type as composite" );
|
||||||
}
|
}
|
||||||
|
@ -2006,7 +2006,7 @@ public abstract class AbstractCollectionPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompositeDefinition toCompositeDefinition() {
|
public CompositionDefinition toCompositeDefinition() {
|
||||||
if ( ! getType().isComponentType() ) {
|
if ( ! getType().isComponentType() ) {
|
||||||
throw new IllegalStateException( "Cannot treat entity collection element type as composite" );
|
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.DerivedValue;
|
||||||
import org.hibernate.metamodel.relational.Value;
|
import org.hibernate.metamodel.relational.Value;
|
||||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
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.pretty.MessageHelper;
|
||||||
import org.hibernate.property.BackrefPropertyAccessor;
|
import org.hibernate.property.BackrefPropertyAccessor;
|
||||||
import org.hibernate.sql.Alias;
|
import org.hibernate.sql.Alias;
|
||||||
|
@ -5076,11 +5081,12 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
// EntityDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// EntityDefinition impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
private EntityIdentifierDefinition entityIdentifierDefinition;
|
||||||
private Iterable<AttributeDefinition> embeddedCompositeIdentifierAttributes;
|
private Iterable<AttributeDefinition> embeddedCompositeIdentifierAttributes;
|
||||||
private Iterable<AttributeDefinition> attributeDefinitions;
|
private Iterable<AttributeDefinition> attributeDefinitions;
|
||||||
|
|
||||||
protected void generateEntityDefinition() {
|
protected void generateEntityDefinition() {
|
||||||
collectEmbeddedCompositeIdentifierAttributeDefinitions();
|
prepareEntityIdentifierDefinition();
|
||||||
collectAttributeDefinitions();
|
collectAttributeDefinitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5090,8 +5096,8 @@ public abstract class AbstractEntityPersister
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
|
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||||
return embeddedCompositeIdentifierAttributes;
|
return entityIdentifierDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5099,52 +5105,85 @@ public abstract class AbstractEntityPersister
|
||||||
return attributeDefinitions;
|
return attributeDefinitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void collectEmbeddedCompositeIdentifierAttributeDefinitions() {
|
|
||||||
|
private void prepareEntityIdentifierDefinition() {
|
||||||
final Type idType = getIdentifierType();
|
final Type idType = getIdentifierType();
|
||||||
|
|
||||||
if ( !idType.isComponentType() ) {
|
if ( !idType.isComponentType() ) {
|
||||||
|
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final CompositeType cidType = (CompositeType) idType;
|
final CompositeType cidType = (CompositeType) idType;
|
||||||
if ( !cidType.isEmbedded() ) {
|
if ( !cidType.isEmbedded() ) {
|
||||||
|
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have an embedded composite identifier. Most likely we need to process the composite
|
entityIdentifierDefinition = new NonEncapsulatedEntityIdentifierDefinition() {
|
||||||
// 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>() {
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<AttributeDefinition> iterator() {
|
public Iterable<AttributeDefinition> getAttributes() {
|
||||||
return new Iterator<AttributeDefinition>() {
|
|
||||||
private final int numberOfAttributes = countSubclassProperties();
|
|
||||||
private int currentAttributeNumber = 0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return currentAttributeNumber < numberOfAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AttributeDefinition next() {
|
|
||||||
// todo : implement
|
// todo : implement
|
||||||
throw new NotYetImplementedException();
|
throw new NotYetImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public Class getSeparateIdentifierMappingClass() {
|
||||||
throw new UnsupportedOperationException( "Remove operation not supported here" );
|
// 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() {
|
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.CascadeStyle;
|
||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
|
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -43,4 +44,6 @@ public interface AssociationAttributeDefinition extends AttributeDefinition {
|
||||||
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath);
|
public FetchStrategy determineFetchPlan(LoadQueryInfluencers loadQueryInfluencers, PropertyPath propertyPath);
|
||||||
|
|
||||||
public CascadeStyle determineCascadeStyle();
|
public CascadeStyle determineCascadeStyle();
|
||||||
|
|
||||||
|
public HydratedCompoundValueHandler getHydratedCompoundValueExtractor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,20 @@ public interface AssociationVisitationStrategy {
|
||||||
public void startingEntity(EntityDefinition entityDefinition);
|
public void startingEntity(EntityDefinition entityDefinition);
|
||||||
public void finishingEntity(EntityDefinition entityDefinition);
|
public void finishingEntity(EntityDefinition entityDefinition);
|
||||||
|
|
||||||
|
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
|
||||||
|
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
|
||||||
|
|
||||||
public void startingCollection(CollectionDefinition collectionDefinition);
|
public void startingCollection(CollectionDefinition collectionDefinition);
|
||||||
public void finishingCollection(CollectionDefinition collectionDefinition);
|
public void finishingCollection(CollectionDefinition collectionDefinition);
|
||||||
|
|
||||||
public void startingComposite(CompositeDefinition compositeDefinition);
|
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
|
||||||
public void finishingComposite(CompositeDefinition compositeDefinition);
|
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 boolean startingAttribute(AttributeDefinition attributeDefinition);
|
||||||
public void finishingAttribute(AttributeDefinition attributeDefinition);
|
public void finishingAttribute(AttributeDefinition attributeDefinition);
|
||||||
|
|
|
@ -35,5 +35,5 @@ public interface CollectionElementDefinition {
|
||||||
|
|
||||||
public EntityDefinition toEntityDefinition();
|
public EntityDefinition toEntityDefinition();
|
||||||
|
|
||||||
public CompositeDefinition toCompositeDefinition();
|
public CompositionDefinition toCompositeDefinition();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,5 +35,5 @@ public interface CollectionIndexDefinition {
|
||||||
|
|
||||||
public EntityDefinition toEntityDefinition();
|
public EntityDefinition toEntityDefinition();
|
||||||
|
|
||||||
public CompositeDefinition toCompositeDefinition();
|
public CompositionDefinition toCompositeDefinition();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,5 +26,5 @@ package org.hibernate.persister.walking.spi;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @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 interface EntityDefinition extends AttributeSource {
|
||||||
public EntityPersister getEntityPersister();
|
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) {
|
private void visitEntityDefinition(EntityDefinition entityDefinition) {
|
||||||
strategy.startingEntity( entityDefinition );
|
strategy.startingEntity( entityDefinition );
|
||||||
try {
|
|
||||||
visitAttributes( entityDefinition );
|
visitAttributes( entityDefinition );
|
||||||
optionallyVisitEmbeddedCompositeIdentifier( entityDefinition );
|
visitIdentifierDefinition( entityDefinition.getEntityKeyDefinition() );
|
||||||
}
|
|
||||||
finally {
|
|
||||||
strategy.finishingEntity( entityDefinition );
|
strategy.finishingEntity( entityDefinition );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void optionallyVisitEmbeddedCompositeIdentifier(EntityDefinition entityDefinition) {
|
private void visitIdentifierDefinition(EntityIdentifierDefinition entityIdentifierDefinition) {
|
||||||
// if the entity has a composite identifier, see if we need to handle its sub-properties separately
|
strategy.startingEntityIdentifier( entityIdentifierDefinition );
|
||||||
final Iterable<AttributeDefinition> embeddedCompositeIdentifierAttributes =
|
|
||||||
entityDefinition.getEmbeddedCompositeIdentifierAttributes();
|
|
||||||
if ( embeddedCompositeIdentifierAttributes == null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( AttributeDefinition attributeDefinition : embeddedCompositeIdentifierAttributes ) {
|
if ( entityIdentifierDefinition.isEncapsulated() ) {
|
||||||
|
visitAttributeDefinition( ( (EncapsulatedEntityIdentifierDefinition) entityIdentifierDefinition).getAttributeDefinition() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for ( AttributeDefinition attributeDefinition : ( (NonEncapsulatedEntityIdentifierDefinition) entityIdentifierDefinition).getAttributes() ) {
|
||||||
visitAttributeDefinition( attributeDefinition );
|
visitAttributeDefinition( attributeDefinition );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strategy.finishingEntityIdentifier( entityIdentifierDefinition );
|
||||||
|
}
|
||||||
|
|
||||||
private void visitAttributes(AttributeSource attributeSource) {
|
private void visitAttributes(AttributeSource attributeSource) {
|
||||||
for ( AttributeDefinition attributeDefinition : attributeSource.getAttributes() ) {
|
for ( AttributeDefinition attributeDefinition : attributeSource.getAttributes() ) {
|
||||||
visitAttributeDefinition( attributeDefinition );
|
visitAttributeDefinition( attributeDefinition );
|
||||||
|
@ -122,7 +122,7 @@ public class MetadataDrivenModelGraphVisitor {
|
||||||
visitAssociation( (AssociationAttributeDefinition) attributeDefinition );
|
visitAssociation( (AssociationAttributeDefinition) attributeDefinition );
|
||||||
}
|
}
|
||||||
else if ( attributeDefinition.getType().isComponentType() ) {
|
else if ( attributeDefinition.getType().isComponentType() ) {
|
||||||
visitCompositeDefinition( (CompositeDefinition) attributeDefinition );
|
visitCompositeDefinition( (CompositionDefinition) attributeDefinition );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -148,42 +148,34 @@ public class MetadataDrivenModelGraphVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitCompositeDefinition(CompositeDefinition compositeDefinition) {
|
private void visitCompositeDefinition(CompositionDefinition compositionDefinition) {
|
||||||
strategy.startingComposite( compositeDefinition );
|
strategy.startingComposite( compositionDefinition );
|
||||||
try {
|
|
||||||
visitAttributes( compositeDefinition );
|
visitAttributes( compositionDefinition );
|
||||||
}
|
|
||||||
finally {
|
strategy.finishingComposite( compositionDefinition );
|
||||||
strategy.finishingComposite( compositeDefinition );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitCollectionDefinition(CollectionDefinition collectionDefinition) {
|
private void visitCollectionDefinition(CollectionDefinition collectionDefinition) {
|
||||||
strategy.startingCollection( collectionDefinition );
|
strategy.startingCollection( collectionDefinition );
|
||||||
|
|
||||||
try {
|
visitCollectionIndex( collectionDefinition );
|
||||||
visitCollectionIndex( collectionDefinition.getIndexDefinition() );
|
visitCollectionElements( collectionDefinition );
|
||||||
|
|
||||||
final CollectionElementDefinition elementDefinition = collectionDefinition.getElementDefinition();
|
|
||||||
if ( elementDefinition.getType().isComponentType() ) {
|
|
||||||
visitCompositeDefinition( elementDefinition.toCompositeDefinition() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
visitEntityDefinition( elementDefinition.toEntityDefinition() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
strategy.finishingCollection( collectionDefinition );
|
strategy.finishingCollection( collectionDefinition );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void visitCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
private void visitCollectionIndex(CollectionDefinition collectionDefinition) {
|
||||||
|
final CollectionIndexDefinition collectionIndexDefinition = collectionDefinition.getIndexDefinition();
|
||||||
if ( collectionIndexDefinition == null ) {
|
if ( collectionIndexDefinition == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug( "Visiting collection index : " + currentPropertyPath.getFullPath() );
|
strategy.startingCollectionIndex( collectionIndexDefinition );
|
||||||
currentPropertyPath = currentPropertyPath.append( "<key>" );
|
|
||||||
|
log.debug( "Visiting index for collection : " + currentPropertyPath.getFullPath() );
|
||||||
|
currentPropertyPath = currentPropertyPath.append( "<index>" );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Type collectionIndexType = collectionIndexDefinition.getType();
|
final Type collectionIndexType = collectionIndexDefinition.getType();
|
||||||
if ( collectionIndexType.isComponentType() ) {
|
if ( collectionIndexType.isComponentType() ) {
|
||||||
|
@ -196,6 +188,22 @@ public class MetadataDrivenModelGraphVisitor {
|
||||||
finally {
|
finally {
|
||||||
currentPropertyPath = currentPropertyPath.getParent();
|
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.CustomLoader;
|
||||||
import org.hibernate.loader.custom.CustomQuery;
|
import org.hibernate.loader.custom.CustomQuery;
|
||||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||||
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.result.NoMoreReturnsException;
|
import org.hibernate.result.NoMoreReturnsException;
|
||||||
import org.hibernate.result.Result;
|
import org.hibernate.result.Result;
|
||||||
import org.hibernate.result.Return;
|
import org.hibernate.result.Return;
|
||||||
|
|
|
@ -126,8 +126,12 @@ public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute i
|
||||||
return attributeInformation.getFetchMode();
|
return attributeInformation.getFetchMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String loggableMetadata() {
|
||||||
|
return "non-identifier";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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.property.PropertyAccessorFactory;
|
||||||
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
|
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
|
||||||
import org.hibernate.tuple.entity.EntityBasedBasicAttribute;
|
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.tuple.entity.VersionProperty;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
@ -282,7 +282,7 @@ public class PropertyFactory {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case COMPOSITE: {
|
case COMPOSITE: {
|
||||||
return new EntityBasedCompositeAttribute(
|
return new EntityBasedCompositionAttribute(
|
||||||
persister,
|
persister,
|
||||||
sessionFactory,
|
sessionFactory,
|
||||||
attributeNumber,
|
attributeNumber,
|
||||||
|
|
|
@ -39,7 +39,7 @@ public abstract class AbstractCompositeBasedAttribute
|
||||||
private final int ownerAttributeNumber;
|
private final int ownerAttributeNumber;
|
||||||
|
|
||||||
public AbstractCompositeBasedAttribute(
|
public AbstractCompositeBasedAttribute(
|
||||||
AbstractCompositeDefinition source,
|
AbstractCompositionDefinition source,
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
int attributeNumber,
|
int attributeNumber,
|
||||||
String attributeName,
|
String attributeName,
|
||||||
|
@ -55,7 +55,7 @@ public abstract class AbstractCompositeBasedAttribute
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractCompositeDefinition getSource() {
|
public AbstractCompositionDefinition getSource() {
|
||||||
return (AbstractCompositeDefinition) super.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.AssociationKey;
|
||||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AttributeSource;
|
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.persister.walking.spi.EntityDefinition;
|
||||||
import org.hibernate.tuple.AbstractNonIdentifierAttribute;
|
import org.hibernate.tuple.AbstractNonIdentifierAttribute;
|
||||||
import org.hibernate.tuple.BaselineAttributeInformation;
|
import org.hibernate.tuple.BaselineAttributeInformation;
|
||||||
|
@ -48,8 +48,9 @@ import static org.hibernate.engine.internal.JoinHelper.getRHSColumnNames;
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierAttribute implements CompositeDefinition {
|
public abstract class AbstractCompositionDefinition extends AbstractNonIdentifierAttribute implements
|
||||||
protected AbstractCompositeDefinition(
|
CompositionDefinition {
|
||||||
|
protected AbstractCompositionDefinition(
|
||||||
AttributeSource source,
|
AttributeSource source,
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
int attributeNumber,
|
int attributeNumber,
|
||||||
|
@ -119,41 +120,41 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CompositeBasedAssociationAttribute(
|
return new CompositeBasedAssociationAttribute(
|
||||||
AbstractCompositeDefinition.this,
|
AbstractCompositionDefinition.this,
|
||||||
sessionFactory(),
|
sessionFactory(),
|
||||||
currentAttributeNumber,
|
currentAttributeNumber,
|
||||||
name,
|
name,
|
||||||
(AssociationType) type,
|
(AssociationType) type,
|
||||||
new BaselineAttributeInformation.Builder()
|
new BaselineAttributeInformation.Builder()
|
||||||
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
|
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
|
||||||
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
|
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||||
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
|
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||||
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
|
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||||
.setDirtyCheckable( true )
|
.setDirtyCheckable( true )
|
||||||
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
|
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||||
.createInformation(),
|
.createInformation(),
|
||||||
AbstractCompositeDefinition.this.attributeNumber(),
|
AbstractCompositionDefinition.this.attributeNumber(),
|
||||||
associationKey
|
associationKey
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ( type.isComponentType() ) {
|
else if ( type.isComponentType() ) {
|
||||||
return new CompositeBasedCompositeAttribute(
|
return new CompositionBasedCompositionAttribute(
|
||||||
AbstractCompositeDefinition.this,
|
AbstractCompositionDefinition.this,
|
||||||
sessionFactory(),
|
sessionFactory(),
|
||||||
currentAttributeNumber,
|
currentAttributeNumber,
|
||||||
name,
|
name,
|
||||||
(CompositeType) type,
|
(CompositeType) type,
|
||||||
new BaselineAttributeInformation.Builder()
|
new BaselineAttributeInformation.Builder()
|
||||||
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
|
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
|
||||||
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
|
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||||
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
|
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||||
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
|
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||||
.setDirtyCheckable( true )
|
.setDirtyCheckable( true )
|
||||||
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
|
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||||
.createInformation()
|
.createInformation()
|
||||||
|
@ -161,19 +162,19 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new CompositeBasedBasicAttribute(
|
return new CompositeBasedBasicAttribute(
|
||||||
AbstractCompositeDefinition.this,
|
AbstractCompositionDefinition.this,
|
||||||
sessionFactory(),
|
sessionFactory(),
|
||||||
currentAttributeNumber,
|
currentAttributeNumber,
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
new BaselineAttributeInformation.Builder()
|
new BaselineAttributeInformation.Builder()
|
||||||
.setInsertable( AbstractCompositeDefinition.this.isInsertable() )
|
.setInsertable( AbstractCompositionDefinition.this.isInsertable() )
|
||||||
.setUpdateable( AbstractCompositeDefinition.this.isUpdateable() )
|
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||||
.setInsertGenerated( AbstractCompositeDefinition.this.isInsertGenerated() )
|
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||||
.setUpdateGenerated( AbstractCompositeDefinition.this.isUpdateGenerated() )
|
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||||
.setDirtyCheckable( true )
|
.setDirtyCheckable( true )
|
||||||
.setVersionable( AbstractCompositeDefinition.this.isVersionable() )
|
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||||
.createInformation()
|
.createInformation()
|
||||||
|
@ -195,8 +196,13 @@ public abstract class AbstractCompositeDefinition extends AbstractNonIdentifierA
|
||||||
return ( (EntityDefinition) getSource() ).getEntityPersister();
|
return ( (EntityDefinition) getSource() ).getEntityPersister();
|
||||||
}
|
}
|
||||||
else {
|
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;
|
package org.hibernate.tuple.component;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
|
@ -34,6 +36,7 @@ import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.Joinable;
|
import org.hibernate.persister.entity.Joinable;
|
||||||
|
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||||
import org.hibernate.persister.walking.internal.Helper;
|
import org.hibernate.persister.walking.internal.Helper;
|
||||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||||
|
@ -54,7 +57,7 @@ public class CompositeBasedAssociationAttribute
|
||||||
private Joinable joinable;
|
private Joinable joinable;
|
||||||
|
|
||||||
public CompositeBasedAssociationAttribute(
|
public CompositeBasedAssociationAttribute(
|
||||||
AbstractCompositeDefinition source,
|
AbstractCompositionDefinition source,
|
||||||
SessionFactoryImplementor factory,
|
SessionFactoryImplementor factory,
|
||||||
int attributeNumber,
|
int attributeNumber,
|
||||||
String attributeName,
|
String attributeName,
|
||||||
|
@ -154,4 +157,29 @@ public class CompositeBasedAssociationAttribute
|
||||||
final CompositeType compositeType = (CompositeType) locateOwningPersister().getPropertyType( getName() );
|
final CompositeType compositeType = (CompositeType) locateOwningPersister().getPropertyType( getName() );
|
||||||
return compositeType.getCascadeStyle( attributeNumber() );
|
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;
|
package org.hibernate.tuple.component;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
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.tuple.BaselineAttributeInformation;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class CompositeBasedCompositeAttribute
|
public class CompositionBasedCompositionAttribute
|
||||||
extends AbstractCompositeDefinition
|
extends AbstractCompositionDefinition
|
||||||
implements CompositeDefinition {
|
implements CompositionDefinition {
|
||||||
public CompositeBasedCompositeAttribute(
|
public CompositionBasedCompositionAttribute(
|
||||||
CompositeDefinition source,
|
CompositionDefinition source,
|
||||||
SessionFactoryImplementor sessionFactory,
|
SessionFactoryImplementor sessionFactory,
|
||||||
int attributeNumber,
|
int attributeNumber,
|
||||||
String attributeName,
|
String attributeName,
|
|
@ -33,6 +33,7 @@ import org.hibernate.persister.collection.QueryableCollection;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.Joinable;
|
import org.hibernate.persister.entity.Joinable;
|
||||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||||
|
import org.hibernate.persister.spi.HydratedCompoundValueHandler;
|
||||||
import org.hibernate.persister.walking.internal.Helper;
|
import org.hibernate.persister.walking.internal.Helper;
|
||||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||||
|
@ -152,4 +153,29 @@ public class EntityBasedAssociationAttribute
|
||||||
public CascadeStyle determineCascadeStyle() {
|
public CascadeStyle determineCascadeStyle() {
|
||||||
return getSource().getEntityPersister().getPropertyCascadeStyles()[attributeNumber()];
|
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.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.tuple.component.AbstractCompositeDefinition;
|
import org.hibernate.tuple.component.AbstractCompositionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CompositeDefinition;
|
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||||
import org.hibernate.tuple.BaselineAttributeInformation;
|
import org.hibernate.tuple.BaselineAttributeInformation;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EntityBasedCompositeAttribute
|
public class EntityBasedCompositionAttribute
|
||||||
extends AbstractCompositeDefinition
|
extends AbstractCompositionDefinition
|
||||||
implements CompositeDefinition {
|
implements CompositionDefinition {
|
||||||
|
|
||||||
public EntityBasedCompositeAttribute(
|
public EntityBasedCompositionAttribute(
|
||||||
EntityPersister source,
|
EntityPersister source,
|
||||||
SessionFactoryImplementor factory,
|
SessionFactoryImplementor factory,
|
||||||
int attributeNumber,
|
int attributeNumber,
|
|
@ -119,9 +119,9 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
|
||||||
CollectionReturn collectionReturn = ExtraAssertions.assertTyping( CollectionReturn.class, rtn );
|
CollectionReturn collectionReturn = ExtraAssertions.assertTyping( CollectionReturn.class, rtn );
|
||||||
assertEquals( "abc", collectionReturn.getAlias() );
|
assertEquals( "abc", collectionReturn.getAlias() );
|
||||||
|
|
||||||
assertNotNull( collectionReturn.getFetches() );
|
assertNotNull( collectionReturn.getElementGraph().getFetches() );
|
||||||
assertEquals( 1, collectionReturn.getFetches().length ); // the collection elements are fetched
|
assertEquals( 1, collectionReturn.getElementGraph().getFetches().length ); // the collection elements are fetched
|
||||||
Fetch fetch = collectionReturn.getFetches()[0];
|
Fetch fetch = collectionReturn.getElementGraph().getFetches()[0];
|
||||||
EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
|
EntityFetch entityFetch = ExtraAssertions.assertTyping( EntityFetch.class, fetch );
|
||||||
assertNotNull( entityFetch.getFetches() );
|
assertNotNull( entityFetch.getFetches() );
|
||||||
assertEquals( 0, entityFetch.getFetches().length );
|
assertEquals( 0, entityFetch.getFetches().length );
|
||||||
|
@ -130,8 +130,8 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
|
||||||
@Entity( name = "Message" )
|
@Entity( name = "Message" )
|
||||||
public static class Message {
|
public static class Message {
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer mid;
|
||||||
private String name;
|
private String msgTxt;
|
||||||
@ManyToOne( cascade = CascadeType.MERGE )
|
@ManyToOne( cascade = CascadeType.MERGE )
|
||||||
@JoinColumn
|
@JoinColumn
|
||||||
private Poster poster;
|
private Poster poster;
|
||||||
|
@ -140,7 +140,7 @@ public class LoadPlanBuilderTest extends BaseCoreFunctionalTestCase {
|
||||||
@Entity( name = "Poster" )
|
@Entity( name = "Poster" )
|
||||||
public static class Poster {
|
public static class Poster {
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer pid;
|
||||||
private String name;
|
private String name;
|
||||||
@OneToMany(mappedBy = "poster")
|
@OneToMany(mappedBy = "poster")
|
||||||
private List<Message> messages;
|
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.AssociationVisitationStrategy;
|
||||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
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.EntityDefinition;
|
||||||
|
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||||
import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
|
import org.hibernate.persister.walking.spi.MetadataDrivenModelGraphVisitor;
|
||||||
|
|
||||||
import org.junit.Test;
|
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
|
@Override
|
||||||
public void startingCollection(CollectionDefinition collectionDefinition) {
|
public void startingCollection(CollectionDefinition collectionDefinition) {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
|
@ -114,23 +127,43 @@ public class BasicWalkingTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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(
|
System.out.println(
|
||||||
String.format(
|
String.format(
|
||||||
"%s Starting composite (%s)",
|
"%s Starting composite (%s)",
|
||||||
StringHelper.repeat( ">>", ++depth ),
|
StringHelper.repeat( ">>", ++depth ),
|
||||||
compositeDefinition.toString()
|
compositionDefinition.toString()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishingComposite(CompositeDefinition compositeDefinition) {
|
public void finishingComposite(CompositionDefinition compositionDefinition) {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
String.format(
|
String.format(
|
||||||
"%s Finishing composite (%s)",
|
"%s Finishing composite (%s)",
|
||||||
StringHelper.repeat( ">>", depth-- ),
|
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.AttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
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.EntityMetamodel;
|
||||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||||
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
||||||
|
@ -590,8 +591,8 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
|
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||||
throw new NotYetImplementedException();
|
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.metadata.ClassMetadata;
|
import org.hibernate.metadata.ClassMetadata;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
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.EntityMetamodel;
|
||||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||||
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
import org.hibernate.tuple.entity.NonPojoInstrumentationMetadata;
|
||||||
|
@ -680,7 +681,7 @@ public class CustomPersister implements EntityPersister {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<AttributeDefinition> getEmbeddedCompositeIdentifierAttributes() {
|
public EntityIdentifierDefinition getEntityKeyDefinition() {
|
||||||
throw new NotYetImplementedException();
|
throw new NotYetImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ log4j.rootLogger=info, stdout
|
||||||
log4j.logger.org.hibernate.tool.hbm2ddl=trace
|
log4j.logger.org.hibernate.tool.hbm2ddl=trace
|
||||||
log4j.logger.org.hibernate.testing.cache=debug
|
log4j.logger.org.hibernate.testing.cache=debug
|
||||||
|
|
||||||
|
log4j.logger.org.hibernate.loader.plan=trace
|
||||||
|
|
||||||
# SQL Logging - HHH-6833
|
# SQL Logging - HHH-6833
|
||||||
log4j.logger.org.hibernate.SQL=debug
|
log4j.logger.org.hibernate.SQL=debug
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue