📄 outerjoinloader.java
字号:
//$Id: OuterJoinLoader.java,v 1.25.2.27 2003/11/15 09:49:06 oneovthafew Exp $package net.sf.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 net.sf.hibernate.LockMode;import net.sf.hibernate.MappingException;import net.sf.hibernate.collection.CollectionPersister;import net.sf.hibernate.collection.QueryableCollection;import net.sf.hibernate.dialect.Dialect;import net.sf.hibernate.engine.SessionFactoryImplementor;import net.sf.hibernate.persister.ClassPersister;import net.sf.hibernate.persister.Joinable;import net.sf.hibernate.persister.Loadable;import net.sf.hibernate.sql.Alias;import net.sf.hibernate.sql.ConditionFragment;import net.sf.hibernate.sql.DisjunctionFragment;import net.sf.hibernate.sql.JoinFragment;import net.sf.hibernate.type.AbstractComponentType;import net.sf.hibernate.type.AssociationType;import net.sf.hibernate.type.EntityType;import net.sf.hibernate.type.OneToOneType;import net.sf.hibernate.type.Type;import net.sf.hibernate.util.ArrayHelper;import net.sf.hibernate.util.StringHelper;/** * Implements logic for walking a tree of associated classes and generating an SQL select string * containing all properties of those classes. Tables are joined using an ANSI-style left outer * join. * @author Gavin King, Jon Lipsky */public abstract class OuterJoinLoader extends Loader { public static final int EAGER = 1; public static final int AUTO = 0; public static final int LAZY = -1; protected Loadable[] classPersisters; protected LockMode[] lockModeArray; protected int[] owners; protected String sql; protected String[] suffixes; private Dialect dialect; public OuterJoinLoader(Dialect dialect) { this.dialect=dialect; } /** * Override on subclasses to enable or suppress joining of some associations, * especially in the case of dynamic fetch settings */ protected boolean isJoinedFetchEnabled(Type type, boolean mappingDefault, String path, String table, String[] foreignKeyColumns) { return type.isEntityType() && mappingDefault; } protected int getJoinType(AssociationType type, int config, String path, String table, String[] foreignKeyColumns, SessionFactoryImplementor factory) throws MappingException { boolean mappingDefault = isJoinedFetchEnabledByDefault(config, type, factory); return isJoinedFetchEnabled(type, mappingDefault, path, table, foreignKeyColumns) ? JoinFragment.LEFT_OUTER_JOIN : -1; } public static final class OuterJoinableAssociation { Joinable joinable; String[] foreignKeyColumns; // belong to other persister String subalias; String[] primaryKeyColumns; String tableName; int owner; // the position of the persister we came from in the list int joinType; //public String foreignKeyalias; boolean isOneToOne; } /** * For an entity class, return a list of associations to be fetched by outerjoin */ protected final List walkTree(Loadable persister, String alias, SessionFactoryImplementor factory) throws MappingException { List associations = new ArrayList(); walkClassTree(persister, alias, associations, new HashSet(), StringHelper.EMPTY_STRING, 0, factory); return associations; } /** * For a collection role, return a list of associations to be fetched by outerjoin */ protected final List walkCollectionTree(QueryableCollection persister, String alias, SessionFactoryImplementor factory) throws MappingException { return walkCollectionTree(persister, alias, new ArrayList(), new HashSet(), StringHelper.EMPTY_STRING, 0, factory); //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 final List walkCollectionTree(QueryableCollection persister, String alias, List associations, Set visitedPersisters, String path, int currentDepth, SessionFactoryImplementor factory) throws MappingException { if ( persister.isOneToMany() ) { walkClassTree( persister.getElementPersister(), alias, associations, visitedPersisters, path, currentDepth, factory ); } else { Type type = persister.getElementType(); if ( type.isAssociationType() ) { // a many-to-many AssociationType etype = (AssociationType) type; int joinType = getJoinType( etype, persister.enableJoinedFetch(), path, persister.getTableName(), persister.getElementColumnNames(), factory ); if (joinType>=0) { String[] columns = StringHelper.qualify( alias, persister.getElementColumnNames() ); walkAssociationTree( etype, columns, persister, alias, associations, visitedPersisters, path, currentDepth, joinType, factory ); } } else if ( type.isComponentType() ) { walkCompositeElementTree( (AbstractComponentType) type, persister.getElementColumnNames(), persister, alias, associations, new HashSet(), path, currentDepth, factory ); } } return associations; } /** * Is this an association that we cannot possibly load by outer * join, no matter what the mapping or subclass specifies? */ private boolean isJoinedFetchAlwaysDisabled(Loadable persister, AssociationType etype, int propertyNumber) { //NOTE: workaround for problem with 1-to-1 defined on a subclass "accidently" picking up an object //TODO: really, this should use the "key" columns of the subclass table, then we don't need this check! // (I *think*) return etype.isEntityType() && ( (EntityType) etype ).isOneToOne() && persister.isDefinedOnSubclass(propertyNumber); } private final void walkAssociationTree( AssociationType etype, Loadable persister, int propertyNumber, String alias, List associations, Set visitedPersisters, String path, int currentDepth, SessionFactoryImplementor factory) throws MappingException { String[] aliasedForeignKeyColumns = getAliasedForeignKeyColumns( persister, alias, etype, persister.toColumns(alias, propertyNumber) ); String[] foreignKeyColumns = getForeignKeyColumns( persister, etype, persister.getSubclassPropertyColumnNames(propertyNumber) ); if ( isJoinedFetchAlwaysDisabled(persister, etype, propertyNumber) ) return; String subpath = subPath( path, persister.getSubclassPropertyName(propertyNumber) ); int joinType = getJoinType( etype, persister.enableJoinedFetch(propertyNumber), subpath, persister.getSubclassPropertyTableName(propertyNumber), foreignKeyColumns, factory ); if (joinType >= 0 ) walkAssociationTree( etype, aliasedForeignKeyColumns, persister, alias, associations, visitedPersisters, subpath, currentDepth, joinType, factory ); } /** * For an entity class, add to a list of associations to be fetched by outerjoin */ private final void walkClassTree( final Loadable persister, String alias, List associations, Set visitedPersisters, String path, int currentDepth, SessionFactoryImplementor factory) throws MappingException { int n = persister.countSubclassProperties(); for ( int i=0; i<n; i++ ) { Type type = persister.getSubclassPropertyType(i); if ( type.isAssociationType() ) { walkAssociationTree( (AssociationType) type, persister, i, alias, associations, visitedPersisters, path, currentDepth, factory ); } else if ( type.isComponentType() ) { walkComponentTree( (AbstractComponentType) type, i, persister.getSubclassPropertyColumnNames(i), persister.toColumns(alias, i), persister, alias, associations, visitedPersisters, subPath( path, persister.getSubclassPropertyName(i) ), currentDepth, factory ); } } } /** * For a component, add to a list of associations to be fetched by outerjoin */ private void walkComponentTree( AbstractComponentType componentType, int propertyNumber, String[] cols, String[] aliasedCols, Loadable persister, String alias, List associations, Set visitedPersisters, String path, int currentDepth, SessionFactoryImplementor factory ) throws MappingException { Type[] types = componentType.getSubtypes(); String[] propertyNames = ( componentType ).getPropertyNames(); int begin = 0; for ( int i=0; i <types.length; i++ ) { int length = types[i].getColumnSpan(factory); String[] range = ArrayHelper.slice(cols, begin, length); String[] aliasedRange = ArrayHelper.slice(aliasedCols, begin, length); if ( types[i].isAssociationType() ) { AssociationType associationType = (AssociationType) types[i]; if ( isJoinedFetchAlwaysDisabled(persister, associationType, propertyNumber) ) return; String[] aliasedFkColumns = getAliasedForeignKeyColumns(persister, alias, associationType, aliasedRange); String[] fkColumns = getForeignKeyColumns(persister, associationType, range); String subpath = subPath( path, propertyNames[i] ); int joinType = getJoinType( associationType, componentType.enableJoinedFetch(i), subpath, persister.getSubclassPropertyTableName(propertyNumber), fkColumns, factory ); if (joinType>=0) walkAssociationTree( associationType, aliasedFkColumns, persister, alias, associations, visitedPersisters, subpath, currentDepth, joinType, factory ); } else if ( types[i].isComponentType() ) { String subpath = subPath( path, propertyNames[i] ); walkComponentTree( (AbstractComponentType) types[i], propertyNumber, range, aliasedRange, persister, alias, associations, visitedPersisters, subpath, currentDepth, factory ); } begin+=length; } } /** * For a composite element, add to a list of associations to be fetched by outerjoin */ private void walkCompositeElementTree( AbstractComponentType compositeType, String[] cols, QueryableCollection persister, String alias, List associations, Set visitedPersisters, String path, int currentDepth, SessionFactoryImplementor factory ) throws MappingException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -