HHH-7841 - Redesign Loader
This commit is contained in:
parent
073bb53c8f
commit
b6fd7bf223
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* 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 Middleware LLC.
|
||||
* 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
|
||||
|
@ -20,7 +20,6 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.loader.internal;
|
||||
import java.util.List;
|
||||
|
@ -29,26 +28,28 @@ import org.hibernate.LockOptions;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.spi.JoinableAssociation;
|
||||
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.sql.JoinFragment;
|
||||
import org.hibernate.sql.Select;
|
||||
|
||||
/**
|
||||
* Abstract walker for walkers which begin at an entity (criteria
|
||||
* queries and entity loaders).
|
||||
* Represents an entity load query for criteria
|
||||
* queries and entity loaders, used for generating SQL.
|
||||
*
|
||||
* This code is based on the SQL generation code originally in
|
||||
* org.hibernate.loader.AbstractEntityJoinWalker.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public abstract class AbstractEntityLoadQueryImpl extends AbstractLoadQueryImpl {
|
||||
|
||||
private final EntityReturn entityReturn;
|
||||
|
||||
public AbstractEntityLoadQueryImpl(
|
||||
SessionFactoryImplementor factory,
|
||||
EntityReturn entityReturn,
|
||||
List<JoinableAssociationImpl> associations) {
|
||||
super( factory, associations );
|
||||
public AbstractEntityLoadQueryImpl(EntityReturn entityReturn, List<JoinableAssociation> associations) {
|
||||
super( associations );
|
||||
this.entityReturn = entityReturn;
|
||||
}
|
||||
|
||||
|
@ -56,8 +57,9 @@ public abstract class AbstractEntityLoadQueryImpl extends AbstractLoadQueryImpl
|
|||
final String whereString,
|
||||
final String orderByString,
|
||||
final LockOptions lockOptions,
|
||||
final SessionFactoryImplementor factory,
|
||||
final LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
return generateSql( null, whereString, orderByString, "", lockOptions, aliasResolutionContext );
|
||||
return generateSql( null, whereString, orderByString, "", lockOptions, factory, aliasResolutionContext );
|
||||
}
|
||||
|
||||
private String generateSql(
|
||||
|
@ -66,27 +68,30 @@ public abstract class AbstractEntityLoadQueryImpl extends AbstractLoadQueryImpl
|
|||
final String orderBy,
|
||||
final String groupBy,
|
||||
final LockOptions lockOptions,
|
||||
final SessionFactoryImplementor factory,
|
||||
final LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
|
||||
JoinFragment ojf = mergeOuterJoins( aliasResolutionContext );
|
||||
JoinFragment ojf = mergeOuterJoins( factory, aliasResolutionContext );
|
||||
|
||||
// If no projection, then the last suffix should be for the entity return.
|
||||
// TODO: simplify how suffixes are generated/processed.
|
||||
|
||||
|
||||
Select select = new Select( getDialect() )
|
||||
final String entityReturnAlias = resolveEntityReturnAlias( aliasResolutionContext );
|
||||
Select select = new Select( factory.getDialect() )
|
||||
.setLockOptions( lockOptions )
|
||||
.setSelectClause(
|
||||
projection == null ?
|
||||
getPersister().selectFragment(
|
||||
getAlias( aliasResolutionContext ),
|
||||
entityReturnAlias,
|
||||
aliasResolutionContext.resolveEntityColumnAliases( entityReturn ).getSuffix()
|
||||
) + associationSelectString( aliasResolutionContext ) :
|
||||
projection
|
||||
)
|
||||
.setFromClause(
|
||||
getDialect().appendLockHint( lockOptions, getPersister().fromTableFragment( getAlias( aliasResolutionContext ) ) ) +
|
||||
getPersister().fromJoinFragment( getAlias( aliasResolutionContext), true, true )
|
||||
factory.getDialect().appendLockHint(
|
||||
lockOptions,
|
||||
getPersister().fromTableFragment( entityReturnAlias )
|
||||
) + getPersister().fromJoinFragment( entityReturnAlias, true, true )
|
||||
)
|
||||
.setWhereClause( condition )
|
||||
.setOuterJoins(
|
||||
|
@ -96,7 +101,7 @@ public abstract class AbstractEntityLoadQueryImpl extends AbstractLoadQueryImpl
|
|||
.setOrderByClause( orderBy( orderBy, aliasResolutionContext ) )
|
||||
.setGroupByClause( groupBy );
|
||||
|
||||
if ( getFactory().getSettings().isCommentsEnabled() ) {
|
||||
if ( factory.getSettings().isCommentsEnabled() ) {
|
||||
select.setComment( getComment() );
|
||||
}
|
||||
return select.toStatementString();
|
||||
|
@ -104,17 +109,17 @@ public abstract class AbstractEntityLoadQueryImpl extends AbstractLoadQueryImpl
|
|||
|
||||
protected String getWhereFragment(LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
// here we do not bother with the discriminator.
|
||||
return getPersister().whereJoinFragment( getAlias( aliasResolutionContext ), true, true );
|
||||
return getPersister().whereJoinFragment( resolveEntityReturnAlias( aliasResolutionContext ), true, true );
|
||||
}
|
||||
|
||||
public abstract String getComment();
|
||||
protected abstract String getComment();
|
||||
|
||||
public final OuterJoinLoadable getPersister() {
|
||||
protected final OuterJoinLoadable getPersister() {
|
||||
return (OuterJoinLoadable) entityReturn.getEntityPersister();
|
||||
}
|
||||
|
||||
public final String getAlias(LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
return aliasResolutionContext.resolveEntitySqlTableAlias( entityReturn );
|
||||
protected final String resolveEntityReturnAlias(LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
return aliasResolutionContext.resolveEntityTableAlias( entityReturn );
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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.util.Map;
|
||||
|
||||
import org.hibernate.Filter;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.spi.CollectionReference;
|
||||
import org.hibernate.loader.plan.spi.EntityReference;
|
||||
import org.hibernate.loader.plan.spi.Fetch;
|
||||
import org.hibernate.loader.spi.JoinableAssociation;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.sql.JoinType;
|
||||
|
||||
/**
|
||||
* This class represents a joinable association.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public abstract class AbstractJoinableAssociationImpl implements JoinableAssociation {
|
||||
private final PropertyPath propertyPath;
|
||||
private final Fetch currentFetch;
|
||||
private final EntityReference currentEntityReference;
|
||||
private final CollectionReference currentCollectionReference;
|
||||
private final JoinType joinType;
|
||||
private final String withClause;
|
||||
private final Map<String, Filter> enabledFilters;
|
||||
private final boolean hasRestriction;
|
||||
|
||||
public AbstractJoinableAssociationImpl(
|
||||
Fetch currentFetch,
|
||||
EntityReference currentEntityReference,
|
||||
CollectionReference currentCollectionReference,
|
||||
String withClause,
|
||||
boolean hasRestriction,
|
||||
Map<String, Filter> enabledFilters) throws MappingException {
|
||||
this.propertyPath = currentFetch.getPropertyPath();
|
||||
final OuterJoinLoadable ownerPersister = (OuterJoinLoadable) currentFetch.getOwner().retrieveFetchSourcePersister();
|
||||
final int propertyNumber = ownerPersister.getEntityMetamodel().getPropertyIndex( currentFetch.getOwnerPropertyName() );
|
||||
final boolean isNullable = ownerPersister.isSubclassPropertyNullable( propertyNumber );
|
||||
if ( currentFetch.getFetchStrategy().getStyle() == FetchStyle.JOIN ) {
|
||||
joinType = isNullable ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
|
||||
}
|
||||
else {
|
||||
joinType = JoinType.NONE;
|
||||
}
|
||||
this.currentFetch = currentFetch;
|
||||
this.currentEntityReference = currentEntityReference;
|
||||
this.currentCollectionReference = currentCollectionReference;
|
||||
this.withClause = withClause;
|
||||
this.hasRestriction = hasRestriction;
|
||||
this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JoinType getJoinType() {
|
||||
return joinType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch getCurrentFetch() {
|
||||
return currentFetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityReference getCurrentEntityReference() {
|
||||
return currentEntityReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionReference getCurrentCollectionReference() {
|
||||
return currentCollectionReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRestriction() {
|
||||
return hasRestriction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWithClause() {
|
||||
return withClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Filter> getEnabledFilters() {
|
||||
return enabledFilters;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* 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.
|
||||
|
@ -25,7 +25,7 @@ package org.hibernate.loader.internal;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.internal.JoinHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.loader.CollectionAliases;
|
||||
|
@ -41,32 +41,23 @@ import org.hibernate.sql.JoinFragment;
|
|||
import org.hibernate.sql.JoinType;
|
||||
|
||||
/**
|
||||
* Walks the metamodel, searching for joins, and collecting
|
||||
* together information needed by <tt>OuterJoinLoader</tt>.
|
||||
*
|
||||
* @see org.hibernate.loader.OuterJoinLoader
|
||||
* @author Gavin King, Jon Lipsky
|
||||
* Represents a generic load query used for generating SQL.
|
||||
*
|
||||
* This code is based on the SQL generation code originally in
|
||||
* org.hibernate.loader.JoinWalker.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Jon Lipsky
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public abstract class AbstractLoadQueryImpl {
|
||||
|
||||
private final SessionFactoryImplementor factory;
|
||||
private final List<JoinableAssociationImpl> associations;
|
||||
private final List<JoinableAssociation> associations;
|
||||
|
||||
protected AbstractLoadQueryImpl(
|
||||
SessionFactoryImplementor factory,
|
||||
List<JoinableAssociationImpl> associations) {
|
||||
this.factory = factory;
|
||||
protected AbstractLoadQueryImpl(List<JoinableAssociation> associations) {
|
||||
this.associations = associations;
|
||||
}
|
||||
|
||||
protected SessionFactoryImplementor getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
protected Dialect getDialect() {
|
||||
return factory.getDialect();
|
||||
}
|
||||
|
||||
protected String orderBy(final String orderBy, LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
return mergeOrderings( orderBy( associations, aliasResolutionContext ), orderBy );
|
||||
}
|
||||
|
@ -86,16 +77,37 @@ public abstract class AbstractLoadQueryImpl {
|
|||
/**
|
||||
* Generate a sequence of <tt>LEFT OUTER JOIN</tt> clauses for the given associations.
|
||||
*/
|
||||
protected final JoinFragment mergeOuterJoins(LoadQueryAliasResolutionContext aliasResolutionContext)
|
||||
protected final JoinFragment mergeOuterJoins(SessionFactoryImplementor factory, LoadQueryAliasResolutionContext aliasResolutionContext)
|
||||
throws MappingException {
|
||||
JoinFragment joinFragment = getDialect().createOuterJoinFragment();
|
||||
JoinFragment joinFragment = factory.getDialect().createOuterJoinFragment();
|
||||
JoinableAssociation previous = null;
|
||||
for ( JoinableAssociation association : associations ) {
|
||||
final String rhsAlias = aliasResolutionContext.resolveAssociationRhsTableAlias( association );
|
||||
final String[] aliasedLhsColumnNames = aliasResolutionContext.resolveAssociationAliasedLhsColumnNames(
|
||||
association
|
||||
);
|
||||
final String[] rhsColumnNames = JoinHelper.getRHSColumnNames( association.getAssociationType(), factory );
|
||||
final String on = resolveOnCondition( factory, association, aliasResolutionContext );
|
||||
if ( previous != null && previous.isManyToManyWith( association ) ) {
|
||||
addManyToManyJoin( joinFragment, association, ( QueryableCollection ) previous.getJoinable(), aliasResolutionContext );
|
||||
addManyToManyJoin(
|
||||
joinFragment,
|
||||
association,
|
||||
( QueryableCollection ) previous.getJoinable(),
|
||||
rhsAlias,
|
||||
aliasedLhsColumnNames,
|
||||
rhsColumnNames,
|
||||
on
|
||||
);
|
||||
}
|
||||
else {
|
||||
addJoins( joinFragment, association, aliasResolutionContext);
|
||||
addJoins(
|
||||
joinFragment,
|
||||
association,
|
||||
rhsAlias,
|
||||
aliasedLhsColumnNames,
|
||||
rhsColumnNames,
|
||||
on
|
||||
);
|
||||
}
|
||||
previous = association;
|
||||
}
|
||||
|
@ -105,14 +117,15 @@ public abstract class AbstractLoadQueryImpl {
|
|||
/**
|
||||
* Get the order by string required for collection fetching
|
||||
*/
|
||||
// TODO: why is this static?
|
||||
protected static String orderBy(
|
||||
List<JoinableAssociationImpl> associations,
|
||||
List<JoinableAssociation> associations,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext)
|
||||
throws MappingException {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
JoinableAssociation previous = null;
|
||||
for ( JoinableAssociation association : associations ) {
|
||||
final String rhsAlias = aliasResolutionContext.resolveRhsAlias( association );
|
||||
final String rhsAlias = aliasResolutionContext.resolveAssociationRhsTableAlias( association );
|
||||
if ( association.getJoinType() == JoinType.LEFT_OUTER_JOIN ) { // why does this matter?
|
||||
if ( association.getJoinable().isCollection() ) {
|
||||
final QueryableCollection queryableCollection = (QueryableCollection) association.getJoinable();
|
||||
|
@ -198,12 +211,18 @@ public abstract class AbstractLoadQueryImpl {
|
|||
? null
|
||||
: associations.get( i + 1 );
|
||||
final Joinable joinable = association.getJoinable();
|
||||
final EntityAliases currentEntityAliases = aliasResolutionContext.resolveCurrentEntityAliases( association );
|
||||
final CollectionAliases currentCollectionAliases = aliasResolutionContext.resolveCurrentCollectionAliases( association );
|
||||
final EntityAliases currentEntityAliases =
|
||||
association.getCurrentEntityReference() == null ?
|
||||
null :
|
||||
aliasResolutionContext.resolveEntityColumnAliases( association.getCurrentEntityReference() );
|
||||
final CollectionAliases currentCollectionAliases =
|
||||
association.getCurrentCollectionReference() == null ?
|
||||
null :
|
||||
aliasResolutionContext.resolveCollectionColumnAliases( association.getCurrentCollectionReference() );
|
||||
final String selectFragment = joinable.selectFragment(
|
||||
next == null ? null : next.getJoinable(),
|
||||
next == null ? null : aliasResolutionContext.resolveRhsAlias( next ),
|
||||
aliasResolutionContext.resolveRhsAlias( association ),
|
||||
next == null ? null : aliasResolutionContext.resolveAssociationRhsTableAlias( next ),
|
||||
aliasResolutionContext.resolveAssociationRhsTableAlias( association ),
|
||||
currentEntityAliases == null ? null : currentEntityAliases.getSuffix(),
|
||||
currentCollectionAliases == null ? null : currentCollectionAliases.getSuffix(),
|
||||
association.getJoinType()==JoinType.LEFT_OUTER_JOIN
|
||||
|
@ -220,15 +239,17 @@ public abstract class AbstractLoadQueryImpl {
|
|||
private void addJoins(
|
||||
JoinFragment joinFragment,
|
||||
JoinableAssociation association,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
final String rhsAlias = aliasResolutionContext.resolveRhsAlias( association );
|
||||
String rhsAlias,
|
||||
String[] aliasedLhsColumnNames,
|
||||
String[] rhsColumnNames,
|
||||
String on) throws MappingException {
|
||||
joinFragment.addJoin(
|
||||
association.getJoinable().getTableName(),
|
||||
rhsAlias,
|
||||
aliasResolutionContext.resolveAliasedLhsColumnNames( association ),
|
||||
association.getRhsColumns(),
|
||||
aliasedLhsColumnNames,
|
||||
rhsColumnNames,
|
||||
association.getJoinType(),
|
||||
resolveOnCondition( association, aliasResolutionContext )
|
||||
on
|
||||
);
|
||||
joinFragment.addJoins(
|
||||
association.getJoinable().fromJoinFragment( rhsAlias, false, true ),
|
||||
|
@ -236,20 +257,20 @@ public abstract class AbstractLoadQueryImpl {
|
|||
);
|
||||
}
|
||||
|
||||
private String resolveOnCondition(JoinableAssociation joinableAssociation,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
private String resolveOnCondition(
|
||||
SessionFactoryImplementor factory,
|
||||
JoinableAssociation joinableAssociation,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
final String withClause = StringHelper.isEmpty( joinableAssociation.getWithClause() ) ?
|
||||
"" :
|
||||
" and ( " + joinableAssociation.getWithClause() + " )";
|
||||
return joinableAssociation.getJoinableType().getOnCondition(
|
||||
aliasResolutionContext.resolveRhsAlias( joinableAssociation ),
|
||||
return joinableAssociation.getAssociationType().getOnCondition(
|
||||
aliasResolutionContext.resolveAssociationRhsTableAlias( joinableAssociation ),
|
||||
factory,
|
||||
joinableAssociation.getEnabledFilters()
|
||||
) + withClause;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
public void validateJoin(String path) throws MappingException {
|
||||
if ( rhsColumns==null || lhsColumns==null
|
||||
|
@ -263,14 +284,14 @@ public abstract class AbstractLoadQueryImpl {
|
|||
JoinFragment outerjoin,
|
||||
JoinableAssociation association,
|
||||
QueryableCollection collection,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
final String rhsAlias = aliasResolutionContext.resolveRhsAlias( association );
|
||||
final String[] aliasedLhsColumnNames = aliasResolutionContext.resolveAliasedLhsColumnNames( association );
|
||||
String rhsAlias,
|
||||
String[] aliasedLhsColumnNames,
|
||||
String[] rhsColumnNames,
|
||||
String on) throws MappingException {
|
||||
final String manyToManyFilter = collection.getManyToManyFilterFragment(
|
||||
rhsAlias,
|
||||
association.getEnabledFilters()
|
||||
);
|
||||
final String on = resolveOnCondition( association, aliasResolutionContext );
|
||||
String condition = "".equals( manyToManyFilter )
|
||||
? on
|
||||
: "".equals( on )
|
||||
|
@ -280,7 +301,7 @@ public abstract class AbstractLoadQueryImpl {
|
|||
association.getJoinable().getTableName(),
|
||||
rhsAlias,
|
||||
aliasedLhsColumnNames,
|
||||
association.getRhsColumns(),
|
||||
rhsColumnNames,
|
||||
association.getJoinType(),
|
||||
condition
|
||||
);
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.hibernate.loader.plan.spi.LoadPlan;
|
|||
import org.hibernate.loader.plan.spi.visit.LoadPlanVisitationStrategyAdapter;
|
||||
import org.hibernate.loader.plan.spi.visit.LoadPlanVisitor;
|
||||
import org.hibernate.loader.plan.spi.Return;
|
||||
import org.hibernate.loader.spi.JoinableAssociation;
|
||||
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
|
||||
import org.hibernate.loader.spi.LoadQueryBuilder;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
|
@ -49,40 +50,52 @@ import org.hibernate.persister.walking.spi.WalkingException;
|
|||
* @author Gail Badner
|
||||
*/
|
||||
public class EntityLoadQueryBuilderImpl implements LoadQueryBuilder {
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final LoadQueryInfluencers loadQueryInfluencers;
|
||||
private final LoadPlan loadPlan;
|
||||
private final LoadQueryAliasResolutionContext aliasResolutionContext;
|
||||
private final List<JoinableAssociationImpl> associations;
|
||||
private final List<JoinableAssociation> associations;
|
||||
|
||||
public EntityLoadQueryBuilderImpl(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
LoadQueryInfluencers loadQueryInfluencers,
|
||||
LoadPlan loadPlan,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
LoadPlan loadPlan) {
|
||||
this.loadQueryInfluencers = loadQueryInfluencers;
|
||||
this.loadPlan = loadPlan;
|
||||
|
||||
// TODO: remove reliance on aliasResolutionContext; it should only be needed when generating the SQL.
|
||||
this.aliasResolutionContext = aliasResolutionContext;
|
||||
// TODO: the whole point of the following is to build associations.
|
||||
// this could be done while building loadPlan (and be a part of the LoadPlan).
|
||||
// Should it be?
|
||||
LocalVisitationStrategy strategy = new LocalVisitationStrategy();
|
||||
LoadPlanVisitor.visit( loadPlan, strategy );
|
||||
this.associations = strategy.associations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSql(int batchSize) {
|
||||
return generateSql( batchSize, getOuterJoinLoadable().getKeyColumnNames() );
|
||||
public String generateSql(
|
||||
int batchSize,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
return generateSql(
|
||||
batchSize,
|
||||
getOuterJoinLoadable().getKeyColumnNames(),
|
||||
sessionFactory,
|
||||
aliasResolutionContext
|
||||
);
|
||||
}
|
||||
|
||||
public String generateSql(int batchSize, String[] uniqueKey) {
|
||||
public String generateSql(
|
||||
int batchSize,
|
||||
String[] uniqueKey,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
final EntityLoadQueryImpl loadQuery = new EntityLoadQueryImpl(
|
||||
sessionFactory,
|
||||
getRootEntityReturn(),
|
||||
associations
|
||||
);
|
||||
return loadQuery.generateSql( uniqueKey, batchSize, getRootEntityReturn().getLockMode(), aliasResolutionContext );
|
||||
return loadQuery.generateSql(
|
||||
uniqueKey,
|
||||
batchSize,
|
||||
getRootEntityReturn().getLockMode(),
|
||||
sessionFactory,
|
||||
aliasResolutionContext );
|
||||
}
|
||||
|
||||
private EntityReturn getRootEntityReturn() {
|
||||
|
@ -92,8 +105,9 @@ public class EntityLoadQueryBuilderImpl implements LoadQueryBuilder {
|
|||
private OuterJoinLoadable getOuterJoinLoadable() {
|
||||
return (OuterJoinLoadable) getRootEntityReturn().getEntityPersister();
|
||||
}
|
||||
|
||||
private class LocalVisitationStrategy extends LoadPlanVisitationStrategyAdapter {
|
||||
private final List<JoinableAssociationImpl> associations = new ArrayList<JoinableAssociationImpl>();
|
||||
private final List<JoinableAssociation> associations = new ArrayList<JoinableAssociation>();
|
||||
private Deque<EntityReference> entityReferenceStack = new ArrayDeque<EntityReference>();
|
||||
private Deque<CollectionReference> collectionReferenceStack = new ArrayDeque<CollectionReference>();
|
||||
|
||||
|
@ -135,12 +149,11 @@ public class EntityLoadQueryBuilderImpl implements LoadQueryBuilder {
|
|||
|
||||
@Override
|
||||
public void startingEntityFetch(EntityFetch entityFetch) {
|
||||
JoinableAssociationImpl assoc = new JoinableAssociationImpl(
|
||||
EntityJoinableAssociationImpl assoc = new EntityJoinableAssociationImpl(
|
||||
entityFetch,
|
||||
getCurrentCollectionReference(),
|
||||
"", // getWithClause( entityFetch.getPropertyPath() )
|
||||
false, // hasRestriction( entityFetch.getPropertyPath() )
|
||||
sessionFactory,
|
||||
loadQueryInfluencers.getEnabledFilters()
|
||||
);
|
||||
associations.add( assoc );
|
||||
|
@ -154,12 +167,11 @@ public class EntityLoadQueryBuilderImpl implements LoadQueryBuilder {
|
|||
|
||||
@Override
|
||||
public void startingCollectionFetch(CollectionFetch collectionFetch) {
|
||||
JoinableAssociationImpl assoc = new JoinableAssociationImpl(
|
||||
CollectionJoinableAssociationImpl assoc = new CollectionJoinableAssociationImpl(
|
||||
collectionFetch,
|
||||
getCurrentEntityReference(),
|
||||
"", // getWithClause( entityFetch.getPropertyPath() )
|
||||
false, // hasRestriction( entityFetch.getPropertyPath() )
|
||||
sessionFactory,
|
||||
loadQueryInfluencers.getEnabledFilters()
|
||||
);
|
||||
associations.add( assoc );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* 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.
|
||||
|
@ -30,36 +30,39 @@ import org.hibernate.LockOptions;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||
import org.hibernate.loader.spi.JoinableAssociation;
|
||||
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
|
||||
|
||||
/**
|
||||
* A walker for loaders that fetch entities
|
||||
* Represents an load query for fetching an entity, used for generating SQL.
|
||||
*
|
||||
* This code is based on the SQL generation code originally in
|
||||
* org.hibernate.loader.EntityJoinWalker.
|
||||
*
|
||||
* @see org.hibernate.loader.entity.EntityLoader
|
||||
* @author Gavin King
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class EntityLoadQueryImpl extends AbstractEntityLoadQueryImpl {
|
||||
|
||||
public EntityLoadQueryImpl(
|
||||
final SessionFactoryImplementor factory,
|
||||
EntityReturn entityReturn,
|
||||
List<JoinableAssociationImpl> associations) throws MappingException {
|
||||
super( factory, entityReturn, associations );
|
||||
List<JoinableAssociation> associations) throws MappingException {
|
||||
super( entityReturn, associations );
|
||||
}
|
||||
|
||||
public String generateSql(
|
||||
String[] uniqueKey,
|
||||
int batchSize,
|
||||
LockMode lockMode,
|
||||
SessionFactoryImplementor factory,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) {
|
||||
StringBuilder whereCondition = whereString( getAlias( aliasResolutionContext ), uniqueKey, batchSize )
|
||||
StringBuilder whereCondition = whereString( resolveEntityReturnAlias( aliasResolutionContext ), uniqueKey, batchSize )
|
||||
//include the discriminator and class-level where, but not filters
|
||||
.append( getPersister().filterFragment( getAlias( aliasResolutionContext ), Collections.EMPTY_MAP ) );
|
||||
return generateSql( whereCondition.toString(), "", new LockOptions().setLockMode( lockMode ), aliasResolutionContext );
|
||||
.append( getPersister().filterFragment( resolveEntityReturnAlias( aliasResolutionContext ), Collections.EMPTY_MAP ) );
|
||||
return generateSql( whereCondition.toString(), "", new LockOptions().setLockMode( lockMode ), factory, aliasResolutionContext );
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
protected String getComment() {
|
||||
return "load " + getPersister().getEntityName();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,303 +0,0 @@
|
|||
/*
|
||||
* 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.util.Map;
|
||||
|
||||
import org.hibernate.Filter;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.internal.JoinHelper;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan.spi.CollectionReference;
|
||||
import org.hibernate.loader.plan.spi.EntityFetch;
|
||||
import org.hibernate.loader.plan.spi.EntityReference;
|
||||
import org.hibernate.loader.plan.spi.Fetch;
|
||||
import org.hibernate.loader.spi.JoinableAssociation;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.sql.JoinType;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
||||
/**
|
||||
* Part of the Hibernate SQL rendering internals. This class represents
|
||||
* a joinable association.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class JoinableAssociationImpl implements JoinableAssociation {
|
||||
private final PropertyPath propertyPath;
|
||||
private final Joinable joinable;
|
||||
private final AssociationType joinableType;
|
||||
private final String[] rhsColumns;
|
||||
private final Fetch currentFetch;
|
||||
private final EntityReference currentEntityReference;
|
||||
private final CollectionReference currentCollectionReference;
|
||||
private final JoinType joinType;
|
||||
private final String withClause;
|
||||
private final Map<String, Filter> enabledFilters;
|
||||
private final boolean hasRestriction;
|
||||
|
||||
public JoinableAssociationImpl(
|
||||
EntityFetch entityFetch,
|
||||
CollectionReference currentCollectionReference,
|
||||
String withClause,
|
||||
boolean hasRestriction,
|
||||
SessionFactoryImplementor factory,
|
||||
Map<String, Filter> enabledFilters) throws MappingException {
|
||||
this(
|
||||
entityFetch,
|
||||
entityFetch.getAssociationType(),
|
||||
entityFetch,
|
||||
currentCollectionReference,
|
||||
withClause,
|
||||
hasRestriction,
|
||||
factory,
|
||||
enabledFilters
|
||||
);
|
||||
}
|
||||
|
||||
public JoinableAssociationImpl(
|
||||
CollectionFetch collectionFetch,
|
||||
EntityReference currentEntityReference,
|
||||
String withClause,
|
||||
boolean hasRestriction,
|
||||
SessionFactoryImplementor factory,
|
||||
Map<String, Filter> enabledFilters) throws MappingException {
|
||||
this(
|
||||
collectionFetch,
|
||||
collectionFetch.getCollectionPersister().getCollectionType(),
|
||||
currentEntityReference,
|
||||
collectionFetch,
|
||||
withClause,
|
||||
hasRestriction,
|
||||
factory,
|
||||
enabledFilters
|
||||
);
|
||||
}
|
||||
|
||||
private JoinableAssociationImpl(
|
||||
Fetch currentFetch,
|
||||
AssociationType associationType,
|
||||
EntityReference currentEntityReference,
|
||||
CollectionReference currentCollectionReference,
|
||||
String withClause,
|
||||
boolean hasRestriction,
|
||||
SessionFactoryImplementor factory,
|
||||
Map<String, Filter> enabledFilters) throws MappingException {
|
||||
this.propertyPath = currentFetch.getPropertyPath();
|
||||
this.joinableType = associationType;
|
||||
final OuterJoinLoadable ownerPersister = (OuterJoinLoadable) currentFetch.getOwner().retrieveFetchSourcePersister();
|
||||
final int propertyNumber = ownerPersister.getEntityMetamodel().getPropertyIndex( currentFetch.getOwnerPropertyName() );
|
||||
final boolean isNullable = ownerPersister.isSubclassPropertyNullable( propertyNumber );
|
||||
if ( currentFetch.getFetchStrategy().getStyle() == FetchStyle.JOIN ) {
|
||||
joinType = isNullable ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
|
||||
}
|
||||
else {
|
||||
joinType = JoinType.NONE;
|
||||
}
|
||||
this.joinable = joinableType.getAssociatedJoinable(factory);
|
||||
this.rhsColumns = JoinHelper.getRHSColumnNames( joinableType, factory );
|
||||
this.currentFetch = currentFetch;
|
||||
this.currentEntityReference = currentEntityReference;
|
||||
this.currentCollectionReference = currentCollectionReference;
|
||||
this.withClause = withClause;
|
||||
this.hasRestriction = hasRestriction;
|
||||
this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public JoinableAssociationImpl(
|
||||
EntityFetch entityFetch,
|
||||
String currentCollectionSuffix,
|
||||
String withClause,
|
||||
boolean hasRestriction,
|
||||
SessionFactoryImplementor factory,
|
||||
Map enabledFilters,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
this.propertyPath = entityFetch.getPropertyPath();
|
||||
this.joinableType = entityFetch.getAssociationType();
|
||||
// TODO: this is not correct
|
||||
final EntityPersister fetchSourcePersister = entityFetch.getOwner().retrieveFetchSourcePersister();
|
||||
final int propertyNumber = fetchSourcePersister.getEntityMetamodel().getPropertyIndex( entityFetch.getOwnerPropertyName() );
|
||||
|
||||
if ( EntityReference.class.isInstance( entityFetch.getOwner() ) ) {
|
||||
this.lhsAlias = aliasResolutionContext.resolveEntitySqlTableAlias( (EntityReference) entityFetch.getOwner() );
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedException( "Cannot determine LHS alias for a FetchOwner that is not an EntityReference." );
|
||||
}
|
||||
final OuterJoinLoadable ownerPersister = (OuterJoinLoadable) entityFetch.getOwner().retrieveFetchSourcePersister();
|
||||
this.lhsColumns = JoinHelper.getAliasedLHSColumnNames(
|
||||
entityFetch.getAssociationType(), lhsAlias, propertyNumber, ownerPersister, factory
|
||||
);
|
||||
this.rhsAlias = aliasResolutionContext.resolveEntitySqlTableAlias( entityFetch );
|
||||
|
||||
final boolean isNullable = ownerPersister.isSubclassPropertyNullable( propertyNumber );
|
||||
if ( entityFetch.getFetchStrategy().getStyle() == FetchStyle.JOIN ) {
|
||||
joinType = isNullable ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
|
||||
}
|
||||
else {
|
||||
joinType = JoinType.NONE;
|
||||
}
|
||||
this.joinable = joinableType.getAssociatedJoinable(factory);
|
||||
this.rhsColumns = JoinHelper.getRHSColumnNames( joinableType, factory );
|
||||
this.currentEntitySuffix = aliasResolutionContext.resolveEntityColumnAliases( entityFetch ).getSuffix();
|
||||
this.currentCollectionSuffix = currentCollectionSuffix;
|
||||
this.on = joinableType.getOnCondition( rhsAlias, factory, enabledFilters )
|
||||
+ ( withClause == null || withClause.trim().length() == 0 ? "" : " and ( " + withClause + " )" );
|
||||
this.hasRestriction = hasRestriction;
|
||||
this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
|
||||
}
|
||||
|
||||
public JoinableAssociationImpl(
|
||||
CollectionFetch collectionFetch,
|
||||
String currentEntitySuffix,
|
||||
String withClause,
|
||||
boolean hasRestriction,
|
||||
SessionFactoryImplementor factory,
|
||||
Map enabledFilters,
|
||||
LoadQueryAliasResolutionContext aliasResolutionContext) throws MappingException {
|
||||
this.propertyPath = collectionFetch.getPropertyPath();
|
||||
final CollectionType collectionType = collectionFetch.getCollectionPersister().getCollectionType();
|
||||
this.joinableType = collectionType;
|
||||
// TODO: this is not correct
|
||||
final EntityPersister fetchSourcePersister = collectionFetch.getOwner().retrieveFetchSourcePersister();
|
||||
final int propertyNumber = fetchSourcePersister.getEntityMetamodel().getPropertyIndex( collectionFetch.getOwnerPropertyName() );
|
||||
|
||||
if ( EntityReference.class.isInstance( collectionFetch.getOwner() ) ) {
|
||||
this.lhsAlias = aliasResolutionContext.resolveEntitySqlTableAlias( (EntityReference) collectionFetch.getOwner() );
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedException( "Cannot determine LHS alias for a FetchOwner that is not an EntityReference." );
|
||||
}
|
||||
final OuterJoinLoadable ownerPersister = (OuterJoinLoadable) collectionFetch.getOwner().retrieveFetchSourcePersister();
|
||||
this.lhsColumns = JoinHelper.getAliasedLHSColumnNames(
|
||||
collectionType, lhsAlias, propertyNumber, ownerPersister, factory
|
||||
);
|
||||
this.rhsAlias = aliasResolutionContext.resolveCollectionSqlTableAlias( collectionFetch );
|
||||
|
||||
final boolean isNullable = ownerPersister.isSubclassPropertyNullable( propertyNumber );
|
||||
if ( collectionFetch.getFetchStrategy().getStyle() == FetchStyle.JOIN ) {
|
||||
joinType = isNullable ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
|
||||
}
|
||||
else {
|
||||
joinType = JoinType.NONE;
|
||||
}
|
||||
this.joinable = joinableType.getAssociatedJoinable(factory);
|
||||
this.rhsColumns = JoinHelper.getRHSColumnNames( joinableType, factory );
|
||||
this.currentEntitySuffix = currentEntitySuffix;
|
||||
this.currentCollectionSuffix = aliasResolutionContext.resolveCollectionColumnAliases( collectionFetch ).getSuffix();
|
||||
this.on = joinableType.getOnCondition( rhsAlias, factory, enabledFilters )
|
||||
+ ( withClause == null || withClause.trim().length() == 0 ? "" : " and ( " + withClause + " )" );
|
||||
this.hasRestriction = hasRestriction;
|
||||
this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public PropertyPath getPropertyPath() {
|
||||
return propertyPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JoinType getJoinType() {
|
||||
return joinType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch getCurrentFetch() {
|
||||
return currentFetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityReference getCurrentEntityReference() {
|
||||
return currentEntityReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionReference getCurrentCollectionReference() {
|
||||
return currentCollectionReference;
|
||||
}
|
||||
|
||||
private boolean isOneToOne() {
|
||||
if ( joinableType.isEntityType() ) {
|
||||
EntityType etype = (EntityType) joinableType;
|
||||
return etype.isOneToOne() /*&& etype.isReferenceToPrimaryKey()*/;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssociationType getJoinableType() {
|
||||
return joinableType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollection() {
|
||||
return getJoinableType().isCollectionType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Joinable getJoinable() {
|
||||
return joinable;
|
||||
}
|
||||
|
||||
public boolean hasRestriction() {
|
||||
return hasRestriction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isManyToManyWith(JoinableAssociation other) {
|
||||
if ( joinable.isCollection() ) {
|
||||
QueryableCollection persister = ( QueryableCollection ) joinable;
|
||||
if ( persister.isManyToMany() ) {
|
||||
return persister.getElementType() == other.getJoinableType();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getRhsColumns() {
|
||||
return rhsColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWithClause() {
|
||||
return withClause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Filter> getEnabledFilters() {
|
||||
return enabledFilters;
|
||||
}
|
||||
}
|
|
@ -50,6 +50,8 @@ import org.hibernate.persister.entity.OuterJoinLoadable;
|
|||
import org.hibernate.type.EntityType;
|
||||
|
||||
/**
|
||||
* Provides aliases that are used by load queries and ResultSet processors.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolutionContext {
|
||||
|
@ -130,7 +132,7 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
|
|||
}
|
||||
|
||||
@Override
|
||||
public String resolveEntitySqlTableAlias(EntityReference entityReference) {
|
||||
public String resolveEntityTableAlias(EntityReference entityReference) {
|
||||
return getOrGenerateLoadQueryEntityAliases( entityReference ).tableAlias;
|
||||
}
|
||||
|
||||
|
@ -140,7 +142,7 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
|
|||
}
|
||||
|
||||
@Override
|
||||
public String resolveCollectionSqlTableAlias(CollectionReference collectionReference) {
|
||||
public String resolveCollectionTableAlias(CollectionReference collectionReference) {
|
||||
return getOrGenerateLoadQueryCollectionAliases( collectionReference ).tableAlias;
|
||||
}
|
||||
|
||||
|
@ -155,34 +157,20 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
|
|||
}
|
||||
|
||||
@Override
|
||||
public String resolveRhsAlias(JoinableAssociation joinableAssociation) {
|
||||
public String resolveAssociationRhsTableAlias(JoinableAssociation joinableAssociation) {
|
||||
return getOrGenerateJoinAssocationAliases( joinableAssociation ).rhsAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveLhsAlias(JoinableAssociation joinableAssociation) {
|
||||
public String resolveAssociationLhsTableAlias(JoinableAssociation joinableAssociation) {
|
||||
return getOrGenerateJoinAssocationAliases( joinableAssociation ).lhsAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] resolveAliasedLhsColumnNames(JoinableAssociation joinableAssociation) {
|
||||
public String[] resolveAssociationAliasedLhsColumnNames(JoinableAssociation joinableAssociation) {
|
||||
return getOrGenerateJoinAssocationAliases( joinableAssociation ).aliasedLhsColumnNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityAliases resolveCurrentEntityAliases(JoinableAssociation joinableAssociation) {
|
||||
return joinableAssociation.getCurrentEntityReference() == null ?
|
||||
null:
|
||||
resolveEntityColumnAliases( joinableAssociation.getCurrentEntityReference() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionAliases resolveCurrentCollectionAliases(JoinableAssociation joinableAssociation) {
|
||||
return joinableAssociation.getCurrentCollectionReference() == null ?
|
||||
null:
|
||||
resolveCollectionColumnAliases( joinableAssociation.getCurrentCollectionReference() );
|
||||
}
|
||||
|
||||
protected SessionFactoryImplementor sessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
@ -224,17 +212,17 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
|
|||
final Fetch currentFetch = joinableAssociation.getCurrentFetch();
|
||||
final String lhsAlias;
|
||||
if ( EntityReference.class.isInstance( currentFetch.getOwner() ) ) {
|
||||
lhsAlias = resolveEntitySqlTableAlias( (EntityReference) currentFetch.getOwner() );
|
||||
lhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch.getOwner() );
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedException( "Cannot determine LHS alias for a FetchOwner that is not an EntityReference yet." );
|
||||
}
|
||||
final String rhsAlias;
|
||||
if ( EntityReference.class.isInstance( currentFetch ) ) {
|
||||
rhsAlias = resolveEntitySqlTableAlias( (EntityReference) currentFetch );
|
||||
rhsAlias = resolveEntityTableAlias( (EntityReference) currentFetch );
|
||||
}
|
||||
else if ( CollectionReference.class.isInstance( joinableAssociation.getCurrentFetch() ) ) {
|
||||
rhsAlias = resolveCollectionSqlTableAlias( (CollectionReference) currentFetch );
|
||||
rhsAlias = resolveCollectionTableAlias( (CollectionReference) currentFetch );
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedException( "Cannot determine RHS alis for a fetch that is not an EntityReference or CollectionReference." );
|
||||
|
@ -244,7 +232,7 @@ public class LoadQueryAliasResolutionContextImpl implements LoadQueryAliasResolu
|
|||
final OuterJoinLoadable fetchSourcePersister = (OuterJoinLoadable) currentFetch.getOwner().retrieveFetchSourcePersister();
|
||||
final int propertyNumber = fetchSourcePersister.getEntityMetamodel().getPropertyIndex( currentFetch.getOwnerPropertyName() );
|
||||
final String[] aliasedLhsColumnNames = JoinHelper.getAliasedLHSColumnNames(
|
||||
joinableAssociation.getJoinableType(),
|
||||
joinableAssociation.getAssociationType(),
|
||||
lhsAlias,
|
||||
propertyNumber,
|
||||
fetchSourcePersister,
|
||||
|
|
|
@ -35,32 +35,138 @@ import org.hibernate.sql.JoinType;
|
|||
import org.hibernate.type.AssociationType;
|
||||
|
||||
/**
|
||||
* Represents a joinable (entity or collection) association.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public interface JoinableAssociation {
|
||||
|
||||
/**
|
||||
* Returns the property path of the association.
|
||||
*
|
||||
* @return the property path of the association.
|
||||
*/
|
||||
PropertyPath getPropertyPath();
|
||||
|
||||
/**
|
||||
* Returns the type of join used for the association.
|
||||
*
|
||||
* @return the type of join used for the association.
|
||||
*
|
||||
* @see JoinType
|
||||
*/
|
||||
JoinType getJoinType();
|
||||
|
||||
/**
|
||||
* Returns the current association fetch object.
|
||||
*
|
||||
* @return the current association fetch object.
|
||||
*
|
||||
* @see Fetch
|
||||
*/
|
||||
Fetch getCurrentFetch();
|
||||
|
||||
/**
|
||||
* Return the current {@link EntityReference}, or null if none.
|
||||
* <p/>
|
||||
* If {@link #getCurrentFetch()} returns an
|
||||
* {@link org.hibernate.loader.plan.spi.EntityFetch}, this method will
|
||||
* return the same object as {@link #getCurrentFetch()}.
|
||||
* <p/>
|
||||
* If {@link #getCurrentFetch()} returns a
|
||||
* {@link org.hibernate.loader.plan.spi.CollectionFetch} and
|
||||
* the collection's owner is returned or fetched, this
|
||||
* method will return the {@link EntityReference} that owns the
|
||||
* {@link Fetch} returned by {@link #getCurrentFetch()};
|
||||
* otherwise this method returns null.
|
||||
*
|
||||
* @return the current {@link EntityReference}, or null if none.
|
||||
*
|
||||
* @see #getCurrentFetch()
|
||||
* @see Fetch
|
||||
* @see org.hibernate.loader.plan.spi.CollectionFetch
|
||||
* @see org.hibernate.loader.plan.spi.EntityFetch
|
||||
* @see EntityReference
|
||||
*/
|
||||
EntityReference getCurrentEntityReference();
|
||||
|
||||
/**
|
||||
* Return the current {@link CollectionReference}, or null if none.
|
||||
* <p/>
|
||||
* If {@link #getCurrentFetch()} returns a
|
||||
* {@link org.hibernate.loader.plan.spi.CollectionFetch}, this method
|
||||
* will return the same object as {@link #getCurrentFetch()}.
|
||||
* <p/>
|
||||
* If {@link #getCurrentFetch()} returns an
|
||||
* {@link org.hibernate.loader.plan.spi.EntityFetch} that is
|
||||
* a collection element (or part of a composite collection element),
|
||||
* and that collection is being returned or fetched, this
|
||||
* method will return the {@link CollectionReference};
|
||||
* otherwise this method returns null.
|
||||
*
|
||||
* @return the current {@link CollectionReference}, or null if none.
|
||||
*
|
||||
* @see #getCurrentFetch()
|
||||
* @see Fetch
|
||||
* @see org.hibernate.loader.plan.spi.EntityFetch
|
||||
* @see org.hibernate.loader.plan.spi.CollectionFetch
|
||||
* @see CollectionReference
|
||||
*/
|
||||
CollectionReference getCurrentCollectionReference();
|
||||
|
||||
AssociationType getJoinableType();
|
||||
/**
|
||||
* Returns the association type.
|
||||
*
|
||||
* @return the association type.
|
||||
*
|
||||
* @see AssociationType
|
||||
*/
|
||||
AssociationType getAssociationType();
|
||||
|
||||
/**
|
||||
* Return the persister for creating the join for the association.
|
||||
*
|
||||
* @return the persister for creating the join for the association.
|
||||
*/
|
||||
Joinable getJoinable();
|
||||
|
||||
/**
|
||||
* Is this a collection association?
|
||||
*
|
||||
* @return true, if this is a collection association; false otherwise.
|
||||
*/
|
||||
boolean isCollection();
|
||||
|
||||
public String[] getRhsColumns();
|
||||
|
||||
/**
|
||||
* Does this association have a restriction?
|
||||
*
|
||||
* @return true if this association has a restriction; false, otherwise.
|
||||
*/
|
||||
boolean hasRestriction();
|
||||
|
||||
/**
|
||||
* Does this association have a many-to-many association
|
||||
* with the specified association?
|
||||
*
|
||||
* @param other - the other association.
|
||||
* @return true, if this association has a many-to-many association
|
||||
* with the other association; false otherwise.
|
||||
*/
|
||||
boolean isManyToManyWith(JoinableAssociation other);
|
||||
|
||||
/**
|
||||
* Returns the with clause for this association.
|
||||
*
|
||||
* @return the with clause for this association.
|
||||
*/
|
||||
String getWithClause();
|
||||
|
||||
/**
|
||||
* Returns the filters that are enabled for this association.
|
||||
*
|
||||
* @return the filters that are enabled for this association.
|
||||
*
|
||||
* @see Filter
|
||||
*/
|
||||
Map<String,Filter> getEnabledFilters();
|
||||
}
|
||||
|
|
|
@ -32,32 +32,70 @@ import org.hibernate.loader.plan.spi.EntityReturn;
|
|||
import org.hibernate.loader.plan.spi.ScalarReturn;
|
||||
|
||||
/**
|
||||
* Provides aliases that are used by load queries and ResultSet processors.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public interface LoadQueryAliasResolutionContext {
|
||||
|
||||
/**
|
||||
* Resolve the alias associated with the specified {@link EntityReturn}.
|
||||
*
|
||||
* @param entityReturn - the {@link EntityReturn}.
|
||||
*
|
||||
* @return the alias associated with the specified {@link EntityReturn}.
|
||||
*/
|
||||
public String resolveEntityReturnAlias(EntityReturn entityReturn);
|
||||
|
||||
/**
|
||||
* Resolve the alias associated with the specified {@link CollectionReturn}.
|
||||
*
|
||||
* @param collectionReturn - the {@link CollectionReturn}.
|
||||
*
|
||||
* @return the alias associated with {@link CollectionReturn}.
|
||||
*/
|
||||
public String resolveCollectionReturnAlias(CollectionReturn collectionReturn);
|
||||
|
||||
/**
|
||||
* Resolve the aliases associated with the specified {@link ScalarReturn}.
|
||||
*
|
||||
* @param scalarReturn - the {@link ScalarReturn}.
|
||||
*
|
||||
* @return the alias associated with {@link ScalarReturn}.
|
||||
*/
|
||||
String[] resolveScalarReturnAliases(ScalarReturn scalarReturn);
|
||||
|
||||
/**
|
||||
* Retrieve the SQL table alias.
|
||||
* Resolve the SQL table alias for the specified {@link EntityReference}.
|
||||
*
|
||||
* @return The SQL table alias
|
||||
* @param entityReference - the {@link EntityReference}.
|
||||
* @return The SQL table alias for the specified {@link EntityReference}.
|
||||
*/
|
||||
String resolveEntitySqlTableAlias(EntityReference entityReference);
|
||||
|
||||
EntityAliases resolveEntityColumnAliases(EntityReference entityReference);
|
||||
|
||||
String resolveCollectionSqlTableAlias(CollectionReference collectionReference);
|
||||
String resolveEntityTableAlias(EntityReference entityReference);
|
||||
|
||||
/**
|
||||
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to the
|
||||
* this collection.
|
||||
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to
|
||||
* an entity.
|
||||
*
|
||||
* @return The ResultSet alias descriptor for the collection
|
||||
* @param entityReference - the {@link EntityReference} for the entity.
|
||||
*
|
||||
* @return The ResultSet alias descriptor for the {@link EntityReference}
|
||||
*/
|
||||
EntityAliases resolveEntityColumnAliases(EntityReference entityReference);
|
||||
|
||||
/**
|
||||
* Resolve the SQL table alias for the specified {@link CollectionReference}.
|
||||
*
|
||||
* @param collectionReference - the {@link CollectionReference}.
|
||||
* @return The SQL table alias for the specified {@link CollectionReference}.
|
||||
*/
|
||||
String resolveCollectionTableAlias(CollectionReference collectionReference);
|
||||
|
||||
/**
|
||||
* Returns the description of the aliases in the JDBC ResultSet that identify values "belonging" to
|
||||
* the specified {@link CollectionReference}.
|
||||
*
|
||||
* @return The ResultSet alias descriptor for the {@link CollectionReference}
|
||||
*/
|
||||
CollectionAliases resolveCollectionColumnAliases(CollectionReference collectionReference);
|
||||
|
||||
|
@ -69,13 +107,28 @@ public interface LoadQueryAliasResolutionContext {
|
|||
*/
|
||||
EntityAliases resolveCollectionElementColumnAliases(CollectionReference collectionReference);
|
||||
|
||||
String resolveRhsAlias(JoinableAssociation joinableAssociation);
|
||||
/**
|
||||
* Resolve the table alias on the right-hand-side of the specified association.
|
||||
*
|
||||
* @param association - the joinable association.
|
||||
*
|
||||
* @return the table alias on the right-hand-side of the specified association.
|
||||
*/
|
||||
String resolveAssociationRhsTableAlias(JoinableAssociation association);
|
||||
|
||||
String resolveLhsAlias(JoinableAssociation joinableAssociation);
|
||||
/**
|
||||
* Resolve the table alias on the left-hand-side of the specified association.
|
||||
*
|
||||
* @param association - the joinable association.
|
||||
*
|
||||
* @return the table alias on the left-hand-side of the specified association.
|
||||
*/
|
||||
String resolveAssociationLhsTableAlias(JoinableAssociation association);
|
||||
|
||||
String[] resolveAliasedLhsColumnNames(JoinableAssociation joinableAssociation);
|
||||
|
||||
EntityAliases resolveCurrentEntityAliases(JoinableAssociation joinableAssociation);
|
||||
|
||||
CollectionAliases resolveCurrentCollectionAliases(JoinableAssociation joinableAssociation);
|
||||
/**
|
||||
* Resolve the column aliases on the left-hand-side of the specified association.
|
||||
* @param association - the joinable association
|
||||
* @return the column aliases on the left-hand-side of the specified association.
|
||||
*/
|
||||
String[] resolveAssociationAliasedLhsColumnNames(JoinableAssociation association);
|
||||
}
|
||||
|
|
|
@ -23,10 +23,22 @@
|
|||
*/
|
||||
package org.hibernate.loader.spi;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
/**
|
||||
* Builds a load query for generating SQL.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public interface LoadQueryBuilder {
|
||||
|
||||
String generateSql(int batchSize);
|
||||
/**
|
||||
* Generates SQL for the performing the load.
|
||||
* @param batchSize - the batch size.
|
||||
* @param factory - the session factory.
|
||||
* @param aliasResolutionContext - the alias resolution context.
|
||||
*
|
||||
* @return the SQL string for performing the load
|
||||
*/
|
||||
String generateSql(int batchSize, SessionFactoryImplementor factory, LoadQueryAliasResolutionContext aliasResolutionContext);
|
||||
}
|
||||
|
|
|
@ -102,12 +102,10 @@ public class EntityAssociationResultSetProcessorTest extends BaseCoreFunctionalT
|
|||
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
|
||||
);
|
||||
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
|
||||
sessionFactory(),
|
||||
LoadQueryInfluencers.NONE,
|
||||
plan,
|
||||
aliasResolutionContext
|
||||
plan
|
||||
);
|
||||
final String sql = queryBuilder.generateSql( 1 );
|
||||
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
|
||||
|
||||
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
|
||||
final List results = new ArrayList();
|
||||
|
@ -202,12 +200,10 @@ public class EntityAssociationResultSetProcessorTest extends BaseCoreFunctionalT
|
|||
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
|
||||
);
|
||||
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
|
||||
sessionFactory(),
|
||||
LoadQueryInfluencers.NONE,
|
||||
plan,
|
||||
aliasResolutionContext
|
||||
plan
|
||||
);
|
||||
final String sql = queryBuilder.generateSql( 1 );
|
||||
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
|
||||
|
||||
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
|
||||
final List results = new ArrayList();
|
||||
|
|
|
@ -90,12 +90,6 @@ public class EntityWithCollectionResultSetProcessorTest extends BaseCoreFunction
|
|||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.get( Person.class, person.id );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
{
|
||||
final SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
|
||||
sessionFactory(),
|
||||
|
@ -109,12 +103,10 @@ public class EntityWithCollectionResultSetProcessorTest extends BaseCoreFunction
|
|||
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
|
||||
);
|
||||
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
|
||||
sessionFactory(),
|
||||
LoadQueryInfluencers.NONE,
|
||||
plan,
|
||||
aliasResolutionContext
|
||||
plan
|
||||
);
|
||||
final String sql = queryBuilder.generateSql( 1 );
|
||||
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
|
||||
|
||||
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
|
||||
final List results = new ArrayList();
|
||||
|
|
|
@ -92,12 +92,10 @@ public class SimpleResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
|||
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
|
||||
);
|
||||
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
|
||||
sessionFactory(),
|
||||
LoadQueryInfluencers.NONE,
|
||||
plan,
|
||||
aliasResolutionContext
|
||||
plan
|
||||
);
|
||||
final String sql = queryBuilder.generateSql( 1 );
|
||||
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
|
||||
|
||||
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
|
||||
final List results = new ArrayList();
|
||||
|
|
Loading…
Reference in New Issue