⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 joinwalker.java

📁 hibernate-3.1.3-all-src.zip 面向对象的访问数据库工具
💻 JAVA
📖 第 1 页 / 共 2 页
字号:

	/**
	 * 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) 
	throws MappingException {

		Type[] types = compositeType.getSubtypes();
		String[] propertyNames = compositeType.getPropertyNames();
		int begin = 0;
		for ( int i=0; i <types.length; i++ ) {
			int length = types[i].getColumnSpan( getFactory() );
			String[] lhsColumns = ArrayHelper.slice(cols, begin, length);

			if ( types[i].isAssociationType() ) {
				AssociationType associationType = (AssociationType) types[i];

				// simple, because we can't have a one-to-one or a collection 
				// (or even a property-ref) in a composite-element:
				String[] aliasedLhsColumns = StringHelper.qualify(alias, lhsColumns);

				String subpath = subPath( path, propertyNames[i] );
				final boolean[] propertyNullability = compositeType.getPropertyNullability();
				final int joinType = getJoinType(
						associationType,
						compositeType.getFetchMode(i),
						subpath,
						persister.getTableName(),
						lhsColumns,
						propertyNullability==null || propertyNullability[i],
						currentDepth, 
						compositeType.getCascadeStyle(i)
					);
				addAssociationToJoinTreeIfNecessary(
						associationType,
						aliasedLhsColumns,
						alias,
						subpath,
						currentDepth,
						joinType
					);
			}
			else if ( types[i].isComponentType() ) {
				String subpath = subPath( path, propertyNames[i] );
				walkCompositeElementTree(
						(AbstractComponentType) types[i],
						lhsColumns,
						persister,
						alias,
						subpath,
						currentDepth
					);
			}
			begin+=length;
		}

	}

	/**
	 * Extend the path by the given property name
	 */
	private static String subPath(String path, String property) {
		if ( path==null || path.length()==0) {
			return property;
		}
		else {
			return StringHelper.qualify(path, property);
		}
	}

	/**
	 * Get the join type (inner, outer, etc) or -1 if the
	 * association should not be joined. Override on
	 * subclasses.
	 */
	protected int getJoinType(
			AssociationType type, 
			FetchMode config, 
			String path, 
			String lhsTable,
			String[] lhsColumns,
			boolean nullable,
			int currentDepth, 
			CascadeStyle cascadeStyle)
	throws MappingException {
		
		if  ( !isJoinedFetchEnabled(type, config, cascadeStyle) ) return -1;
		
		if ( isTooDeep(currentDepth) || isTooManyCollections() ) return -1;
		
		final boolean dupe = isDuplicateAssociation(lhsTable,  lhsColumns, type);
		if (dupe) return -1;
		
		return getJoinType(nullable, currentDepth);
		
	}
	
	/**
	 * Use an inner join if it is a non-null association and this
	 * is the "first" join in a series
	 */
	protected int getJoinType(boolean nullable, int currentDepth) {
		//TODO: this is too conservative; if all preceding joins were 
		//      also inner joins, we could use an inner join here
		return !nullable && currentDepth==0 ? 
					JoinFragment.INNER_JOIN : 
					JoinFragment.LEFT_OUTER_JOIN;
	}

	protected boolean isTooDeep(int currentDepth) {
		Integer maxFetchDepth = getFactory().getSettings().getMaximumFetchDepth();
		return maxFetchDepth!=null && currentDepth >= maxFetchDepth.intValue();
	}
	
	protected boolean isTooManyCollections() {
		return false;
	}
	
	/**
	 * Does the mapping, and Hibernate default semantics, specify that
	 * this association should be fetched by outer joining
	 */
	protected boolean isJoinedFetchEnabledInMapping(FetchMode config, AssociationType type) 
	throws MappingException {
		if ( !type.isEntityType() && !type.isCollectionType() ) {
			return false;
		}
		else {
			if (config==FetchMode.JOIN) return true;
			if (config==FetchMode.SELECT) return false;
			if ( type.isEntityType() ) {
				//TODO: look at the owning property and check that it 
				//      isn't lazy (by instrumentation)
				EntityType entityType =(EntityType) type;
				EntityPersister persister = getFactory().getEntityPersister( entityType.getAssociatedEntityName() );
				return !persister.hasProxy();
			}
			else {
				return false;
			}
		}
	}

	/**
	 * Override on subclasses to enable or suppress joining 
	 * of certain association types
	 */
	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
		return type.isEntityType() && isJoinedFetchEnabledInMapping(config, type) ;
	}
	
	protected String generateTableAlias(
			final int n,
			final String path,
			final Joinable joinable
	) {
		return StringHelper.generateAlias( joinable.getName(), n );
	}

	protected String generateRootAlias(final String description) {
		return StringHelper.generateAlias(description, 0);
	}

	/**
	 * Used to detect circularities in the joined graph, note that 
	 * this method is side-effecty
	 */
	protected boolean isDuplicateAssociation(
		final String foreignKeyTable, 
		final String[] foreignKeyColumns
	) {
		AssociationKey associationKey = new AssociationKey(foreignKeyColumns, foreignKeyTable);
		return !visitedAssociationKeys.add( associationKey );
	}
	
	/**
	 * Used to detect circularities in the joined graph, note that 
	 * this method is side-effecty
	 */
	protected boolean isDuplicateAssociation(
		final String lhsTable,
		final String[] lhsColumnNames,
		final AssociationType type
	) {
		final String foreignKeyTable;
		final String[] foreignKeyColumns;
		if ( type.getForeignKeyDirection()==ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) {
			foreignKeyTable = lhsTable;
			foreignKeyColumns = lhsColumnNames;
		}
		else {
			foreignKeyTable = type.getAssociatedJoinable( getFactory() ).getTableName();
			foreignKeyColumns = JoinHelper.getRHSColumnNames( type, getFactory() );
		}
		return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns);
	}
	
	/**
	 * Uniquely identifier a foreign key, so that we don't
	 * join it more than once, and create circularities
	 */
	private static final class AssociationKey {
		private String[] columns;
		private String table;
		private AssociationKey(String[] columns, String table) {
			this.columns = columns;
			this.table = table;
		}
		public boolean equals(Object other) {
			AssociationKey that = (AssociationKey) other;
			return that.table.equals(table) && Arrays.equals(columns, that.columns);
		}
		public int hashCode() {
			return table.hashCode(); //TODO: inefficient
		}
	}
	
	/**
	 * Should we join this association?
	 */
	protected boolean isJoinable(
		final int joinType,
		final Set visitedAssociationKeys, 
		final String lhsTable,
		final String[] lhsColumnNames,
		final AssociationType type,
		final int depth
	) {
		if (joinType<0) return false;
		
		if (joinType==JoinFragment.INNER_JOIN) return true;
		
		Integer maxFetchDepth = getFactory().getSettings().getMaximumFetchDepth();
		final boolean tooDeep = maxFetchDepth!=null && 
			depth >= maxFetchDepth.intValue();
		
		return !tooDeep && !isDuplicateAssociation(lhsTable, lhsColumnNames, type);
	}
	
	protected String orderBy(final List associations, final String orderBy) {
		String fullOrderBy = orderBy(associations);
		if ( fullOrderBy.length()== 0 ) {
			fullOrderBy = orderBy;
		}
		else if ( orderBy.length()!=0 ) {
			fullOrderBy = fullOrderBy + ", " + orderBy;
		}
		return fullOrderBy;
	}
	
	/**
	 * Generate a sequence of <tt>LEFT OUTER JOIN</tt> clauses for the given associations.
	 */
	protected final JoinFragment mergeOuterJoins(List associations)
	throws MappingException {
		JoinFragment outerjoin = getDialect().createOuterJoinFragment();
		Iterator iter = associations.iterator();
		OuterJoinableAssociation last = null;
		while ( iter.hasNext() ) {
			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
			if ( last != null && last.isManyToManyWith( oj ) ) {
				oj.addManyToManyJoin( outerjoin, ( QueryableCollection ) last.getJoinable() );
			}
			else {
				oj.addJoins(outerjoin);
			}
			last = oj;
		}
		last = null;
		return outerjoin;
	}

	/**
	 * Count the number of instances of Joinable which are actually
	 * also instances of Loadable, or are one-to-many associations
	 */
	protected static final int countEntityPersisters(List associations)
	throws MappingException {
		int result = 0;
		Iterator iter = associations.iterator();
		while ( iter.hasNext() ) {
			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
			if ( oj.getJoinable().consumesEntityAlias() ) {
				result++;
			}
		}
		return result;
	}
	
	/**
	 * Count the number of instances of Joinable which are actually
	 * also instances of PersistentCollection which are being fetched
	 * by outer join
	 */
	protected static final int countCollectionPersisters(List associations)
	throws MappingException {
		int result = 0;
		Iterator iter = associations.iterator();
		while ( iter.hasNext() ) {
			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
			if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() ) {
				result++;
			}
		}
		return result;
	}
	
	/**
	 * Get the order by string required for collection fetching
	 */
	protected static final String orderBy(List associations)
	throws MappingException {
		StringBuffer buf = new StringBuffer();
		Iterator iter = associations.iterator();
		while ( iter.hasNext() ) {
			OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
			if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() ) {
				final QueryableCollection queryableCollection = (QueryableCollection) oj.getJoinable();
				if ( queryableCollection.hasOrdering() ) {
					final String orderByString = queryableCollection.getSQLOrderByString( oj.getRHSAlias() );
					buf.append( orderByString ).append(", ");
				}
			}
		}
		if ( buf.length()>0 ) buf.setLength( buf.length()-2 );
		return buf.toString();
	}
	
	/**
	 * Render the where condition for a (batch) load by identifier / collection key
	 */
	protected StringBuffer whereString(String alias, String[] columnNames, int batchSize) {
		if ( columnNames.length==1 ) {
			// if not a composite key, use "foo in (?, ?, ?)" for batching
			// if no batch, and not a composite key, use "foo = ?"
			InFragment in = new InFragment().setColumn( alias, columnNames[0] );
			for ( int i=0; i<batchSize; i++ ) in.addValue("?");
			return new StringBuffer( in.toFragmentString() );
		}
		else {
			//a composite key
			ConditionFragment byId = new ConditionFragment()
					.setTableAlias(alias)
					.setCondition( columnNames, "?" );
	
			StringBuffer whereString = new StringBuffer();
			if ( batchSize==1 ) {
				// if no batch, use "foo = ? and bar = ?"
				whereString.append( byId.toFragmentString() );
			}
			else {
				// if a composite key, use "( (foo = ? and bar = ?) or (foo = ? and bar = ?) )" for batching
				whereString.append('('); //TODO: unnecessary for databases with ANSI-style joins
				DisjunctionFragment df = new DisjunctionFragment();
				for ( int i=0; i<batchSize; i++ ) {
					df.addCondition(byId);
				}
				whereString.append( df.toFragmentString() );
				whereString.append(')'); //TODO: unnecessary for databases with ANSI-style joins
			}
			return whereString;
		}
	}

	protected void initPersisters(final List associations, final LockMode lockMode) throws MappingException {
		
		final int joins = countEntityPersisters(associations);
		final int collections = countCollectionPersisters(associations);

		collectionOwners = collections==0 ? null : new int[collections];
		collectionPersisters = collections==0 ? null : new CollectionPersister[collections];
		collectionSuffixes = BasicLoader.generateSuffixes( joins + 1, collections );

		persisters = new Loadable[joins];
		aliases = new String[joins];
		owners = new int[joins];
		ownerAssociationTypes = new EntityType[joins];
		lockModeArray = ArrayHelper.fillArray(lockMode, joins);
		
		int i=0;
		int j=0;
		Iterator iter = associations.iterator();
		while ( iter.hasNext() ) {
			final OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next();
			if ( !oj.isCollection() ) {
				
				persisters[i] = (Loadable) oj.getJoinable();
				aliases[i] = oj.getRHSAlias();
				owners[i] = oj.getOwner(associations);
				ownerAssociationTypes[i] = (EntityType) oj.getJoinableType();
				i++;
				
			}
			else {
				
				QueryableCollection collPersister = (QueryableCollection) oj.getJoinable();
				if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN ) {
					//it must be a collection fetch
					collectionPersisters[j] = collPersister;
					collectionOwners[j] = oj.getOwner(associations);
					j++;
				}
	
				if ( collPersister.isOneToMany() ) {
					persisters[i] = (Loadable) collPersister.getElementPersister();
					aliases[i] = oj.getRHSAlias();
					i++;
				}
			}
		}
	
		if ( ArrayHelper.isAllNegative(owners) ) owners = null;
		if ( collectionOwners!=null && ArrayHelper.isAllNegative(collectionOwners) ) {
			collectionOwners = null;
		}
	}

	/**
	 * Generate a select list of columns containing all properties of the entity classes
	 */
	protected final String selectString(List associations)
	throws MappingException {

		if ( associations.size()==0 ) {
			return "";
		}
		else {
			StringBuffer buf = new StringBuffer( associations.size() * 100 )
				.append(", ");
			int entityAliasCount=0;
			int collectionAliasCount=0;
			for ( int i=0; i<associations.size(); i++ ) {
				OuterJoinableAssociation join = (OuterJoinableAssociation) associations.get(i);
				OuterJoinableAssociation next = (i == associations.size() - 1)
				        ? null
				        : ( OuterJoinableAssociation ) associations.get( i + 1 );
				final Joinable joinable = join.getJoinable();
				final String entitySuffix = ( suffixes == null || entityAliasCount >= suffixes.length )
				        ? null
				        : suffixes[entityAliasCount];
				final String collectionSuffix = ( collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.length )
				        ? null
				        : collectionSuffixes[collectionAliasCount];
				final String selectFragment = joinable.selectFragment(
						next == null ? null : next.getJoinable(),
						next == null ? null : next.getRHSAlias(),
						join.getRHSAlias(),
						entitySuffix,
				        collectionSuffix,
						join.getJoinType()==JoinFragment.LEFT_OUTER_JOIN
				);
				buf.append(selectFragment);
				if ( joinable.consumesEntityAlias() ) entityAliasCount++;
				if ( joinable.consumesCollectionAlias() && join.getJoinType()==JoinFragment.LEFT_OUTER_JOIN ) collectionAliasCount++;
				if (
					i<associations.size()-1 &&
					selectFragment.trim().length()>0
				) {
					buf.append(", ");
				}
			}
			return buf.toString();
		}
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -