📄 joinwalker.java
字号:
//$Id: JoinWalker.java 9889 2006-05-05 01:24:12Z steve.ebersole@jboss.com $package org.hibernate.loader;import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import org.hibernate.FetchMode;import org.hibernate.LockMode;import org.hibernate.MappingException;import org.hibernate.dialect.Dialect;import org.hibernate.engine.CascadeStyle;import org.hibernate.engine.JoinHelper;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.persister.collection.CollectionPersister;import org.hibernate.persister.collection.QueryableCollection;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.persister.entity.Joinable;import org.hibernate.persister.entity.Loadable;import org.hibernate.persister.entity.OuterJoinLoadable;import org.hibernate.sql.ConditionFragment;import org.hibernate.sql.DisjunctionFragment;import org.hibernate.sql.InFragment;import org.hibernate.sql.JoinFragment;import org.hibernate.type.AbstractComponentType;import org.hibernate.type.AssociationType;import org.hibernate.type.EntityType;import org.hibernate.type.ForeignKeyDirection;import org.hibernate.type.Type;import org.hibernate.util.ArrayHelper;import org.hibernate.util.StringHelper;/** * Walks the metamodel, searching for joins, and collecting * together information needed by <tt>OuterJoinLoader</tt>. * * @see OuterJoinLoader * @author Gavin King, Jon Lipsky */public class JoinWalker { private final SessionFactoryImplementor factory; protected final List associations = new ArrayList(); private final Set visitedAssociationKeys = new HashSet(); private final Map enabledFilters; protected String[] suffixes; protected String[] collectionSuffixes; protected Loadable[] persisters; protected int[] owners; protected EntityType[] ownerAssociationTypes; protected CollectionPersister[] collectionPersisters; protected int[] collectionOwners; protected String[] aliases; protected LockMode[] lockModeArray; protected String sql; public String[] getCollectionSuffixes() { return collectionSuffixes; } public void setCollectionSuffixes(String[] collectionSuffixes) { this.collectionSuffixes = collectionSuffixes; } public LockMode[] getLockModeArray() { return lockModeArray; } public void setLockModeArray(LockMode[] lockModeArray) { this.lockModeArray = lockModeArray; } public String[] getSuffixes() { return suffixes; } public void setSuffixes(String[] suffixes) { this.suffixes = suffixes; } public String[] getAliases() { return aliases; } public void setAliases(String[] aliases) { this.aliases = aliases; } public int[] getCollectionOwners() { return collectionOwners; } public void setCollectionOwners(int[] collectionOwners) { this.collectionOwners = collectionOwners; } public CollectionPersister[] getCollectionPersisters() { return collectionPersisters; } public void setCollectionPersisters(CollectionPersister[] collectionPersisters) { this.collectionPersisters = collectionPersisters; } public EntityType[] getOwnerAssociationTypes() { return ownerAssociationTypes; } public void setOwnerAssociationTypes(EntityType[] ownerAssociationType) { this.ownerAssociationTypes = ownerAssociationType; } public int[] getOwners() { return owners; } public void setOwners(int[] owners) { this.owners = owners; } public Loadable[] getPersisters() { return persisters; } public void setPersisters(Loadable[] persisters) { this.persisters = persisters; } public String getSQLString() { return sql; } public void setSql(String sql) { this.sql = sql; } protected SessionFactoryImplementor getFactory() { return factory; } protected Dialect getDialect() { return factory.getDialect(); } protected Map getEnabledFilters() { return enabledFilters; } protected JoinWalker(SessionFactoryImplementor factory, Map enabledFilters) { this.factory = factory; this.enabledFilters = enabledFilters; } /** * Add on association (one-to-one, many-to-one, or a collection) to a list * of associations to be fetched by outerjoin (if necessary) */ private void addAssociationToJoinTreeIfNecessary( final AssociationType type, final String[] aliasedLhsColumns, final String alias, final String path, int currentDepth, final int joinType) throws MappingException { if (joinType>=0) { addAssociationToJoinTree( type, aliasedLhsColumns, alias, path, currentDepth, joinType ); } } /** * Add on association (one-to-one, many-to-one, or a collection) to a list * of associations to be fetched by outerjoin */ private void addAssociationToJoinTree( final AssociationType type, final String[] aliasedLhsColumns, final String alias, final String path, final int currentDepth, final int joinType) throws MappingException { Joinable joinable = type.getAssociatedJoinable( getFactory() ); String subalias = generateTableAlias( associations.size()+1, //before adding to collection! path, joinable ); OuterJoinableAssociation assoc = new OuterJoinableAssociation( type, alias, aliasedLhsColumns, subalias, joinType, getFactory(), enabledFilters ); assoc.validateJoin(path); associations.add(assoc); int nextDepth = currentDepth+1; if ( !joinable.isCollection() ) { if (joinable instanceof OuterJoinLoadable) { walkEntityTree( (OuterJoinLoadable) joinable, subalias, path, nextDepth ); } } else { if (joinable instanceof QueryableCollection) { walkCollectionTree( (QueryableCollection) joinable, subalias, path, nextDepth ); } } } /** * For an entity class, return a list of associations to be fetched by outerjoin */ protected final void walkEntityTree(OuterJoinLoadable persister, String alias) throws MappingException { walkEntityTree(persister, alias, "", 0); } /** * For a collection role, return a list of associations to be fetched by outerjoin */ protected final void walkCollectionTree(QueryableCollection persister, String alias) throws MappingException { walkCollectionTree(persister, alias, "", 0); //TODO: when this is the entry point, we should use an INNER_JOIN for fetching the many-to-many elements! } /** * For a collection role, return a list of associations to be fetched by outerjoin */ private void walkCollectionTree( final QueryableCollection persister, final String alias, final String path, final int currentDepth) throws MappingException { if ( persister.isOneToMany() ) { walkEntityTree( (OuterJoinLoadable) persister.getElementPersister(), alias, path, currentDepth ); } else { Type type = persister.getElementType(); if ( type.isAssociationType() ) { // a many-to-many; // decrement currentDepth here to allow join across the association table // without exceeding MAX_FETCH_DEPTH (i.e. the "currentDepth - 1" bit) AssociationType associationType = (AssociationType) type; String[] aliasedLhsColumns = persister.getElementColumnNames(alias); String[] lhsColumns = persister.getElementColumnNames(); // if the current depth is 0, the root thing being loaded is the // many-to-many collection itself. Here, it is alright to use // an inner join... boolean useInnerJoin = currentDepth == 0; final int joinType = getJoinType( associationType, persister.getFetchMode(), path, persister.getTableName(), lhsColumns, !useInnerJoin, currentDepth - 1, null //operations which cascade as far as the collection also cascade to collection elements ); addAssociationToJoinTreeIfNecessary( associationType, aliasedLhsColumns, alias, path, currentDepth - 1, joinType ); } else if ( type.isComponentType() ) { walkCompositeElementTree( (AbstractComponentType) type, persister.getElementColumnNames(), persister, alias, path, currentDepth ); } } } /** * Walk the tree for a particular entity association */ private final void walkEntityAssociationTree( final AssociationType associationType, final OuterJoinLoadable persister, final int propertyNumber, final String alias, final String path, final boolean nullable, final int currentDepth) throws MappingException { String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames( associationType, alias, propertyNumber, persister, getFactory() ); String[] lhsColumns = JoinHelper.getLHSColumnNames( associationType, propertyNumber, persister, getFactory() ); String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister); String subpath = subPath( path, persister.getSubclassPropertyName(propertyNumber) ); int joinType = getJoinType( associationType, persister.getFetchMode(propertyNumber), subpath, lhsTable, lhsColumns, nullable, currentDepth, persister.getCascadeStyle(propertyNumber) ); addAssociationToJoinTreeIfNecessary( associationType, aliasedLhsColumns, alias, subpath, currentDepth, joinType ); } /** * For an entity class, add to a list of associations to be fetched * by outerjoin */ private final void walkEntityTree( final OuterJoinLoadable persister, final String alias, final String path, final int currentDepth) throws MappingException { int n = persister.countSubclassProperties(); for ( int i=0; i<n; i++ ) { Type type = persister.getSubclassPropertyType(i); if ( type.isAssociationType() ) { walkEntityAssociationTree( (AssociationType) type, persister, i, alias, path, persister.isSubclassPropertyNullable(i), currentDepth ); } else if ( type.isComponentType() ) { walkComponentTree( (AbstractComponentType) type, i, 0, persister, alias, subPath( path, persister.getSubclassPropertyName(i) ), currentDepth ); } } } /** * For a component, add to a list of associations to be fetched by outerjoin */ private void walkComponentTree( final AbstractComponentType componentType, final int propertyNumber, int begin, final OuterJoinLoadable persister, final String alias, final String path, final int currentDepth ) throws MappingException { Type[] types = componentType.getSubtypes(); String[] propertyNames = componentType.getPropertyNames(); for ( int i=0; i <types.length; i++ ) { if ( types[i].isAssociationType() ) { AssociationType associationType = (AssociationType) types[i]; String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames( associationType, alias, propertyNumber, begin, persister, getFactory() ); String[] lhsColumns = JoinHelper.getLHSColumnNames( associationType, propertyNumber, begin, persister, getFactory() ); String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister); String subpath = subPath( path, propertyNames[i] ); final boolean[] propertyNullability = componentType.getPropertyNullability(); final int joinType = getJoinType( associationType, componentType.getFetchMode(i), subpath, lhsTable, lhsColumns, propertyNullability==null || propertyNullability[i], currentDepth, componentType.getCascadeStyle(i) ); addAssociationToJoinTreeIfNecessary( associationType, aliasedLhsColumns, alias, subpath, currentDepth, joinType ); } else if ( types[i].isComponentType() ) { String subpath = subPath( path, propertyNames[i] ); walkComponentTree( (AbstractComponentType) types[i], propertyNumber, begin, persister, alias, subpath, currentDepth ); } begin+=types[i].getColumnSpan( getFactory() ); } } /** * For a composite element, add to a list of associations to be fetched by outerjoin */ private void walkCompositeElementTree( final AbstractComponentType compositeType, final String[] cols, final QueryableCollection persister, final String alias, final String path, final int currentDepth)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -