[hibernate-commits] Hibernate SVN: r15091 - in core/trunk: core/src/main/java/org/hibernate/cfg and 17 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Fri Aug 15 17:20:16 EDT 2008


Author: steve.ebersole at jboss.com
Date: 2008-08-15 17:20:15 -0400 (Fri, 15 Aug 2008)
New Revision: 15091

Added:
   core/trunk/core/src/main/java/org/hibernate/UnknownProfileException.java
   core/trunk/core/src/main/java/org/hibernate/engine/LoadQueryInfluencers.java
   core/trunk/core/src/main/java/org/hibernate/engine/profile/
   core/trunk/core/src/main/java/org/hibernate/engine/profile/Association.java
   core/trunk/core/src/main/java/org/hibernate/engine/profile/Fetch.java
   core/trunk/core/src/main/java/org/hibernate/engine/profile/FetchProfile.java
   core/trunk/core/src/main/java/org/hibernate/mapping/FetchProfile.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/BasicFetchProfileTest.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Course.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/CourseOffering.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Department.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Enrollment.java
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Mappings.hbm.xml
   core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Student.java
Modified:
   core/trunk/core/src/main/java/org/hibernate/Session.java
   core/trunk/core/src/main/java/org/hibernate/SessionFactory.java
   core/trunk/core/src/main/java/org/hibernate/cfg/Configuration.java
   core/trunk/core/src/main/java/org/hibernate/cfg/HbmBinder.java
   core/trunk/core/src/main/java/org/hibernate/cfg/Mappings.java
   core/trunk/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java
   core/trunk/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java
   core/trunk/core/src/main/java/org/hibernate/engine/SessionImplementor.java
   core/trunk/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java
   core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java
   core/trunk/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java
   core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/JoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
   core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
   core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
   core/trunk/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java
   core/trunk/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java
   core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
   core/trunk/core/src/main/java/org/hibernate/persister/entity/Loadable.java
   core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
   core/trunk/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java
   core/trunk/testsuite/src/test/resources/hibernate.properties
Log:
HHH-3414 : fetch profiles, phase 1 : join fetching

Modified: core/trunk/core/src/main/java/org/hibernate/Session.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/Session.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/Session.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -813,4 +813,40 @@
 	 * @see #disconnect()
 	 */
 	void reconnect(Connection connection) throws HibernateException;
+
+	/**
+	 * Is a particular fetch profile enabled on this session?
+	 *
+	 * @param name The name of the profile to be checked.
+	 * @return True if fetch profile is enabled; false if not.
+	 * @throws UnknownProfileException Indicates that the given name does not
+	 * match any known profile names
+	 *
+	 * @see org.hibernate.engine.profile.FetchProfile for discussion of this feature
+	 */
+	public boolean isFetchProfileEnabled(String name) throws UnknownProfileException;
+
+	/**
+	 * Enable a particular fetch profile on this session.  No-op if requested
+	 * profile is already enabled.
+	 *
+	 * @param name The name of the fetch profile to be enabled.
+	 * @throws UnknownProfileException Indicates that the given name does not
+	 * match any known profile names
+	 *
+	 * @see org.hibernate.engine.profile.FetchProfile for discussion of this feature
+	 */
+	public void enableFetchProfile(String name) throws UnknownProfileException;
+
+	/**
+	 * Disable a particular fetch profile on this session.  No-op if requested
+	 * profile is already disabled.
+	 *
+	 * @param name The name of the fetch profile to be disabled.
+	 * @throws UnknownProfileException Indicates that the given name does not
+	 * match any known profile names
+	 *
+	 * @see org.hibernate.engine.profile.FetchProfile for discussion of this feature
+	 */
+	public void disableFetchProfile(String name) throws UnknownProfileException;
 }

Modified: core/trunk/core/src/main/java/org/hibernate/SessionFactory.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/SessionFactory.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/SessionFactory.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -244,4 +244,13 @@
 	 * @throws HibernateException If no filter defined with the given name.
 	 */
 	public FilterDefinition getFilterDefinition(String filterName) throws HibernateException;
+
+	/**
+	 * Determine if this session factory contains a fetch profile definition
+	 * registered under the given name.
+	 *
+	 * @param name The name to check
+	 * @return True if there is such a fetch profile; false otherwise.
+	 */
+	public boolean containsFetchProfileDefition(String name);
 }

Added: core/trunk/core/src/main/java/org/hibernate/UnknownProfileException.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/UnknownProfileException.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/UnknownProfileException.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,48 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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;
+
+/**
+ * Used to indicate a request against an unknown profile name.
+ *
+ * @author Steve Ebersole
+ */
+public class UnknownProfileException extends HibernateException {
+	private final String name;
+
+	public UnknownProfileException(String name) {
+		super( "Unknow fetch profile [" + name + "]" );
+		this.name = name;
+	}
+
+	/**
+	 * The unknown fetch profile name.
+	 *
+	 * @return The unknown fetch profile name.
+	 */
+	public String getName() {
+		return name;
+	}
+}

Modified: core/trunk/core/src/main/java/org/hibernate/cfg/Configuration.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/cfg/Configuration.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/cfg/Configuration.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -114,6 +114,7 @@
 import org.hibernate.mapping.SimpleValue;
 import org.hibernate.mapping.Table;
 import org.hibernate.mapping.UniqueKey;
+import org.hibernate.mapping.FetchProfile;
 import org.hibernate.proxy.EntityNotFoundDelegate;
 import org.hibernate.secure.JACCConfiguration;
 import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
@@ -163,6 +164,7 @@
 	 */
 	protected Map sqlResultSetMappings;
 	protected Map filterDefinitions;
+	protected Map fetchProfiles;
 	protected List secondPasses;
 	protected List propertyReferences;
 //	protected List extendsQueue;
@@ -202,6 +204,7 @@
 		entityResolver = XMLHelper.DEFAULT_DTD_RESOLVER;
 		eventListeners = new EventListeners();
 		filterDefinitions = new HashMap();
+		fetchProfiles = new HashMap();
 //		extendsQueue = new ArrayList();
 		extendsQueue = new HashMap();
 		auxiliaryDatabaseObjects = new ArrayList();
@@ -720,6 +723,7 @@
 				namingStrategy,
 				typeDefs,
 				filterDefinitions,
+				fetchProfiles,
 				extendsQueue,
 				auxiliaryDatabaseObjects,
 				tableNameBinding,
@@ -2181,6 +2185,14 @@
 		filterDefinitions.put( definition.getFilterName(), definition );
 	}
 
+	public Map getFetchProfiles() {
+		return fetchProfiles;
+	}
+
+	public void addFetchProfile(FetchProfile fetchProfile) {
+		fetchProfiles.put( fetchProfile.getName(), fetchProfile );
+	}
+
 	public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject object) {
 		auxiliaryDatabaseObjects.add( object );
 	}

Modified: core/trunk/core/src/main/java/org/hibernate/cfg/HbmBinder.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/cfg/HbmBinder.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/cfg/HbmBinder.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -89,6 +89,7 @@
 import org.hibernate.mapping.UnionSubclass;
 import org.hibernate.mapping.UniqueKey;
 import org.hibernate.mapping.Value;
+import org.hibernate.mapping.FetchProfile;
 import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
 import org.hibernate.persister.entity.SingleTableEntityPersister;
 import org.hibernate.persister.entity.UnionSubclassEntityPersister;
@@ -158,6 +159,9 @@
 			if ( "filter-def".equals( elementName ) ) {
 				parseFilterDef( element, mappings );
 			}
+			else if ( "fetch-profile".equals( elementName ) ) {
+				parseFetchProfile( element, mappings, null );
+			}
 			else if ( "typedef".equals( elementName ) ) {
 				bindTypeDef( element, mappings );
 			}
@@ -546,8 +550,13 @@
 		bindDom4jRepresentation( node, persistentClass, mappings, inheritedMetas );
 		bindMapRepresentation( node, persistentClass, mappings, inheritedMetas );
 
+		Iterator itr = node.elementIterator( "fetch-profile" );
+		while ( itr.hasNext() ) {
+			final Element profileElement = ( Element ) itr.next();
+			parseFetchProfile( profileElement, mappings, entityName );
+		}
+
 		bindPersistentClassCommonValues( node, persistentClass, mappings, inheritedMetas );
-
 	}
 
 	private static void bindPojoRepresentation(Element node, PersistentClass entity,
@@ -2963,6 +2972,25 @@
 		filterable.addFilter( name, condition );
 	}
 
+	private static void parseFetchProfile(Element element, Mappings mappings, String containingEntityName) {
+		String profileName = element.attributeValue( "name" );
+		FetchProfile profile = mappings.findOrCreateFetchProfile( profileName );
+		Iterator itr = element.elementIterator( "fetch" );
+		while ( itr.hasNext() ) {
+			final Element fetchElement = ( Element ) itr.next();
+			final String association = fetchElement.attributeValue( "association" );
+			final String style = fetchElement.attributeValue( "style" );
+			String entityName = fetchElement.attributeValue( "entity" );
+			if ( entityName == null ) {
+				entityName = containingEntityName;
+			}
+			if ( entityName == null ) {
+				throw new MappingException( "could not determine entity for fetch-profile fetch [" + profileName + "]:[" + association + "]" );
+			}
+			profile.addFetch( entityName, association, style );
+		}
+	}
+
 	private static String getSubselect(Element element) {
 		String subselect = element.attributeValue( "subselect" );
 		if ( subselect != null ) {

Modified: core/trunk/core/src/main/java/org/hibernate/cfg/Mappings.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/cfg/Mappings.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/cfg/Mappings.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -46,6 +46,7 @@
 import org.hibernate.mapping.TypeDef;
 import org.hibernate.mapping.AuxiliaryDatabaseObject;
 import org.hibernate.mapping.Column;
+import org.hibernate.mapping.FetchProfile;
 import org.hibernate.util.StringHelper;
 
 /**
@@ -77,6 +78,7 @@
 	protected final List propertyReferences;
 	protected final NamingStrategy namingStrategy;
 	protected final Map filterDefinitions;
+	protected final Map fetchProfiles;
 	protected final List auxiliaryDatabaseObjects;
 
 	protected final Map extendsQueue;
@@ -111,12 +113,12 @@
 			final NamingStrategy namingStrategy,
 			final Map typeDefs,
 			final Map filterDefinitions,
+			final Map fetchProfiles,
 //			final List extendsQueue,
 			final Map extendsQueue,
 			final List auxiliaryDatabaseObjects,
 			final Map tableNamebinding,
-			final Map columnNameBindingPerTable
-			) {
+			final Map columnNameBindingPerTable) {
 		this.classes = classes;
 		this.collections = collections;
 		this.queries = queries;
@@ -129,6 +131,7 @@
 		this.namingStrategy = namingStrategy;
 		this.typeDefs = typeDefs;
 		this.filterDefinitions = filterDefinitions;
+		this.fetchProfiles = fetchProfiles;
 		this.extendsQueue = extendsQueue;
 		this.auxiliaryDatabaseObjects = auxiliaryDatabaseObjects;
 		this.tableNameBinding = tableNamebinding;
@@ -418,7 +421,20 @@
 	public FilterDefinition getFilterDefinition(String name) {
 		return (FilterDefinition) filterDefinitions.get(name);
 	}
-	
+
+	public Map getFetchProfiles() {
+		return fetchProfiles;
+	}
+
+	public FetchProfile findOrCreateFetchProfile(String name) {
+		FetchProfile profile = ( FetchProfile ) fetchProfiles.get( name );
+		if ( profile == null ) {
+			profile = new FetchProfile( name );
+			fetchProfiles.put( name, profile );
+		}
+		return profile;
+	}
+
 	public boolean isDefaultLazy() {
 		return defaultLazy;
 	}

Modified: core/trunk/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/criterion/SubqueryExpression.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -32,6 +32,7 @@
 import org.hibernate.engine.QueryParameters;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.TypedValue;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.impl.CriteriaImpl;
 import org.hibernate.loader.criteria.CriteriaJoinWalker;
 import org.hibernate.loader.criteria.CriteriaQueryTranslator;
@@ -76,8 +77,9 @@
 				factory,
 				criteriaImpl,
 				criteriaImpl.getEntityOrClassName(),
-				new HashMap(),
-				innerQuery.getRootSQLALias());
+				LoadQueryInfluencers.NONE,
+				innerQuery.getRootSQLALias()
+		);
 
 		String sql = walker.getSQLString();
 

Added: core/trunk/core/src/main/java/org/hibernate/engine/LoadQueryInfluencers.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/LoadQueryInfluencers.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/engine/LoadQueryInfluencers.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,192 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.engine;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.hibernate.Filter;
+import org.hibernate.UnknownProfileException;
+import org.hibernate.type.Type;
+import org.hibernate.impl.FilterImpl;
+
+/**
+ * Centralize all options which can influence the SQL query needed to load and
+ * entity.  Currently such influencers are defined as:<ul>
+ * <li>filters</li>
+ * <li>fetch profiles</li>
+ * <li>internal fetch profile (merge profile, etc)</li>
+ * </ul>
+ *
+ * @author Steve Ebersole
+ */
+public class LoadQueryInfluencers {
+	/**
+	 * Static reference useful for cases where we are creating load SQL
+	 * outside the context of any influencers.  One such example is
+	 * anything created by the session factory.
+	 */
+	public static LoadQueryInfluencers NONE = new LoadQueryInfluencers();
+
+	private final SessionFactoryImplementor sessionFactory;
+	private String internalFetchProfile;
+	private Map enabledFilters;
+	private Set enabledFetchProfileNames;
+
+	public LoadQueryInfluencers() {
+		this( null, java.util.Collections.EMPTY_MAP, java.util.Collections.EMPTY_SET );
+	}
+
+	public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory) {
+		this( sessionFactory, new HashMap(), new HashSet() );
+	}
+
+	private LoadQueryInfluencers(SessionFactoryImplementor sessionFactory, Map enabledFilters, Set enabledFetchProfileNames) {
+		this.sessionFactory = sessionFactory;
+		this.enabledFilters = enabledFilters;
+		this.enabledFetchProfileNames = enabledFetchProfileNames;
+	}
+
+	public SessionFactoryImplementor getSessionFactory() {
+		return sessionFactory;
+	}
+
+
+	// internal fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public String getInternalFetchProfile() {
+		return internalFetchProfile;
+	}
+
+	public void setInternalFetchProfile(String internalFetchProfile) {
+		if ( sessionFactory == null ) {
+			// thats the signal that this is the immutable, context-less
+			// variety
+			throw new IllegalStateException( "Cannot modify context-less LoadQueryInfluencers" );
+		}
+		this.internalFetchProfile = internalFetchProfile;
+	}
+
+
+	// filter support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean hasEnabledFilters() {
+		return enabledFilters != null && !enabledFilters.isEmpty();
+	}
+
+	public Map getEnabledFilters() {
+		// First, validate all the enabled filters...
+		//TODO: this implementation has bad performance
+		Iterator itr = enabledFilters.values().iterator();
+		while ( itr.hasNext() ) {
+			final Filter filter = ( Filter ) itr.next();
+			filter.validate();
+		}
+		return enabledFilters;
+	}
+
+	public Filter getEnabledFilter(String filterName) {
+		return ( Filter ) enabledFilters.get( filterName );
+	}
+
+	public Filter enableFilter(String filterName) {
+		FilterImpl filter = new FilterImpl( sessionFactory.getFilterDefinition( filterName ) );
+		enabledFilters.put( filterName, filter );
+		return filter;
+	}
+
+	public void disableFilter(String filterName) {
+		enabledFilters.remove( filterName );
+	}
+
+	public Object getFilterParameterValue(String filterParameterName) {
+		String[] parsed = parseFilterParameterName( filterParameterName );
+		FilterImpl filter = ( FilterImpl ) enabledFilters.get( parsed[0] );
+		if ( filter == null ) {
+			throw new IllegalArgumentException( "Filter [" + parsed[0] + "] currently not enabled" );
+		}
+		return filter.getParameter( parsed[1] );
+	}
+
+	public Type getFilterParameterType(String filterParameterName) {
+		String[] parsed = parseFilterParameterName( filterParameterName );
+		FilterDefinition filterDef = sessionFactory.getFilterDefinition( parsed[0] );
+		if ( filterDef == null ) {
+			throw new IllegalArgumentException( "Filter [" + parsed[0] + "] not defined" );
+		}
+		Type type = filterDef.getParameterType( parsed[1] );
+		if ( type == null ) {
+			// this is an internal error of some sort...
+			throw new InternalError( "Unable to locate type for filter parameter" );
+		}
+		return type;
+	}
+
+	public static String[] parseFilterParameterName(String filterParameterName) {
+		int dot = filterParameterName.indexOf( '.' );
+		if ( dot <= 0 ) {
+			throw new IllegalArgumentException( "Invalid filter-parameter name format" );
+		}
+		String filterName = filterParameterName.substring( 0, dot );
+		String parameterName = filterParameterName.substring( dot + 1 );
+		return new String[] { filterName, parameterName };
+	}
+
+
+	// fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean hasEnabledFetchProfiles() {
+		return enabledFetchProfileNames != null && !enabledFetchProfileNames.isEmpty();
+	}
+
+	public Set getEnabledFetchProfileNames() {
+		return enabledFetchProfileNames;
+	}
+
+	private void checkFetchProfileName(String name) {
+		if ( !sessionFactory.containsFetchProfileDefition( name ) ) {
+			throw new UnknownProfileException( name );
+		}
+	}
+
+	public boolean isFetchProfileEnabled(String name) throws UnknownProfileException {
+		checkFetchProfileName( name );
+		return enabledFetchProfileNames.contains( name );
+	}
+
+	public void enableFetchProfile(String name) throws UnknownProfileException {
+		checkFetchProfileName( name );
+		enabledFetchProfileNames.add( name );
+	}
+
+	public void disableFetchProfile(String name) throws UnknownProfileException {
+		checkFetchProfileName( name );
+		enabledFetchProfileNames.remove( name );
+	}
+
+}

Modified: core/trunk/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/engine/SessionFactoryImplementor.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -37,6 +37,7 @@
 import org.hibernate.ConnectionReleaseMode;
 import org.hibernate.proxy.EntityNotFoundDelegate;
 import org.hibernate.engine.query.QueryPlanCache;
+import org.hibernate.engine.profile.FetchProfile;
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.cache.QueryCache;
@@ -219,5 +220,13 @@
 	public EntityNotFoundDelegate getEntityNotFoundDelegate();
 
 	public SQLFunctionRegistry getSqlFunctionRegistry();
-		
+
+	/**
+	 * Retrieve fetch profile by name.
+	 *
+	 * @param name The name of the profile to retrieve.
+	 * @return The profile definition
+	 */
+	public FetchProfile getFetchProfile(String name);
+
 }

Modified: core/trunk/core/src/main/java/org/hibernate/engine/SessionImplementor.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/SessionImplementor.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/engine/SessionImplementor.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -29,6 +29,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.hibernate.CacheMode;
 import org.hibernate.EntityMode;
@@ -237,6 +238,7 @@
 	 * @param filterParameterName The filter parameter name in the format
 	 * {FILTER_NAME.PARAMETER_NAME}.
 	 * @return The filter parameter value.
+	 * @deprecated use #getLoadQueryInfluencers instead
 	 */
 	public Object getFilterParameterValue(String filterParameterName);
 
@@ -245,6 +247,8 @@
 	 *
 	 * @param filterParameterName The filter parameter name in the format
 	 * {FILTER_NAME.PARAMETER_NAME}.
+	 * @return The filter param type
+	 * @deprecated use #getLoadQueryInfluencers instead
 	 */
 	public Type getFilterParameterType(String filterParameterName);
 
@@ -253,6 +257,7 @@
 	 * name, with values corresponding to the {@link org.hibernate.impl.FilterImpl}
 	 * instance.
 	 * @return The currently enabled filters.
+	 * @deprecated use #getLoadQueryInfluencers instead
 	 */
 	public Map getEnabledFilters();
 	
@@ -307,10 +312,22 @@
 
 	public void afterScrollOperation();
 
+	/**
+	 * Get the <i>internal</i> fetch profile currently associated with this session.
+	 *
+	 * @return The current internal fetch profile, or null if none currently associated.
+	 * @deprecated use #getLoadQueryInfluencers instead
+	 */
+	public String getFetchProfile();
+
+	/**
+	 * Set the current <i>internal</i> fetch profile for this session.
+	 *
+	 * @param name The internal fetch profile name to use
+	 * @deprecated use #getLoadQueryInfluencers instead
+	 */
 	public void setFetchProfile(String name);
 
-	public String getFetchProfile();
-
 	public JDBCContext getJDBCContext();
 
 	/**
@@ -322,4 +339,12 @@
 	 * @return True if the session is closed; false otherwise.
 	 */
 	public boolean isClosed();
+
+	/**
+	 * Get the load query influencers associated with this session.
+	 *
+	 * @return the load query influencers associated with this session;
+	 * should never be null.
+	 */
+	public LoadQueryInfluencers getLoadQueryInfluencers();
 }

Added: core/trunk/core/src/main/java/org/hibernate/engine/profile/Association.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/profile/Association.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/engine/profile/Association.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,56 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.engine.profile;
+
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * Models the association of a given fetch.
+ *
+ * @author Steve Ebersole
+ */
+public class Association {
+	private final EntityPersister owner;
+	private final String associationPath;
+	private final String role;
+
+	public Association(EntityPersister owner, String associationPath) {
+		this.owner = owner;
+		this.associationPath = associationPath;
+		this.role = owner.getEntityName() + '.' + associationPath;
+	}
+
+	public EntityPersister getOwner() {
+		return owner;
+	}
+
+	public String getAssociationPath() {
+		return associationPath;
+	}
+
+	public String getRole() {
+		return role;
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/engine/profile/Fetch.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/profile/Fetch.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/engine/profile/Fetch.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,84 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.engine.profile;
+
+/**
+ * Models an individual fetch within a profile.
+ *
+ * @author Steve Ebersole
+ */
+public class Fetch {
+	private final Association association;
+	private final Style style;
+
+	public Fetch(Association association, Style style) {
+		this.association = association;
+		this.style = style;
+	}
+
+	public Association getAssociation() {
+		return association;
+	}
+
+	public Style getStyle() {
+		return style;
+	}
+
+	/**
+	 * The type or style of fetch.  For the moment we limit this to
+	 * join and select, though technically subselect would be valid
+	 * here as as well; however, to support subselect here would
+	 * require major changes to the subselect loading code (which is
+	 * needed for other things as well anyway).
+	 */
+	public static class Style {
+		public static final Style JOIN = new Style( "join" );
+		public static final Style SELECT = new Style( "select" );
+
+		private final String name;
+
+		private Style(String name) {
+			this.name = name;
+		}
+
+		public String toString() {
+			return name;
+		}
+
+		public static Style parse(String name) {
+			if ( SELECT.name.equals( name ) ) {
+				return SELECT;
+			}
+			else {
+				// the default...
+				return JOIN;
+			}
+		}
+	}
+
+	public String toString() {
+		return "Fetch[" + style + "{" + association.getRole() + "}]";
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/engine/profile/FetchProfile.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/engine/profile/FetchProfile.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/engine/profile/FetchProfile.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,169 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.engine.profile;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+import org.hibernate.type.BagType;
+import org.hibernate.type.AssociationType;
+
+/**
+ * A 'fetch profile' allows a user to dynamically modify the fetching
+ * strategy used for particular associations at runtime, whereas that
+ * information was historically only statically defined in the metadata.
+ *
+ * @author Steve Ebersole
+ */
+public class FetchProfile {
+	private static final Logger log = LoggerFactory.getLogger( FetchProfile.class );
+
+	private final String name;
+	private Map fetches = new HashMap();
+
+	private boolean containsJoinFetchedCollection = false;
+	private boolean containsJoinFetchedBag = false;
+	private Fetch bagJoinFetch;
+
+	/**
+	 * A 'fetch profile' is uniquely named within a
+	 * {@link SessionFactoryImplementor SessionFactory}, thus it is also
+	 * uniquely and easily identifiable within that
+	 * {@link SessionFactoryImplementor SessionFactory}.
+	 *
+	 * @param name The name under which we are bound in the sessionFactory
+	 */
+	public FetchProfile(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Add a fetch to the profile.
+	 *
+	 * @param association The association to be fetched
+	 * @param fetchStyleName The name of the fetch style to apply
+	 */
+	public void addFetch(Association association, String fetchStyleName) {
+		addFetch( association, Fetch.Style.parse( fetchStyleName ) );
+	}
+
+	/**
+	 * Add a fetch to the profile.
+	 *
+	 * @param association The association to be fetched
+	 * @param style The style to apply
+	 */
+	public void addFetch(Association association, Fetch.Style style) {
+		addFetch( new Fetch( association, style ) );
+	}
+
+	/**
+	 * Add a fetch to the profile.
+	 *
+	 * @param fetch The fetch to add.
+	 */
+	public void addFetch(Fetch fetch) {
+		Type associationType = fetch.getAssociation().getOwner().getPropertyType( fetch.getAssociation().getAssociationPath() );
+		if ( associationType.isCollectionType() ) {
+			log.trace( "handling request to add collection fetch [{}]", fetch.getAssociation().getRole() );
+
+			// couple of things for whcih to account in the case of collection
+			// join fetches
+			if ( Fetch.Style.JOIN == fetch.getStyle() ) {
+				// first, if this is a bag we need to ignore it if we previously
+				// processed collection join fetches
+				if ( BagType.class.isInstance( associationType ) ) {
+					if ( containsJoinFetchedCollection ) {
+						log.warn( "Ignoring bag join fetch [{}] due to prior collection join fetch", fetch.getAssociation().getRole() );
+						return; // EARLY EXIT!!!
+					}
+				}
+
+				// also, in cases where we are asked to add a collection join
+				// fetch where we had already added a bag join fetch previously,
+				// we need to go back and ignore that previous bag join fetch.
+				if ( containsJoinFetchedBag ) {
+					if ( fetches.remove( bagJoinFetch.getAssociation().getRole() ) != bagJoinFetch ) {
+						// just for safety...
+						log.warn( "Unable to erase previously added bag join fetch" );
+					}
+					bagJoinFetch = null;
+					containsJoinFetchedBag = false;
+				}
+
+				containsJoinFetchedCollection = true;
+			}
+		}
+		fetches.put( fetch.getAssociation().getRole(), fetch );
+	}
+
+	/**
+	 * Getter for property 'name'.
+	 *
+	 * @return Value for property 'name'.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Getter for property 'fetches'.  Map of {@link Fetch} instances,
+	 * keyed by associaion <tt>role</tt>
+	 *
+	 * @return Value for property 'fetches'.
+	 */
+	public Map getFetches() {
+		return fetches;
+	}
+
+	public Fetch getFetchByRole(String role) {
+		return ( Fetch ) fetches.get( role );
+	}
+
+	/**
+	 * Getter for property 'containsJoinFetchedCollection', which flags whether
+	 * this fetch profile contained any collection join fetches.
+	 *
+	 * @return Value for property 'containsJoinFetchedCollection'.
+	 */
+	public boolean isContainsJoinFetchedCollection() {
+		return containsJoinFetchedCollection;
+	}
+
+	/**
+	 * Getter for property 'containsJoinFetchedBag', which flags whether this
+	 * fetch profile contained any bag join fetches
+	 *
+	 * @return Value for property 'containsJoinFetchedBag'.
+	 */
+	public boolean isContainsJoinFetchedBag() {
+		return containsJoinFetchedBag;
+	}
+}

Modified: core/trunk/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/impl/SessionFactoryImpl.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -84,6 +84,9 @@
 import org.hibernate.engine.NamedSQLQueryDefinition;
 import org.hibernate.engine.ResultSetMappingDefinition;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.profile.FetchProfile;
+import org.hibernate.engine.profile.Fetch;
+import org.hibernate.engine.profile.Association;
 import org.hibernate.engine.query.QueryPlanCache;
 import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
 import org.hibernate.event.EventListeners;
@@ -100,6 +103,7 @@
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.persister.entity.Queryable;
+import org.hibernate.persister.entity.Loadable;
 import org.hibernate.pretty.MessageHelper;
 import org.hibernate.proxy.EntityNotFoundDelegate;
 import org.hibernate.stat.Statistics;
@@ -156,6 +160,7 @@
 	private final transient Map namedSqlQueries;
 	private final transient Map sqlResultSetMappings;
 	private final transient Map filters;
+	private final transient Map fetchProfiles;
 	private final transient Map imports;
 	private final transient Interceptor interceptor;
 	private final transient Settings settings;
@@ -198,6 +203,7 @@
 			public void sessionFactoryClosed(SessionFactory factory) {
 			}
 		};
+
 		this.filters = new HashMap();
 		this.filters.putAll( cfg.getFilterDefinitions() );
 
@@ -412,6 +418,43 @@
 		}
 		this.entityNotFoundDelegate = entityNotFoundDelegate;
 
+		// this needs to happen after persisters are all ready to go...
+		this.fetchProfiles = new HashMap();
+		itr = cfg.getFetchProfiles().values().iterator();
+		while ( itr.hasNext() ) {
+			final org.hibernate.mapping.FetchProfile mappingProfile =
+					( org.hibernate.mapping.FetchProfile ) itr.next();
+			final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() );
+			Iterator fetches = mappingProfile.getFetches().iterator();
+			while ( fetches.hasNext() ) {
+				final org.hibernate.mapping.FetchProfile.Fetch mappingFetch =
+						( org.hibernate.mapping.FetchProfile.Fetch ) fetches.next();
+				// resolve the persister owning the fetch
+				final String entityName = getImportedClassName( mappingFetch.getEntity() );
+				final EntityPersister owner = ( EntityPersister ) ( entityName == null ? null : entityPersisters.get( entityName ) );
+				if ( owner == null ) {
+					throw new HibernateException(
+							"Unable to resolve entity reference [" + mappingFetch.getEntity()
+									+ "] in fetch profile [" + fetchProfile.getName() + "]"
+					);
+				}
+
+				// validate the specified association fetch
+				Type associationType = owner.getPropertyType( mappingFetch.getAssociation() );
+				if ( associationType == null || !associationType.isAssociationType() ) {
+					throw new HibernateException( "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association" );
+				}
+
+				// resolve the style
+				final Fetch.Style fetchStyle = Fetch.Style.parse( mappingFetch.getStyle() );
+
+				// then construct the fetch instance...
+				fetchProfile.addFetch( new Association( owner, mappingFetch.getAssociation() ), fetchStyle );
+				( ( Loadable ) owner ).registerAffectingFetchProfile( fetchProfile.getName() );
+			}
+			fetchProfiles.put( fetchProfile.getName(), fetchProfile );
+		}
+
 		this.observer.sessionFactoryCreated( this );
 	}
 
@@ -1004,6 +1047,10 @@
 		return def;
 	}
 
+	public boolean containsFetchProfileDefition(String name) {
+		return fetchProfiles.containsKey( name );
+	}
+
 	public Set getDefinedFilterNames() {
 		return filters.keySet();
 	}
@@ -1061,6 +1108,14 @@
 		return entityNotFoundDelegate;
 	}
 
+	public SQLFunctionRegistry getSqlFunctionRegistry() {
+		return sqlFunctionRegistry;
+	}
+
+	public FetchProfile getFetchProfile(String name) {
+		return ( FetchProfile ) fetchProfiles.get( name );
+	}
+
 	/**
 	 * Custom serialization hook used during Session serialization.
 	 *
@@ -1102,8 +1157,4 @@
 		}
 		return ( SessionFactoryImpl ) result;
 	}
-
-	public SQLFunctionRegistry getSqlFunctionRegistry() {
-		return sqlFunctionRegistry;
-	}
 }

Modified: core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/impl/SessionImpl.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -66,6 +66,7 @@
 import org.hibernate.Transaction;
 import org.hibernate.TransientObjectException;
 import org.hibernate.UnresolvableObjectException;
+import org.hibernate.UnknownProfileException;
 import org.hibernate.collection.PersistentCollection;
 import org.hibernate.engine.ActionQueue;
 import org.hibernate.engine.CollectionEntry;
@@ -76,6 +77,7 @@
 import org.hibernate.engine.QueryParameters;
 import org.hibernate.engine.StatefulPersistenceContext;
 import org.hibernate.engine.Status;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.engine.query.FilterQueryPlan;
 import org.hibernate.engine.query.HQLQueryPlan;
 import org.hibernate.engine.query.NativeSQLQueryPlan;
@@ -167,10 +169,8 @@
 	private transient boolean flushBeforeCompletionEnabled;
 	private transient boolean autoCloseSessionEnabled;
 	private transient ConnectionReleaseMode connectionReleaseMode;
-	
-	private transient String fetchProfile;
 
-	private transient Map enabledFilters = new HashMap();
+	private transient LoadQueryInfluencers loadQueryInfluencers;
 
 	private transient Session rootSession;
 	private transient Map childSessionsByEntityMode;
@@ -195,6 +195,8 @@
 		this.autoCloseSessionEnabled = false;
 		this.connectionReleaseMode = null;
 
+		loadQueryInfluencers = new LoadQueryInfluencers( factory );
+
 		if ( factory.getStatistics().isStatisticsEnabled() ) {
 			factory.getStatisticsImplementor().openSession();
 		}
@@ -239,6 +241,8 @@
 		this.connectionReleaseMode = connectionReleaseMode;
 		this.jdbcContext = new JDBCContext( this, connection, interceptor );
 
+		loadQueryInfluencers = new LoadQueryInfluencers( factory );
+
 		if ( factory.getStatistics().isStatisticsEnabled() ) {
 			factory.getStatisticsImplementor().openSession();
 		}
@@ -1048,76 +1052,7 @@
 		flush();
 	}
 
-	public Filter getEnabledFilter(String filterName) {
-		checkTransactionSynchStatus();
-		return (Filter) enabledFilters.get(filterName);
-	}
 
-	public Filter enableFilter(String filterName) {
-		errorIfClosed();
-		checkTransactionSynchStatus();
-		FilterImpl filter = new FilterImpl( factory.getFilterDefinition(filterName) );
-		enabledFilters.put(filterName, filter);
-		return filter;
-	}
-
-	public void disableFilter(String filterName) {
-		errorIfClosed();
-		checkTransactionSynchStatus();
-		enabledFilters.remove(filterName);
-	}
-
-	public Object getFilterParameterValue(String filterParameterName) {
-		errorIfClosed();
-		checkTransactionSynchStatus();
-		String[] parsed = parseFilterParameterName(filterParameterName);
-		FilterImpl filter = (FilterImpl) enabledFilters.get( parsed[0] );
-		if (filter == null) {
-			throw new IllegalArgumentException("Filter [" + parsed[0] + "] currently not enabled");
-		}
-		return filter.getParameter( parsed[1] );
-	}
-
-	public Type getFilterParameterType(String filterParameterName) {
-		errorIfClosed();
-		checkTransactionSynchStatus();
-		String[] parsed = parseFilterParameterName(filterParameterName);
-		FilterDefinition filterDef = factory.getFilterDefinition( parsed[0] );
-		if (filterDef == null) {
-			throw new IllegalArgumentException("Filter [" + parsed[0] + "] not defined");
-		}
-		Type type = filterDef.getParameterType( parsed[1] );
-		if (type == null) {
-			// this is an internal error of some sort...
-			throw new InternalError("Unable to locate type for filter parameter");
-		}
-		return type;
-	}
-
-	public Map getEnabledFilters() {
-		errorIfClosed();
-		checkTransactionSynchStatus();
-		// First, validate all the enabled filters...
-		//TODO: this implementation has bad performance
-		Iterator itr = enabledFilters.values().iterator();
-		while ( itr.hasNext() ) {
-			final Filter filter = (Filter) itr.next();
-			filter.validate();
-		}
-		return enabledFilters;
-	}
-
-	private String[] parseFilterParameterName(String filterParameterName) {
-		int dot = filterParameterName.indexOf('.');
-		if (dot <= 0) {
-			throw new IllegalArgumentException("Invalid filter-parameter name format"); // TODO: what type?
-		}
-		String filterName = filterParameterName.substring(0, dot);
-		String parameterName = filterParameterName.substring(dot+1);
-		return new String[] {filterName, parameterName};
-	}
-
-
 	/**
 	 * Retrieve a list of persistent objects using a hibernate query
 	 */
@@ -1432,7 +1367,7 @@
 		return listFilter( collection, filter, new QueryParameters( new Type[]{null, type}, new Object[]{null, value} ) );
 	}
 
-	public Collection filter(Object collection, String filter, Object[] values, Type[] types) 
+	public Collection filter(Object collection, String filter, Object[] values, Type[] types)
 	throws HibernateException {
 		Object[] vals = new Object[values.length + 1];
 		Type[] typs = new Type[types.length + 1];
@@ -1491,7 +1426,7 @@
 		return plan;
 	}
 
-	public List listFilter(Object collection, String filter, QueryParameters queryParameters) 
+	public List listFilter(Object collection, String filter, QueryParameters queryParameters)
 	throws HibernateException {
 		errorIfClosed();
 		checkTransactionSynchStatus();
@@ -1511,7 +1446,7 @@
 		return results;
 	}
 
-	public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) 
+	public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters)
 	throws HibernateException {
 		errorIfClosed();
 		checkTransactionSynchStatus();
@@ -1552,7 +1487,7 @@
 				factory,
 				criteria,
 				entityName,
-				getEnabledFilters()
+				getLoadQueryInfluencers()
 		);
 		autoFlushIfRequired( loader.getQuerySpaces() );
 		dontFlushFromFind++;
@@ -1579,7 +1514,7 @@
 					factory,
 					criteria,
 					implementors[i],
-					getEnabledFilters()
+					getLoadQueryInfluencers()
 				);
 
 			spaces.addAll( loaders[i].getQuerySpaces() );
@@ -1680,7 +1615,7 @@
 		);
 	}
 
-	public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
+	public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
 	throws HibernateException {
 		errorIfClosed();
 		checkTransactionSynchStatus();
@@ -1734,7 +1669,7 @@
 		return factory;
 	}
 	
-	public void initializeCollection(PersistentCollection collection, boolean writing) 
+	public void initializeCollection(PersistentCollection collection, boolean writing)
 	throws HibernateException {
 		errorIfClosed();
 		checkTransactionSynchStatus();
@@ -1882,23 +1817,107 @@
 		// nothing to do in a stateful session
 	}
 
-	public String getFetchProfile() {
+	public JDBCContext getJDBCContext() {
+		errorIfClosed();
 		checkTransactionSynchStatus();
-		return fetchProfile;
+		return jdbcContext;
 	}
 
-	public JDBCContext getJDBCContext() {
+	public LoadQueryInfluencers getLoadQueryInfluencers() {
+		return loadQueryInfluencers;
+	}
+
+	// filter support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Filter getEnabledFilter(String filterName) {
+		checkTransactionSynchStatus();
+		return loadQueryInfluencers.getEnabledFilter( filterName );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Filter enableFilter(String filterName) {
 		errorIfClosed();
 		checkTransactionSynchStatus();
-		return jdbcContext;
+		return loadQueryInfluencers.enableFilter( filterName );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
+	public void disableFilter(String filterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		loadQueryInfluencers.disableFilter( filterName );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object getFilterParameterValue(String filterParameterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return loadQueryInfluencers.getFilterParameterValue( filterParameterName );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Type getFilterParameterType(String filterParameterName) {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return loadQueryInfluencers.getFilterParameterType( filterParameterName );
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Map getEnabledFilters() {
+		errorIfClosed();
+		checkTransactionSynchStatus();
+		return loadQueryInfluencers.getEnabledFilters();
+	}
+
+
+	// internal fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String getFetchProfile() {
+		checkTransactionSynchStatus();
+		return loadQueryInfluencers.getInternalFetchProfile();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
 	public void setFetchProfile(String fetchProfile) {
 		errorIfClosed();
 		checkTransactionSynchStatus();
-		this.fetchProfile = fetchProfile;
+		loadQueryInfluencers.setInternalFetchProfile( fetchProfile );
 	}
 
+
+	// fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public boolean isFetchProfileEnabled(String name) throws UnknownProfileException {
+		return loadQueryInfluencers.isFetchProfileEnabled( name );
+	}
+
+	public void enableFetchProfile(String name) throws UnknownProfileException {
+		loadQueryInfluencers.enableFetchProfile( name );
+	}
+
+	public void disableFetchProfile(String name) throws UnknownProfileException {
+		loadQueryInfluencers.disableFetchProfile( name );
+	}
+
+
 	private void checkTransactionSynchStatus() {
 		if ( jdbcContext != null && !isClosed() ) {
 			jdbcContext.registerSynchronizationIfPossible();
@@ -1923,7 +1942,6 @@
 		cacheMode = CacheMode.parse( ( String ) ois.readObject() );
 		flushBeforeCompletionEnabled = ois.readBoolean();
 		autoCloseSessionEnabled = ois.readBoolean();
-		fetchProfile = ( String ) ois.readObject();
 		interceptor = ( Interceptor ) ois.readObject();
 
 		factory = SessionFactoryImpl.deserialize( ois );
@@ -1936,12 +1954,13 @@
 		persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
 		actionQueue = ActionQueue.deserialize( ois, this );
 
-		enabledFilters = ( Map ) ois.readObject();
+		loadQueryInfluencers = ( LoadQueryInfluencers ) ois.readObject();
+
 		childSessionsByEntityMode = ( Map ) ois.readObject();
 
-		Iterator iter = enabledFilters.values().iterator();
+		Iterator iter = loadQueryInfluencers.getEnabledFilters().values().iterator();
 		while ( iter.hasNext() ) {
-			( ( FilterImpl ) iter.next() ).afterDeserialize(factory);
+			( ( FilterImpl ) iter.next() ).afterDeserialize( factory );
 		}
 
 		if ( isRootSession && childSessionsByEntityMode != null ) {
@@ -1975,7 +1994,6 @@
 		oos.writeObject( cacheMode.toString() );
 		oos.writeBoolean( flushBeforeCompletionEnabled );
 		oos.writeBoolean( autoCloseSessionEnabled );
-		oos.writeObject( fetchProfile );
 		// we need to writeObject() on this since interceptor is user defined
 		oos.writeObject( interceptor );
 
@@ -1989,7 +2007,7 @@
 		actionQueue.serialize( oos );
 
 		// todo : look at optimizing these...
-		oos.writeObject( enabledFilters );
+		oos.writeObject( loadQueryInfluencers );
 		oos.writeObject( childSessionsByEntityMode );
 	}
 }

Modified: core/trunk/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/impl/StatelessSessionImpl.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -57,6 +57,7 @@
 import org.hibernate.engine.QueryParameters;
 import org.hibernate.engine.StatefulPersistenceContext;
 import org.hibernate.engine.Versioning;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.engine.query.HQLQueryPlan;
 import org.hibernate.engine.query.NativeSQLQueryPlan;
 import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
@@ -527,12 +528,12 @@
 		errorIfClosed();
 		String entityName = criteria.getEntityOrClassName();
 		CriteriaLoader loader = new CriteriaLoader(
-				getOuterJoinLoadable(entityName),
+				getOuterJoinLoadable( entityName ),
 		        factory,
 		        criteria,
 		        entityName,
-		        getEnabledFilters()
-			);
+		        getLoadQueryInfluencers()
+		);
 		return loader.scroll(this, scrollMode);
 	}
 
@@ -548,7 +549,7 @@
 			        factory,
 			        criteria,
 			        implementors[i],
-			        getEnabledFilters()
+			        getLoadQueryInfluencers()
 			);
 		}
 
@@ -623,6 +624,10 @@
 		return jdbcContext;
 	}
 
+	public LoadQueryInfluencers getLoadQueryInfluencers() {
+		return null;
+	}
+
 	public void setFetchProfile(String name) {}
 
 	public void afterTransactionBegin(Transaction tx) {}

Modified: core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -26,13 +26,16 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
+import java.util.Iterator;
 
 import org.hibernate.FetchMode;
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
+import org.hibernate.engine.profile.FetchProfile;
+import org.hibernate.engine.profile.Fetch;
 import org.hibernate.persister.entity.Loadable;
 import org.hibernate.persister.entity.OuterJoinLoadable;
 import org.hibernate.sql.JoinFragment;
@@ -51,55 +54,60 @@
 	private final OuterJoinLoadable persister;
 	private final String alias;
 
-	public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters) {
-		this( persister, factory, enabledFilters, null );
+	public AbstractEntityJoinWalker(
+			OuterJoinLoadable persister,
+			SessionFactoryImplementor factory,
+			LoadQueryInfluencers loadQueryInfluencers) {
+		this( persister, factory, loadQueryInfluencers, null );
 	}
 
-	public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters, String alias) {
-		super( factory, enabledFilters );
+	public AbstractEntityJoinWalker(
+			OuterJoinLoadable persister,
+			SessionFactoryImplementor factory,
+			LoadQueryInfluencers loadQueryInfluencers,
+			String alias) {
+		super( factory, loadQueryInfluencers );
 		this.persister = persister;
 		this.alias = ( alias == null ) ? generateRootAlias( persister.getEntityName() ) : alias;
 	}
 
 	protected final void initAll(
-		final String whereString,
-		final String orderByString,
-		final LockMode lockMode)
-	throws MappingException {
+			final String whereString,
+			final String orderByString,
+			final LockMode lockMode) throws MappingException {
 		walkEntityTree( persister, getAlias() );
 		List allAssociations = new ArrayList();
 		allAssociations.addAll(associations);
-		allAssociations.add( new OuterJoinableAssociation(
-				persister.getEntityType(),
-				null,
-				null,
-				alias,
-				JoinFragment.LEFT_OUTER_JOIN,
-				getFactory(),
-				CollectionHelper.EMPTY_MAP
-			) );
-
+		allAssociations.add(
+				new OuterJoinableAssociation(
+						persister.getEntityType(),
+						null,
+						null,
+						alias,
+						JoinFragment.LEFT_OUTER_JOIN,
+						getFactory(),
+						CollectionHelper.EMPTY_MAP
+				)
+		);
 		initPersisters(allAssociations, lockMode);
 		initStatementString( whereString, orderByString, lockMode);
 	}
 
 	protected final void initProjection(
-		final String projectionString,
-		final String whereString,
-		final String orderByString,
-		final String groupByString,
-		final LockMode lockMode)
-	throws MappingException {
+			final String projectionString,
+			final String whereString,
+			final String orderByString,
+			final String groupByString,
+			final LockMode lockMode) throws MappingException {
 		walkEntityTree( persister, getAlias() );
 		persisters = new Loadable[0];
 		initStatementString(projectionString, whereString, orderByString, groupByString, lockMode);
 	}
 
 	private void initStatementString(
-		final String condition,
-		final String orderBy,
-		final LockMode lockMode)
-	throws MappingException {
+			final String condition,
+			final String orderBy,
+			final LockMode lockMode) throws MappingException {
 		initStatementString(null, condition, orderBy, "", lockMode);
 	}
 
@@ -149,9 +157,35 @@
 	 * The superclass deliberately excludes collections
 	 */
 	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
-		return isJoinedFetchEnabledInMapping(config, type);
+		return isJoinedFetchEnabledInMapping( config, type );
 	}
 
+	protected final boolean isJoinFetchEnabledByProfile(OuterJoinLoadable persister, String path, int propertyNumber) {
+		if ( !getLoadQueryInfluencers().hasEnabledFetchProfiles() ) {
+			// perf optimization
+			return false;
+		}
+
+		// ugh, this stuff has to be made easier...
+		String rootPropertyName = persister.getSubclassPropertyName( propertyNumber );
+		int pos = path.lastIndexOf( rootPropertyName );
+		String relativePropertyPath = pos >= 0
+				? path.substring( pos )
+				: rootPropertyName;
+		String fetchRole = persister.getEntityName() + "." + relativePropertyPath;
+
+		Iterator profiles = getLoadQueryInfluencers().getEnabledFetchProfileNames().iterator();
+		while ( profiles.hasNext() ) {
+			final String profileName = ( String ) profiles.next();
+			final FetchProfile profile = getFactory().getFetchProfile( profileName );
+			final Fetch fetch = profile.getFetchByRole( fetchRole );
+			if ( fetch != null && Fetch.Style.JOIN == fetch.getStyle() ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	public abstract String getComment();
 
 	protected final Loadable getPersister() {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/JoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/JoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/JoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -29,7 +29,6 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.hibernate.FetchMode;
@@ -39,6 +38,9 @@
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.JoinHelper;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
+import org.hibernate.engine.profile.FetchProfile;
+import org.hibernate.engine.profile.Fetch;
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.collection.QueryableCollection;
 import org.hibernate.persister.entity.EntityPersister;
@@ -69,7 +71,7 @@
 	private final SessionFactoryImplementor factory;
 	protected final List associations = new ArrayList();
 	private final Set visitedAssociationKeys = new HashSet();
-	private final Map enabledFilters;
+	private final LoadQueryInfluencers loadQueryInfluencers;
 
 	protected String[] suffixes;
 	protected String[] collectionSuffixes;
@@ -81,6 +83,14 @@
 	protected String[] aliases;
 	protected LockMode[] lockModeArray;
 	protected String sql;
+
+	protected JoinWalker(
+			SessionFactoryImplementor factory,
+			LoadQueryInfluencers loadQueryInfluencers) {
+		this.factory = factory;
+		this.loadQueryInfluencers = loadQueryInfluencers;
+
+	}
 	
 	public String[] getCollectionSuffixes() {
 		return collectionSuffixes;
@@ -169,14 +179,9 @@
 	protected Dialect getDialect() {
 		return factory.getDialect();
 	}
-	
-	protected Map getEnabledFilters() {
-		return enabledFilters;
-	}
 
-	protected JoinWalker(SessionFactoryImplementor factory, Map enabledFilters) {
-		this.factory = factory;
-		this.enabledFilters = enabledFilters;
+	public LoadQueryInfluencers getLoadQueryInfluencers() {
+		return loadQueryInfluencers;
 	}
 
 	/**
@@ -184,15 +189,13 @@
 	 * 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) {	
+			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, 
@@ -200,9 +203,8 @@
 					path,
 					currentDepth,
 					joinType
-				);
+			);
 		}
-
 	}
 
 	/**
@@ -210,35 +212,37 @@
 	 * 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 {
+			final AssociationType type,
+			final String[] aliasedLhsColumns,
+			final String alias,
+			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
-			);
+		// important to generate alias based on size of association collection
+		// *before* adding this join to that collection
+		String subalias = generateTableAlias( associations.size() + 1, path, joinable );
 
+		// NOTE : it should be fine to continue to pass only filters below
+		// (instead of LoadQueryInfluencers) since "from that point on" we
+		// only need to worry about restrictions (and not say adding more
+		// joins)
 		OuterJoinableAssociation assoc = new OuterJoinableAssociation(
 				type, 
 				alias, 
 				aliasedLhsColumns, 
 				subalias, 
 				joinType, 
-				getFactory(), 
-				enabledFilters
-			);
-		assoc.validateJoin(path);
-		associations.add(assoc);
+				getFactory(),
+				loadQueryInfluencers.getEnabledFilters()
+		);
+		assoc.validateJoin( path );
+		associations.add( assoc );
 
-		int nextDepth = currentDepth+1;
+		int nextDepth = currentDepth + 1;
+//		path = "";
 		if ( !joinable.isCollection() ) {
 			if (joinable instanceof OuterJoinLoadable) {
 				walkEntityTree(
@@ -263,11 +267,19 @@
 	}
 
 	/**
-	 * For an entity class, return a list of associations to be fetched by outerjoin
+	 * Walk the association tree for an entity, adding associations which should
+	 * be join fetched to the {@link #associations} inst var.  This form is the
+	 * entry point into the walking for a given entity, starting the recursive
+	 * calls into {@link #walkEntityTree(OuterJoinLoadable, String, String, int)}.
+	 *
+	 * @param persister The persister representing the entity to be walked.
+	 * @param alias The (root) alias to use for this entity/persister.
+	 * @throws org.hibernate.MappingException ???
 	 */
-	protected final void walkEntityTree(OuterJoinLoadable persister, String alias)
-	throws MappingException {
-		walkEntityTree(persister, alias, "", 0);
+	protected final void walkEntityTree(
+			OuterJoinLoadable persister,
+			String alias) throws MappingException {
+		walkEntityTree( persister, alias, "", 0 );
 	}
 
 	/**
@@ -344,38 +356,49 @@
 	}
 	
 	/**
-	 * Walk the tree for a particular entity association
+	 * Process a particular association owned by the entity
+	 *
+	 * @param associationType The type representing the association to be
+	 * processed.
+	 * @param persister The owner of the association to be processed.
+	 * @param propertyNumber The property number for the association
+	 * (relative to the persister).
+	 * @param alias The entity alias
+	 * @param path The path to the association
+	 * @param nullable is the association nullable (which I think is supposed
+	 * to indicate inner/outer join semantics).
+	 * @param currentDepth The current join depth
+	 * @throws org.hibernate.MappingException ???
 	 */
-	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 {
-
+	private 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(
+				persister,
+				subpath,
+				propertyNumber,
 				associationType,
-				persister.getFetchMode(propertyNumber),
-				subpath,
+				persister.getFetchMode( propertyNumber ),
+				persister.getCascadeStyle( propertyNumber ),
 				lhsTable,
 				lhsColumns,
 				nullable,
-				currentDepth, 
-				persister.getCascadeStyle(propertyNumber)
-			);
+				currentDepth
+		);
 		addAssociationToJoinTreeIfNecessary(
 				associationType,
 				aliasedLhsColumns,
@@ -383,27 +406,110 @@
 				subpath,
 				currentDepth,
 				joinType
-			);
+		);
+	}
 
+	/**
+	 * Determine the appropriate type of join (if any) to use to fetch the
+	 * given association.
+	 *
+	 * @param persister The owner of the association.
+	 * @param path The path to the association
+	 * @param propertyNumber The property number representing the association.
+	 * @param associationType The association type.
+	 * @param metadataFetchMode The metadata-defined fetch mode.
+	 * @param metadataCascadeStyle The metadata-defined cascade style.
+	 * @param lhsTable The owner table
+	 * @param lhsColumns The owner join columns
+	 * @param nullable Is the association nullable.
+	 * @param currentDepth Current join depth
+	 * @return type of join to use ({@link JoinFragment#INNER_JOIN},
+	 * {@link JoinFragment#LEFT_OUTER_JOIN}, or -1 to indicate no joining.
+	 * @throws MappingException ??
+	 */
+	protected int getJoinType(
+			OuterJoinLoadable persister,
+			final String path,
+			int propertyNumber,
+			AssociationType associationType,
+			FetchMode metadataFetchMode,
+			CascadeStyle metadataCascadeStyle,
+			String lhsTable,
+			String[] lhsColumns,
+			final boolean nullable,
+			final int currentDepth) throws MappingException {
+		return getJoinType(
+				associationType,
+				metadataFetchMode,
+				path,
+				lhsTable,
+				lhsColumns,
+				nullable,
+				currentDepth,
+				metadataCascadeStyle
+		);
 	}
 
 	/**
-	 * For an entity class, add to a list of associations to be fetched 
-	 * by outerjoin
+	 * Determine the appropriate associationType of join (if any) to use to fetch the
+	 * given association.
+	 *
+	 * @param associationType The association associationType.
+	 * @param config The metadata-defined fetch mode.
+	 * @param path The path to the association
+	 * @param lhsTable The owner table
+	 * @param lhsColumns The owner join columns
+	 * @param nullable Is the association nullable.
+	 * @param currentDepth Current join depth
+	 * @param cascadeStyle The metadata-defined cascade style.
+	 * @return type of join to use ({@link JoinFragment#INNER_JOIN},
+	 * {@link JoinFragment#LEFT_OUTER_JOIN}, or -1 to indicate no joining.
+	 * @throws MappingException ??
 	 */
-	private final void walkEntityTree(
-		final OuterJoinLoadable persister,
-		final String alias,
-		final String path,
-		final int currentDepth) 
-	throws MappingException {
+	private int getJoinType(
+			AssociationType associationType,
+			FetchMode config,
+			String path,
+			String lhsTable,
+			String[] lhsColumns,
+			boolean nullable,
+			int currentDepth,
+			CascadeStyle cascadeStyle) throws MappingException {
+		if  ( !isJoinedFetchEnabled( associationType, config, cascadeStyle ) ) {
+			return -1;
+		}
+		if ( isTooDeep(currentDepth) || ( associationType.isCollectionType() && isTooManyCollections() ) ) {
+			return -1;
+		}
+		if ( isDuplicateAssociation( lhsTable, lhsColumns, associationType ) ) {
+			return -1;
+		}
+		return getJoinType( nullable, currentDepth );
+	}
 
+	/**
+	 * Walk the association tree for an entity, adding associations which should
+	 * be join fetched to the {@link #associations} inst var.  This form is the
+	 * entry point into the walking for a given entity, starting the recursive
+	 * calls into {@link #walkEntityTree(OuterJoinLoadable, String, String, int)}.
+	 *
+	 * @param persister The persister representing the entity to be walked.
+	 * @param alias The (root) alias to use for this entity/persister.
+	 * @param path todo this seems to be rooted at the *root* persister
+	 * @param currentDepth The current join depth
+	 * @throws org.hibernate.MappingException ???
+	 */
+	private 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++ ) {
+		for ( int i = 0; i < n; i++ ) {
 			Type type = persister.getSubclassPropertyType(i);
 			if ( type.isAssociationType() ) {
 				walkEntityAssociationTree(
-					(AssociationType) type,
+					( AssociationType ) type,
 					persister,
 					i,
 					alias,
@@ -414,7 +520,7 @@
 			}
 			else if ( type.isComponentType() ) {
 				walkComponentTree(
-					(AbstractComponentType) type,
+					( AbstractComponentType ) type,
 					i,
 					0,
 					persister,
@@ -428,28 +534,34 @@
 
 	/**
 	 * For a component, add to a list of associations to be fetched by outerjoin
+	 *
+	 *
+	 * @param componentType The component type to be walked.
+	 * @param propertyNumber The property number for the component property (relative to
+	 * persister).
+	 * @param begin todo unknowm
+	 * @param persister The owner of the component property
+	 * @param alias The root alias
+	 * @param path The property access path
+	 * @param currentDepth The current join depth
+	 * @throws org.hibernate.MappingException ???
 	 */
 	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 {
-
+			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++ ) {
-
+		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()
 				);
@@ -458,15 +570,17 @@
 				String subpath = subPath( path, propertyNames[i] );
 				final boolean[] propertyNullability = componentType.getPropertyNullability();
 				final int joinType = getJoinType(
+						persister,
+						subpath,
+						propertyNumber,
 						associationType,
 						componentType.getFetchMode(i),
-						subpath,
+						componentType.getCascadeStyle(i),
 						lhsTable,
 						lhsColumns,
 						propertyNullability==null || propertyNullability[i],
-						currentDepth, 
-						componentType.getCascadeStyle(i)
-					);
+						currentDepth
+				);
 				addAssociationToJoinTreeIfNecessary(			
 						associationType,
 						aliasedLhsColumns,
@@ -474,23 +588,22 @@
 						subpath,
 						currentDepth,
 						joinType
-					);
+				);
 
 			}
 			else if ( types[i].isComponentType() ) {
 				String subpath = subPath( path, propertyNames[i] );
 				walkComponentTree(
-						(AbstractComponentType) types[i],
+						( AbstractComponentType ) types[i],
 						propertyNumber,
 						begin,
 						persister,
 						alias,
 						subpath,
 						currentDepth
-					);
+				);
 			}
-			
-			begin+=types[i].getColumnSpan( getFactory() );
+			begin += types[i].getColumnSpan( getFactory() );
 		}
 
 	}
@@ -499,13 +612,12 @@
 	 * 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 {
+			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();
@@ -571,42 +683,15 @@
 	}
 
 	/**
-	 * 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) || ( type.isCollectionType() && 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;
+		return !nullable && currentDepth == 0
+				? JoinFragment.INNER_JOIN
+				: JoinFragment.LEFT_OUTER_JOIN;
 	}
 
 	protected boolean isTooDeep(int currentDepth) {
@@ -654,8 +739,7 @@
 	protected String generateTableAlias(
 			final int n,
 			final String path,
-			final Joinable joinable
-	) {
+			final Joinable joinable) {
 		return StringHelper.generateAlias( joinable.getName(), n );
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -25,10 +25,12 @@
 package org.hibernate.loader;
 
 import java.util.Map;
+import java.util.Set;
 
 import org.hibernate.LockMode;
 import org.hibernate.dialect.Dialect;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.entity.Loadable;
 import org.hibernate.type.EntityType;
@@ -54,15 +56,17 @@
 	protected String[] suffixes;
 	protected String[] collectionSuffixes;
 
-    private Map enabledFilters;
-    
-    protected final Dialect getDialect() {
+    private LoadQueryInfluencers loadQueryInfluencers;
+
+	protected final Dialect getDialect() {
     	return getFactory().getDialect();
     }
 
-	public OuterJoinLoader(SessionFactoryImplementor factory, Map enabledFilters) {
-		super(factory);
-		this.enabledFilters = enabledFilters;
+	public OuterJoinLoader(
+			SessionFactoryImplementor factory,
+			LoadQueryInfluencers loadQueryInfluencers) {
+		super( factory );
+		this.loadQueryInfluencers = loadQueryInfluencers;
 	}
 
 	protected String[] getSuffixes() {
@@ -92,9 +96,9 @@
 	protected LockMode[] getLockModes(Map lockModes) {
 		return lockModeArray;
 	}
-	
-	public Map getEnabledFilters() {
-		return enabledFilters;
+
+	public LoadQueryInfluencers getLoadQueryInfluencers() {
+		return loadQueryInfluencers;
 	}
 
 	protected final String[] getAliases() {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/OuterJoinableAssociation.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -36,6 +36,12 @@
 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
+ */
 public final class OuterJoinableAssociation {
 	private final AssociationType joinableType;
 	private final Joinable joinable;
@@ -48,14 +54,13 @@
 	private final Map enabledFilters;
 
 	public OuterJoinableAssociation(
-		AssociationType joinableType,
-		String lhsAlias,
-		String[] lhsColumns,
-		String rhsAlias,
-		int joinType,
-		SessionFactoryImplementor factory,
-		Map enabledFilters)
-	throws MappingException {
+			AssociationType joinableType,
+			String lhsAlias,
+			String[] lhsColumns,
+			String rhsAlias,
+			int joinType,
+			SessionFactoryImplementor factory,
+			Map enabledFilters) throws MappingException {
 		this.joinableType = joinableType;
 		this.lhsAlias = lhsAlias;
 		this.lhsColumns = lhsColumns;

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -34,9 +34,12 @@
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
+import org.hibernate.engine.CascadeStyle;
 import org.hibernate.loader.BasicLoader;
 import org.hibernate.loader.OuterJoinableAssociation;
 import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.OuterJoinLoadable;
 import org.hibernate.sql.JoinFragment;
 import org.hibernate.sql.Select;
 import org.hibernate.type.AssociationType;
@@ -58,10 +61,9 @@
 			int batchSize, 
 			String subquery, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
 
-		super(factory, enabledFilters);
+		super( factory, loadQueryInfluencers );
 
 		this.collectionPersister = collectionPersister;
 
@@ -71,26 +73,25 @@
 
 		List allAssociations = new ArrayList();
 		allAssociations.addAll(associations);
-		allAssociations.add( new OuterJoinableAssociation( 
-				collectionPersister.getCollectionType(),
-				null, 
-				null, 
-				alias, 
-				JoinFragment.LEFT_OUTER_JOIN, 
-				getFactory(), 
-				CollectionHelper.EMPTY_MAP 
-			) );
-
+		allAssociations.add(
+				new OuterJoinableAssociation(
+						collectionPersister.getCollectionType(),
+						null,
+						null,
+						alias,
+						JoinFragment.LEFT_OUTER_JOIN,
+						getFactory(),
+						CollectionHelper.EMPTY_MAP
+				)
+		);
 		initPersisters(allAssociations, LockMode.NONE);
 		initStatementString(alias, batchSize, subquery);
-
 	}
 
 	private void initStatementString(
 		final String alias,
 		final int batchSize,
-		final String subquery)
-	throws MappingException {
+		final String subquery) throws MappingException {
 
 		final int joins = countEntityPersisters( associations );
 		final int collectionJoins = countCollectionPersisters( associations ) + 1;
@@ -106,7 +107,7 @@
 			);
 
 		String manyToManyOrderBy = "";
-		String filter = collectionPersister.filterFragment( alias, getEnabledFilters() );
+		String filter = collectionPersister.filterFragment( alias, getLoadQueryInfluencers().getEnabledFilters() );
 		if ( collectionPersister.isManyToMany() ) {
 			// from the collection of associations, locate OJA for the
 			// ManyToOne corresponding to this persister to fully
@@ -121,9 +122,9 @@
 					// we found it
 					filter += collectionPersister.getManyToManyFilterFragment( 
 							oja.getRHSAlias(), 
-							getEnabledFilters() 
+							getLoadQueryInfluencers().getEnabledFilters() 
 						);
-						manyToManyOrderBy += collectionPersister.getManyToManyOrderByString( oja.getRHSAlias() );
+					manyToManyOrderBy += collectionPersister.getManyToManyOrderByString( oja.getRHSAlias() );
 				}
 			}
 		}
@@ -151,37 +152,36 @@
 		sql = select.toStatementString();
 	}
 
-	/**
-	 * We can use an inner join for first many-to-many association
-	 */
 	protected int getJoinType(
-			AssociationType type, 
-			FetchMode config, 
-			String path, 
-			Set visitedAssociations,
+			OuterJoinLoadable persister,
+			String path,
+			int propertyNumber,
+			AssociationType associationType,
+			FetchMode metadataFetchMode,
+			CascadeStyle metadataCascadeStyle,
 			String lhsTable,
 			String[] lhsColumns,
 			boolean nullable,
-			int currentDepth)
-	throws MappingException {
-
+			int currentDepth) throws MappingException {
 		int joinType = super.getJoinType(
-				type, 
-				config, 
-				path, 
-				lhsTable, 
-				lhsColumns, 
-				nullable, 
-				currentDepth,
-				null
-			);
+				persister,
+				path,
+				propertyNumber,
+				associationType,
+				metadataFetchMode,
+				metadataCascadeStyle,
+				lhsTable,
+				lhsColumns,
+				nullable,
+				currentDepth
+		);
 		//we can use an inner join for the many-to-many
 		if ( joinType==JoinFragment.LEFT_OUTER_JOIN && "".equals(path) ) {
 			joinType=JoinFragment.INNER_JOIN;
 		}
 		return joinType;
 	}
-	
+
 	public String toString() {
 		return getClass().getName() + '(' + collectionPersister.getRole() + ')';
 	}

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/BasicCollectionLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -24,12 +24,11 @@
  */
 package org.hibernate.loader.collection;
 
-import java.util.Map;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.JoinWalker;
 import org.hibernate.persister.collection.QueryableCollection;
 
@@ -49,18 +48,16 @@
 	public BasicCollectionLoader(
 			QueryableCollection collectionPersister, 
 			SessionFactoryImplementor session, 
-			Map enabledFilters)
-	throws MappingException {
-		this(collectionPersister, 1, session, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		this( collectionPersister, 1, session, loadQueryInfluencers );
 	}
 
 	public BasicCollectionLoader(
 			QueryableCollection collectionPersister, 
 			int batchSize, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
-		this(collectionPersister, batchSize, null, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		this( collectionPersister, batchSize, null, factory, loadQueryInfluencers );
 	}
 	
 	protected BasicCollectionLoader(
@@ -68,18 +65,16 @@
 			int batchSize, 
 			String subquery, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( collectionPersister, factory, loadQueryInfluencers );
 		
-		super(collectionPersister, factory, enabledFilters);
-		
 		JoinWalker walker = new BasicCollectionJoinWalker(
 				collectionPersister, 
 				batchSize, 
 				subquery, 
 				factory, 
-				enabledFilters
-			);
+				loadQueryInfluencers
+		);
 		initFromWalker( walker );
 
 		postInstantiate();

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/BatchingCollectionInitializer.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -31,6 +31,7 @@
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.Loader;
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.collection.QueryableCollection;
@@ -77,42 +78,38 @@
 	}
 
 	public static CollectionInitializer createBatchingOneToManyInitializer(
-		final QueryableCollection persister,
-		final int maxBatchSize,
-		final SessionFactoryImplementor factory,
-		final Map enabledFilters)
-	throws MappingException {
-
-		if ( maxBatchSize>1 ) {
+			final QueryableCollection persister,
+			final int maxBatchSize,
+			final SessionFactoryImplementor factory,
+			final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		if ( maxBatchSize > 1 ) {
 			int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
 			Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
 			for ( int i=0; i<batchSizesToCreate.length; i++ ) {
-				loadersToCreate[i] = new OneToManyLoader(persister, batchSizesToCreate[i], factory, enabledFilters);
+				loadersToCreate[i] = new OneToManyLoader( persister, batchSizesToCreate[i], factory, loadQueryInfluencers );
 			}
-			return new BatchingCollectionInitializer(persister, batchSizesToCreate, loadersToCreate);
+			return new BatchingCollectionInitializer( persister, batchSizesToCreate, loadersToCreate );
 		}
 		else {
-			return new OneToManyLoader(persister, factory, enabledFilters);
+			return new OneToManyLoader( persister, factory, loadQueryInfluencers );
 		}
 	}
 
 	public static CollectionInitializer createBatchingCollectionInitializer(
-		final QueryableCollection persister,
-		final int maxBatchSize,
-		final SessionFactoryImplementor factory,
-		final Map enabledFilters)
-	throws MappingException {
-
-		if ( maxBatchSize>1 ) {
+			final QueryableCollection persister,
+			final int maxBatchSize,
+			final SessionFactoryImplementor factory,
+			final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		if ( maxBatchSize > 1 ) {
 			int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
 			Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
 			for ( int i=0; i<batchSizesToCreate.length; i++ ) {
-				loadersToCreate[i] = new BasicCollectionLoader(persister, batchSizesToCreate[i], factory, enabledFilters);
+				loadersToCreate[i] = new BasicCollectionLoader( persister, batchSizesToCreate[i], factory, loadQueryInfluencers );
 			}
 			return new BatchingCollectionInitializer(persister, batchSizesToCreate, loadersToCreate);
 		}
 		else {
-			return new BasicCollectionLoader(persister, factory, enabledFilters);
+			return new BasicCollectionLoader( persister, factory, loadQueryInfluencers );
 		}
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -24,9 +24,8 @@
  */
 package org.hibernate.loader.collection;
 
-import java.util.Map;
-
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.JoinWalker;
 import org.hibernate.util.StringHelper;
 
@@ -40,8 +39,8 @@
  */
 public abstract class CollectionJoinWalker extends JoinWalker {
 	
-	public CollectionJoinWalker(SessionFactoryImplementor factory, Map enabledFilters) {
-		super( factory, enabledFilters );
+	public CollectionJoinWalker(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) {
+		super( factory, loadQueryInfluencers );
 	}
 
 	protected StringBuffer whereString(String alias, String[] columnNames, String subselect, int batchSize) {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/CollectionLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -25,11 +25,11 @@
 package org.hibernate.loader.collection;
 
 import java.io.Serializable;
-import java.util.Map;
 
 import org.hibernate.HibernateException;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.OuterJoinLoader;
 import org.hibernate.persister.collection.QueryableCollection;
 import org.hibernate.type.Type;
@@ -45,8 +45,11 @@
 
 	private final QueryableCollection collectionPersister;
 
-	public CollectionLoader(QueryableCollection collectionPersister, SessionFactoryImplementor factory, Map enabledFilters) {
-		super( factory, enabledFilters );
+	public CollectionLoader(
+			QueryableCollection collectionPersister,
+			SessionFactoryImplementor factory,
+			LoadQueryInfluencers loadQueryInfluencers) {
+		super( factory, loadQueryInfluencers );
 		this.collectionPersister = collectionPersister;
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -27,11 +27,11 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.BasicLoader;
 import org.hibernate.loader.OuterJoinableAssociation;
 import org.hibernate.persister.collection.QueryableCollection;
@@ -67,11 +67,9 @@
 			int batchSize, 
 			String subquery, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( factory, loadQueryInfluencers );
 
-		super(factory, enabledFilters);
-
 		this.oneToManyPersister = oneToManyPersister;
 
 		final OuterJoinLoadable elementPersister = (OuterJoinLoadable) oneToManyPersister.getElementPersister();
@@ -93,7 +91,6 @@
 		
 		initPersisters(allAssociations, LockMode.NONE);
 		initStatementString(elementPersister, alias, batchSize, subquery);
-
 	}
 
 	private void initStatementString(
@@ -115,7 +112,7 @@
 				subquery,
 				batchSize
 			);
-		String filter = oneToManyPersister.filterFragment( alias, getEnabledFilters() );
+		String filter = oneToManyPersister.filterFragment( alias, getLoadQueryInfluencers().getEnabledFilters() );
 		whereString.insert( 0, StringHelper.moveAndToBeginning(filter) );
 
 		JoinFragment ojf = mergeOuterJoins(associations);

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/OneToManyLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -24,12 +24,11 @@
  */
 package org.hibernate.loader.collection;
 
-import java.util.Map;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.JoinWalker;
 import org.hibernate.persister.collection.QueryableCollection;
 
@@ -49,18 +48,16 @@
 	public OneToManyLoader(
 			QueryableCollection oneToManyPersister, 
 			SessionFactoryImplementor session, 
-			Map enabledFilters)
-	throws MappingException {
-		this(oneToManyPersister, 1, session, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		this( oneToManyPersister, 1, session, loadQueryInfluencers );
 	}
 
 	public OneToManyLoader(
 			QueryableCollection oneToManyPersister, 
 			int batchSize, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
-		this(oneToManyPersister, batchSize, null, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		this( oneToManyPersister, batchSize, null, factory, loadQueryInfluencers );
 	}
 
 	public OneToManyLoader(
@@ -68,22 +65,19 @@
 			int batchSize, 
 			String subquery, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
-
-		super(oneToManyPersister, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( oneToManyPersister, factory, loadQueryInfluencers );
 		
 		JoinWalker walker = new OneToManyJoinWalker(
 				oneToManyPersister, 
 				batchSize, 
 				subquery, 
 				factory, 
-				enabledFilters
-			);
+				loadQueryInfluencers
+		);
 		initFromWalker( walker );
 
 		postInstantiate();
-
 		log.debug( "Static select for one-to-many " + oneToManyPersister.getRole() + ": " + getSQLString() );
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectCollectionLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -35,6 +35,7 @@
 import org.hibernate.engine.QueryParameters;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.persister.collection.QueryableCollection;
 import org.hibernate.type.Type;
 
@@ -57,10 +58,8 @@
 			QueryParameters queryParameters,
 			Map namedParameterLocMap,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
-		
-		super(persister, 1, subquery, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( persister, 1, subquery, factory, loadQueryInfluencers );
 
 		keys = new Serializable[ entityKeys.size() ];
 		Iterator iter = entityKeys.iterator();
@@ -77,7 +76,7 @@
 	}
 
 	public void initialize(Serializable id, SessionImplementor session)
-	throws HibernateException {
+			throws HibernateException {
 		loadCollectionSubselect( 
 				session, 
 				keys, 
@@ -85,7 +84,7 @@
 				types,
 				namedParameters,
 				getKeyType() 
-			);
+		);
 	}
 
 	public int[] getNamedParameterLocs(String name) {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/collection/SubselectOneToManyLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -35,6 +35,7 @@
 import org.hibernate.engine.QueryParameters;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.persister.collection.QueryableCollection;
 import org.hibernate.type.Type;
 
@@ -57,10 +58,8 @@
 			QueryParameters queryParameters,
 			Map namedParameterLocMap,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters)
-	throws MappingException {
-		
-		super(persister, 1, subquery, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( persister, 1, subquery, factory, loadQueryInfluencers );
 
 		keys = new Serializable[ entityKeys.size() ];
 		Iterator iter = entityKeys.iterator();
@@ -73,11 +72,9 @@
 		this.types = queryParameters.getFilteredPositionalParameterTypes();
 		this.values = queryParameters.getFilteredPositionalParameterValues();
 		this.namedParameterLocMap = namedParameterLocMap;
-		
 	}
 
-	public void initialize(Serializable id, SessionImplementor session)
-	throws HibernateException {
+	public void initialize(Serializable id, SessionImplementor session) throws HibernateException {
 		loadCollectionSubselect( 
 				session, 
 				keys, 
@@ -85,7 +82,7 @@
 				types,
 				namedParameters,
 				getKeyType() 
-			);
+		);
 	}
 
 	public int[] getNamedParameterLocs(String name) {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -26,7 +26,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import org.hibernate.Criteria;
@@ -35,6 +34,7 @@
 import org.hibernate.MappingException;
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.impl.CriteriaImpl;
 import org.hibernate.loader.AbstractEntityJoinWalker;
 import org.hibernate.persister.entity.Joinable;
@@ -78,8 +78,8 @@
 			final SessionFactoryImplementor factory, 
 			final CriteriaImpl criteria, 
 			final String rootEntityName,
-			final Map enabledFilters) {
-		this(persister, translator, factory, criteria, rootEntityName, enabledFilters, null);
+			final LoadQueryInfluencers loadQueryInfluencers) {
+		this( persister, translator, factory, criteria, rootEntityName, loadQueryInfluencers, null );
 	}
 
 	public CriteriaJoinWalker(
@@ -88,9 +88,9 @@
 			final SessionFactoryImplementor factory,
 			final CriteriaImpl criteria,
 			final String rootEntityName,
-			final Map enabledFilters,
+			final LoadQueryInfluencers loadQueryInfluencers,
 			final String alias) {
-		super(persister, factory, enabledFilters, alias);
+		super( persister, factory, loadQueryInfluencers, alias );
 
 		this.translator = translator;
 
@@ -119,16 +119,17 @@
 	}
 
 	protected int getJoinType(
-			AssociationType type, 
-			FetchMode config, 
-			String path,
+			OuterJoinLoadable persister,
+			final String path,
+			int propertyNumber,
+			AssociationType associationType,
+			FetchMode metadataFetchMode,
+			CascadeStyle metadataCascadeStyle,
 			String lhsTable,
 			String[] lhsColumns,
-			boolean nullable,
-			int currentDepth, CascadeStyle cascadeStyle)
-	throws MappingException {
-
-		if ( translator.isJoin(path) ) {
+			final boolean nullable,
+			final int currentDepth) throws MappingException {
+		if ( translator.isJoin( path ) ) {
 			return translator.getJoinType( path );
 		}
 		else {
@@ -136,23 +137,30 @@
 				return -1;
 			}
 			else {
-				FetchMode fetchMode = translator.getRootCriteria()
-					.getFetchMode(path);
-				if ( isDefaultFetchMode(fetchMode) ) {
-					return super.getJoinType(
-							type, 
-							config, 
-							path, 
-							lhsTable, 
-							lhsColumns, 
-							nullable,
-							currentDepth, cascadeStyle
+				FetchMode fetchMode = translator.getRootCriteria().getFetchMode( path );
+				if ( isDefaultFetchMode( fetchMode ) ) {
+					if ( isJoinFetchEnabledByProfile( persister, path, propertyNumber ) ) {
+						return getJoinType( nullable, currentDepth );
+					}
+					else {
+						return super.getJoinType(
+								persister,
+								path,
+								propertyNumber,
+								associationType,
+								metadataFetchMode,
+								metadataCascadeStyle,
+								lhsTable,
+								lhsColumns,
+								nullable,
+								currentDepth
 						);
+					}
 				}
 				else {
-					if ( fetchMode==FetchMode.JOIN ) {
-						isDuplicateAssociation(lhsTable, lhsColumns, type); //deliberately ignore return value!
-						return getJoinType(nullable, currentDepth);
+					if ( fetchMode == FetchMode.JOIN ) {
+						isDuplicateAssociation( lhsTable, lhsColumns, associationType ); //deliberately ignore return value!
+						return getJoinType( nullable, currentDepth );
 					}
 					else {
 						return -1;
@@ -172,7 +180,7 @@
 	 */
 	protected String getWhereFragment() throws MappingException {
 		return super.getWhereFragment() +
-			( (Queryable) getPersister() ).filterFragment( getAlias(), getEnabledFilters() );
+			( (Queryable) getPersister() ).filterFragment( getAlias(), getLoadQueryInfluencers().getEnabledFilters() );
 	}
 	
 	protected String generateTableAlias(int n, String path, Joinable joinable) {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -30,7 +30,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Iterator;
 
 import org.hibernate.HibernateException;
 import org.hibernate.LockMode;
@@ -41,6 +40,7 @@
 import org.hibernate.engine.QueryParameters;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.impl.CriteriaImpl;
 import org.hibernate.loader.OuterJoinLoader;
 import org.hibernate.persister.entity.OuterJoinLoadable;
@@ -75,9 +75,8 @@
 			final SessionFactoryImplementor factory, 
 			final CriteriaImpl criteria, 
 			final String rootEntityName,
-			final Map enabledFilters)
-	throws HibernateException {
-		super(factory, enabledFilters);
+			final LoadQueryInfluencers loadQueryInfluencers) throws HibernateException {
+		super( factory, loadQueryInfluencers );
 
 		translator = new CriteriaQueryTranslator(
 				factory, 
@@ -94,7 +93,7 @@
 				factory, 
 				criteria, 
 				rootEntityName, 
-				enabledFilters
+				loadQueryInfluencers
 			);
 
 		initFromWalker(walker);

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -29,12 +29,14 @@
 import java.sql.SQLException;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.hibernate.HibernateException;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.OuterJoinLoader;
 import org.hibernate.persister.entity.OuterJoinLoadable;
 import org.hibernate.transform.ResultTransformer;
@@ -52,8 +54,8 @@
 			OuterJoinLoadable persister, 
 			Type uniqueKeyType, 
 			SessionFactoryImplementor factory, 
-			Map enabledFilters) {
-		super( factory, enabledFilters );
+			LoadQueryInfluencers loadQueryInfluencers) {
+		super( factory, loadQueryInfluencers );
 		this.uniqueKeyType = uniqueKeyType;
 		this.entityName = persister.getEntityName();
 		this.persister = persister;

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/BatchingEntityLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -28,12 +28,14 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.hibernate.HibernateException;
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.Loader;
 import org.hibernate.persister.entity.EntityPersister;
 import org.hibernate.persister.entity.OuterJoinLoadable;
@@ -111,19 +113,18 @@
 		final int maxBatchSize,
 		final LockMode lockMode,
 		final SessionFactoryImplementor factory,
-		final Map enabledFilters)
-	throws MappingException {
+		final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
 
 		if ( maxBatchSize>1 ) {
 			int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
 			Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
 			for ( int i=0; i<batchSizesToCreate.length; i++ ) {
-				loadersToCreate[i] = new EntityLoader(persister, batchSizesToCreate[i], lockMode, factory, enabledFilters);
+				loadersToCreate[i] = new EntityLoader(persister, batchSizesToCreate[i], lockMode, factory, loadQueryInfluencers);
 			}
 			return new BatchingEntityLoader(persister, batchSizesToCreate, loadersToCreate);
 		}
 		else {
-			return new EntityLoader(persister, lockMode, factory, enabledFilters);
+			return new EntityLoader(persister, lockMode, factory, loadQueryInfluencers);
 		}
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -30,6 +30,7 @@
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.CascadingAction;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.AbstractEntityJoinWalker;
 import org.hibernate.persister.entity.OuterJoinLoadable;
 import org.hibernate.type.AssociationType;
@@ -41,7 +42,7 @@
 
 	public CascadeEntityJoinWalker(OuterJoinLoadable persister, CascadingAction action, SessionFactoryImplementor factory) 
 	throws MappingException {
-		super( persister, factory, CollectionHelper.EMPTY_MAP );
+		super( persister, factory, LoadQueryInfluencers.NONE );
 		this.cascadeAction = action;
 		StringBuffer whereCondition = whereString( getAlias(), persister.getIdentifierColumnNames(), 1 )
 				//include the discriminator and class-level where, but not filters

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/CascadeEntityLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -27,29 +27,28 @@
 import org.hibernate.MappingException;
 import org.hibernate.engine.CascadingAction;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.JoinWalker;
 import org.hibernate.persister.entity.OuterJoinLoadable;
-import org.hibernate.util.CollectionHelper;
 
 public class CascadeEntityLoader extends AbstractEntityLoader {
 	
 	public CascadeEntityLoader(
 			OuterJoinLoadable persister,
 			CascadingAction action,
-			SessionFactoryImplementor factory) 
-	throws MappingException {
+			SessionFactoryImplementor factory) throws MappingException {
 		super(
 				persister, 
 				persister.getIdentifierType(), 
-				factory, 
-				CollectionHelper.EMPTY_MAP
-			);
+				factory,
+				LoadQueryInfluencers.NONE
+		);
 
 		JoinWalker walker = new CascadeEntityJoinWalker(
 				persister, 
 				action,
 				factory
-			);
+		);
 		initFromWalker( walker );
 
 		postInstantiate();

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/CollectionElementLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -27,7 +27,6 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.List;
-import java.util.Map;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,6 +35,7 @@
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.JoinWalker;
 import org.hibernate.loader.OuterJoinLoader;
 import org.hibernate.persister.collection.QueryableCollection;
@@ -61,9 +61,8 @@
 	public CollectionElementLoader(
 			QueryableCollection collectionPersister,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters) 
-	throws MappingException {
-		super(factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( factory, loadQueryInfluencers );
 
 		this.keyType = collectionPersister.getKeyType();
 		this.indexType = collectionPersister.getIndexType();
@@ -79,7 +78,7 @@
 				1, 
 				LockMode.NONE, 
 				factory, 
-				enabledFilters
+				loadQueryInfluencers
 			);
 		initFromWalker( walker );
 
@@ -130,5 +129,4 @@
 		return true;
 	}
 
-	
 }
\ No newline at end of file

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityJoinWalker.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -25,13 +25,16 @@
 package org.hibernate.loader.entity;
 
 import java.util.Collections;
-import java.util.Map;
+import java.util.Iterator;
 
 import org.hibernate.FetchMode;
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
 import org.hibernate.engine.CascadeStyle;
 import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
+import org.hibernate.engine.profile.FetchProfile;
+import org.hibernate.engine.profile.Fetch;
 import org.hibernate.loader.AbstractEntityJoinWalker;
 import org.hibernate.persister.entity.OuterJoinLoadable;
 import org.hibernate.type.AssociationType;
@@ -52,28 +55,47 @@
 			int batchSize, 
 			LockMode lockMode,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters) 
-	throws MappingException {
-		super(persister, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( persister, factory, loadQueryInfluencers );
 
 		this.lockMode = lockMode;
 		
 		StringBuffer whereCondition = whereString( getAlias(), uniqueKey, batchSize )
-			//include the discriminator and class-level where, but not filters
-			.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
+				//include the discriminator and class-level where, but not filters
+				.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
 
 		initAll( whereCondition.toString(), "", lockMode );
-		
 	}
 
-	/**
-	 * Disable outer join fetching if this loader obtains an
-	 * upgrade lock mode
-	 */
-	protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) {
-		return lockMode.greaterThan(LockMode.READ) ?
-			false :
-			super.isJoinedFetchEnabled(type, config, cascadeStyle);
+	protected int getJoinType(
+			OuterJoinLoadable persister,
+			String path,
+			int propertyNumber,
+			AssociationType associationType,
+			FetchMode metadataFetchMode,
+			CascadeStyle metadataCascadeStyle,
+			String lhsTable,
+			String[] lhsColumns,
+			boolean nullable,
+			int currentDepth) throws MappingException {
+		// NOTE : we override this form here specifically to account for
+		// fetch profiles.
+		// TODO : how to best handle criteria queries?
+		if ( lockMode.greaterThan( LockMode.READ ) ) {
+			return -1;
+		}
+		if ( isTooDeep( currentDepth )
+				|| ( associationType.isCollectionType() && isTooManyCollections() ) ) {
+			return -1;
+		}
+		if ( !isJoinedFetchEnabledInMapping( metadataFetchMode, associationType )
+				&& !isJoinFetchEnabledByProfile( persister, path, propertyNumber ) ) {
+			return -1;
+		}
+		if ( isDuplicateAssociation( lhsTable, lhsColumns, associationType ) ) {
+			return -1;
+		}
+		return getJoinType( nullable, currentDepth );
 	}
 
 	public String getComment() {

Modified: core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/loader/entity/EntityLoader.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -25,12 +25,14 @@
 package org.hibernate.loader.entity;
 
 import java.util.Map;
+import java.util.Set;
 
 import org.hibernate.HibernateException;
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.loader.JoinWalker;
 import org.hibernate.persister.entity.OuterJoinLoadable;
 import org.hibernate.type.Type;
@@ -51,9 +53,8 @@
 			OuterJoinLoadable persister, 
 			LockMode lockMode,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters) 
-	throws MappingException {
-		this(persister, 1, lockMode, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		this( persister, 1, lockMode, factory, loadQueryInfluencers );
 	}
 	
 	public EntityLoader(
@@ -61,16 +62,15 @@
 			int batchSize, 
 			LockMode lockMode,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters) 
-	throws MappingException {
-		this( 
-				persister, 
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		this(
+				persister,
 				persister.getIdentifierColumnNames(), 
 				persister.getIdentifierType(), 
 				batchSize,
 				lockMode,
 				factory, 
-				enabledFilters 
+				loadQueryInfluencers
 			);
 	}
 
@@ -81,9 +81,8 @@
 			int batchSize, 
 			LockMode lockMode,
 			SessionFactoryImplementor factory, 
-			Map enabledFilters) 
-	throws MappingException {
-		super(persister, uniqueKeyType, factory, enabledFilters);
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
+		super( persister, uniqueKeyType, factory, loadQueryInfluencers );
 
 		JoinWalker walker = new EntityJoinWalker(
 				persister, 
@@ -91,8 +90,8 @@
 				batchSize, 
 				lockMode, 
 				factory, 
-				enabledFilters
-			);
+				loadQueryInfluencers
+		);
 		initFromWalker( walker );
 
 		postInstantiate();
@@ -103,9 +102,10 @@
 
 	}
 
-	public Object loadByUniqueKey(SessionImplementor session, Object key) 
-	throws HibernateException {
-		return load(session, key, null, null);
+	public Object loadByUniqueKey(
+			SessionImplementor session,
+			Object key) throws HibernateException {
+		return load( session, key, null, null );
 	}
 
 	protected boolean isSingleRowLoader() {

Added: core/trunk/core/src/main/java/org/hibernate/mapping/FetchProfile.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/mapping/FetchProfile.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/mapping/FetchProfile.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,101 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.mapping;
+
+import java.util.LinkedHashSet;
+
+/**
+ * A fetch profile allows a user to dynamically modify the fetching
+ * strategy used for particular associations at runtime, whereas that
+ * information was historically only statically defined in the metadata.
+ *
+ * @author Steve Ebersole
+ */
+public class FetchProfile {
+	private final String name;
+	private LinkedHashSet fetches = new LinkedHashSet();
+
+	public FetchProfile(String name) {
+		this.name = name;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public LinkedHashSet getFetches() {
+		return fetches;
+	}
+
+	public void addFetch(String entity, String association, String style) {
+		fetches.add( new Fetch( entity, association, style ) );
+	}
+
+	public boolean equals(Object o) {
+		if ( this == o ) {
+			return true;
+		}
+		if ( o == null || getClass() != o.getClass() ) {
+			return false;
+		}
+
+		FetchProfile that = ( FetchProfile ) o;
+
+		return name.equals( that.name );
+
+	}
+
+	public int hashCode() {
+		return name.hashCode();
+	}
+
+
+	/**
+	 * Defines an individual association fetch within the given profile.
+	 */
+	public static class Fetch {
+		private final String entity;
+		private final String association;
+		private final String style;
+
+		public Fetch(String entity, String association, String style) {
+			this.entity = entity;
+			this.association = association;
+			this.style = style;
+		}
+
+		public String getEntity() {
+			return entity;
+		}
+
+		public String getAssociation() {
+			return association;
+		}
+
+		public String getStyle() {
+			return style;
+		}
+	}
+}

Modified: core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -58,6 +58,7 @@
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.SubselectFetch;
 import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.exception.JDBCExceptionHelper;
 import org.hibernate.exception.SQLExceptionConverter;
 import org.hibernate.id.IdentifierGenerator;
@@ -561,7 +562,7 @@
 
 	public void postInstantiate() throws MappingException {
 		initializer = queryLoaderName == null ?
-				createCollectionInitializer( CollectionHelper.EMPTY_MAP ) :
+				createCollectionInitializer( LoadQueryInfluencers.NONE ) :
 				new NamedQueryCollectionInitializer( queryLoaderName, this );
 	}
 
@@ -601,7 +602,7 @@
 			return initializer;
 		}
 		else {
-			return createCollectionInitializer( session.getEnabledFilters() );
+			return createCollectionInitializer( session.getLoadQueryInfluencers() );
 		}
 	}
 
@@ -637,7 +638,7 @@
 
 	protected abstract CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session);
 
-	protected abstract CollectionInitializer createCollectionInitializer(Map enabledFilters)
+	protected abstract CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers)
 			throws MappingException;
 
 	public CollectionRegionAccessStrategy getCacheAccessStrategy() {

Modified: core/trunk/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -42,6 +42,7 @@
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.SubselectFetch;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.exception.JDBCExceptionHelper;
 import org.hibernate.loader.collection.BatchingCollectionInitializer;
 import org.hibernate.loader.collection.CollectionInitializer;
@@ -315,9 +316,9 @@
 	 *
 	 * @see org.hibernate.loader.collection.BasicCollectionLoader
 	 */
-	protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters)
+	protected CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers)
 			throws MappingException {
-		return BatchingCollectionInitializer.createBatchingCollectionInitializer( this, batchSize, getFactory(), enabledFilters );
+		return BatchingCollectionInitializer.createBatchingCollectionInitializer( this, batchSize, getFactory(), loadQueryInfluencers );
 	}
 
 	public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
@@ -336,8 +337,8 @@
 				subselect.getQueryParameters(),
 				subselect.getNamedParameterLocMap(),
 				session.getFactory(),
-				session.getEnabledFilters() 
-			);
+				session.getLoadQueryInfluencers() 
+		);
 	}
 
 }

Modified: core/trunk/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -40,6 +40,7 @@
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.SubselectFetch;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.exception.JDBCExceptionHelper;
 import org.hibernate.loader.collection.BatchingCollectionInitializer;
 import org.hibernate.loader.collection.CollectionInitializer;
@@ -338,8 +339,9 @@
 	 *
 	 * @see org.hibernate.loader.collection.OneToManyLoader
 	 */
-	protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters) throws MappingException {
-		return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), enabledFilters );
+	protected CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers) 
+			throws MappingException {
+		return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), loadQueryInfluencers );
 	}
 
 	public String fromJoinFragment(String alias,
@@ -375,12 +377,12 @@
 				subselect.getQueryParameters(),
 				subselect.getNamedParameterLocMap(),
 				session.getFactory(),
-				session.getEnabledFilters() 
+				session.getLoadQueryInfluencers()
 			);
 	}
 
 	public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner) {
-		return new CollectionElementLoader( this, getFactory(), session.getEnabledFilters() )
+		return new CollectionElementLoader( this, getFactory(), session.getLoadQueryInfluencers() )
 				.loadElement( session, key, incrementIndexByBase(index) );
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -52,7 +52,6 @@
 import org.hibernate.jdbc.Expectations;
 import org.hibernate.jdbc.TooManyRowsAffectedException;
 import org.hibernate.dialect.lock.LockingStrategy;
-import org.hibernate.cache.CacheConcurrencyStrategy;
 import org.hibernate.cache.CacheKey;
 import org.hibernate.cache.access.EntityRegionAccessStrategy;
 import org.hibernate.cache.entry.CacheEntry;
@@ -69,6 +68,7 @@
 import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
 import org.hibernate.engine.EntityKey;
 import org.hibernate.engine.ValueInclusion;
+import org.hibernate.engine.LoadQueryInfluencers;
 import org.hibernate.exception.JDBCExceptionHelper;
 import org.hibernate.id.IdentifierGenerator;
 import org.hibernate.id.PostInsertIdentifierGenerator;
@@ -109,7 +109,6 @@
 import org.hibernate.type.TypeFactory;
 import org.hibernate.type.VersionType;
 import org.hibernate.util.ArrayHelper;
-import org.hibernate.util.CollectionHelper;
 import org.hibernate.util.FilterHelper;
 import org.hibernate.util.StringHelper;
 
@@ -196,6 +195,8 @@
 	// dynamic filters attached to the class-level
 	private final FilterHelper filterHelper;
 
+	private final Set affectingFetchProfileNames = new HashSet();
+
 	private final Map uniqueKeyLoaders = new HashMap();
 	private final Map lockers = new HashMap();
 	private final Map loaders = new HashMap();
@@ -1667,26 +1668,27 @@
 
 	}
 
-	public Object loadByUniqueKey(String propertyName, Object uniqueKey, SessionImplementor session)
-			throws HibernateException {
-		return getAppropriateUniqueKeyLoader( propertyName, session.getEnabledFilters() )
-				.loadByUniqueKey( session, uniqueKey );
+	public Object loadByUniqueKey(
+			String propertyName,
+			Object uniqueKey,
+			SessionImplementor session) throws HibernateException {
+		return getAppropriateUniqueKeyLoader( propertyName, session ).loadByUniqueKey( session, uniqueKey );
 	}
 
-	private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, Map enabledFilters) {
-
-		final boolean useStaticLoader = ( enabledFilters == null || enabledFilters.isEmpty() )
+	private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, SessionImplementor session) {
+		final boolean useStaticLoader = !session.getLoadQueryInfluencers().hasEnabledFilters()
+				&& !session.getLoadQueryInfluencers().hasEnabledFetchProfiles()
 				&& propertyName.indexOf('.')<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
 
 		if ( useStaticLoader ) {
-			return (EntityLoader) uniqueKeyLoaders.get( propertyName );
+			return ( EntityLoader ) uniqueKeyLoaders.get( propertyName );
 		}
 		else {
 			return createUniqueKeyLoader(
-					propertyMapping.toType(propertyName),
-					propertyMapping.toColumns(propertyName),
-					enabledFilters
-				);
+					propertyMapping.toType( propertyName ),
+					propertyMapping.toColumns( propertyName ),
+					session.getLoadQueryInfluencers()
+			);
 		}
 	}
 
@@ -1705,21 +1707,31 @@
 						createUniqueKeyLoader(
 								propertyTypes[i],
 								getPropertyColumnNames( i ),
-								CollectionHelper.EMPTY_MAP
-							)
-					);
+								LoadQueryInfluencers.NONE
+						)
+				);
 				//TODO: create uk loaders for component properties
 			}
 		}
 	}
 
-	private EntityLoader createUniqueKeyLoader(Type uniqueKeyType, String[] columns, Map enabledFilters) {
+	private EntityLoader createUniqueKeyLoader(
+			Type uniqueKeyType,
+			String[] columns,
+			LoadQueryInfluencers loadQueryInfluencers) {
 		if ( uniqueKeyType.isEntityType() ) {
 			String className = ( ( EntityType ) uniqueKeyType ).getAssociatedEntityName();
 			uniqueKeyType = getFactory().getEntityPersister( className ).getIdentifierType();
 		}
-
-		return new EntityLoader( this, columns, uniqueKeyType, 1, LockMode.NONE, getFactory(), enabledFilters );
+		return new EntityLoader(
+				this,
+				columns,
+				uniqueKeyType,
+				1,
+				LockMode.NONE,
+				getFactory(),
+				loadQueryInfluencers
+		);
 	}
 
 	protected String getSQLWhereString(String alias) {
@@ -1770,13 +1782,21 @@
 		}
 	}
 
-	protected UniqueEntityLoader createEntityLoader(LockMode lockMode, Map enabledFilters) throws MappingException {
+	protected UniqueEntityLoader createEntityLoader(
+			LockMode lockMode,
+			LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
 		//TODO: disable batch loading if lockMode > READ?
-		return BatchingEntityLoader.createBatchingEntityLoader( this, batchSize, lockMode, getFactory(), enabledFilters );
+		return BatchingEntityLoader.createBatchingEntityLoader(
+				this,
+				batchSize,
+				lockMode,
+				getFactory(),
+				loadQueryInfluencers
+		);
 	}
 
 	protected UniqueEntityLoader createEntityLoader(LockMode lockMode) throws MappingException {
-		return createEntityLoader( lockMode, CollectionHelper.EMPTY_MAP );
+		return createEntityLoader( lockMode, LoadQueryInfluencers.NONE );
 	}
 
 	protected boolean check(int rows, Serializable id, int tableNumber, Expectation expectation, PreparedStatement statement) throws HibernateException {
@@ -3072,21 +3092,49 @@
 		return loader.load( id, optionalObject, session );
 	}
 
+	public void registerAffectingFetchProfile(String fetchProfileName) {
+		affectingFetchProfileNames.add( fetchProfileName );
+	}
+
+	private boolean isAffectedByEnabledFetchProfiles(SessionImplementor session) {
+		Iterator itr = session.getLoadQueryInfluencers().getEnabledFetchProfileNames().iterator();
+		while ( itr.hasNext() ) {
+			if ( affectingFetchProfileNames.contains( itr.next() ) ) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private boolean isAffectedByEnabledFilters(SessionImplementor session) {
+		return session.getLoadQueryInfluencers().hasEnabledFilters()
+				&& filterHelper.isAffectedBy( session.getLoadQueryInfluencers().getEnabledFilters() );
+	}
+
 	private UniqueEntityLoader getAppropriateLoader(LockMode lockMode, SessionImplementor session) {
-		final Map enabledFilters = session.getEnabledFilters();
 		if ( queryLoader != null ) {
+			// if the user specified a custom query loader we need to that
+			// regardless of any other consideration
 			return queryLoader;
 		}
-		else if ( enabledFilters == null || enabledFilters.isEmpty() ) {
-			if ( session.getFetchProfile()!=null && LockMode.UPGRADE.greaterThan(lockMode) ) {
-				return (UniqueEntityLoader) loaders.get( session.getFetchProfile() );
-			}
-			else {
-				return (UniqueEntityLoader) loaders.get( lockMode );
-			}
+		else if ( isAffectedByEnabledFilters( session ) ) {
+			// because filters affect the rows returned (because they add
+			// restirctions) these need to be next in precendence
+			return createEntityLoader( lockMode, session.getLoadQueryInfluencers() );
 		}
+		else if ( session.getLoadQueryInfluencers().getInternalFetchProfile() != null && LockMode.UPGRADE.greaterThan( lockMode ) ) {
+			// Next, we consider whether an 'internal' fetch profile has been set.
+			// This indicates a special fetch profile Hibernate needs applied
+			// (for its merge loading process e.g.).
+			return ( UniqueEntityLoader ) loaders.get( session.getLoadQueryInfluencers().getInternalFetchProfile() );
+		}
+		else if ( isAffectedByEnabledFetchProfiles( session ) ) {
+			// If the session has associated influencers we need to adjust the
+			// SQL query used for loading based on those influencers
+			return createEntityLoader( lockMode, session.getLoadQueryInfluencers() );
+		}
 		else {
-			return createEntityLoader( lockMode, enabledFilters );
+			return ( UniqueEntityLoader ) loaders.get( lockMode );
 		}
 	}
 

Modified: core/trunk/core/src/main/java/org/hibernate/persister/entity/Loadable.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/entity/Loadable.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/java/org/hibernate/persister/entity/Loadable.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -108,4 +108,12 @@
 
 	public boolean isAbstract();
 
+	/**
+	 * Register the name of a fetch profile determined to have an affect on the
+	 * underlying loadable in regards to the fact that the underlying load SQL
+	 * needs to be adjust when the given fetch profile is enabled.
+	 * 
+	 * @param fetchProfileName The name of the profile affecting this.
+	 */
+	public void registerAffectingFetchProfile(String fetchProfileName);
 }

Modified: core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
===================================================================
--- core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd	2008-08-15 21:20:15 UTC (rev 15091)
@@ -19,11 +19,12 @@
 <!ELEMENT hibernate-mapping (
 	meta*, 
 	typedef*, 
-	import*, 
+	import*,
 	(class|subclass|joined-subclass|union-subclass)*,
     resultset*,
 	(query|sql-query)*,
 	filter-def*,
+	fetch-profile*,
     database-object*
 )>
 	<!ATTLIST hibernate-mapping schema CDATA #IMPLIED>									<!-- default: none -->
@@ -78,6 +79,7 @@
 	((join*,subclass*)|joined-subclass*|union-subclass*),
 	loader?,sql-insert?,sql-update?,sql-delete?,
 	filter*,
+    fetch-profile*,
     resultset*,
 	(query|sql-query)*
 )>
@@ -133,7 +135,23 @@
 	<!ATTLIST filter name CDATA #REQUIRED>
 	<!ATTLIST filter condition CDATA #IMPLIED>
 
+<!--
+-->
+<!ELEMENT fetch-profile (fetch*)>
+    <!ATTLIST fetch-profile name CDATA #REQUIRED>
 
+<!--
+    The <fetch> element defines a single path to which the fetch
+    refers, as well as the style of fetch to apply.  The 'root' of the
+    path is different depending upon the context in which the
+    containing <fetch-profile/> occurs; within a <class/> element,
+    the entity-name of the containing class mapping is assumed...
+-->
+<!ELEMENT fetch EMPTY>
+    <!ATTLIST fetch entity CDATA #IMPLIED> <!-- Implied as long as the containing fetch profile is contained in a class mapping -->
+    <!ATTLIST fetch association CDATA #REQUIRED>
+    <!ATTLIST fetch style (join|select) "join">
+
 <!-- A join allows some properties of a class to be persisted to a second table -->
 
 <!ELEMENT join ( 
@@ -231,6 +249,7 @@
 	join*, 
 	subclass*,
 	loader?,sql-insert?,sql-update?,sql-delete?,
+    fetch-profile*,
     resultset*,
 	(query|sql-query)*
 )>
@@ -263,6 +282,7 @@
 	(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*, 
 	joined-subclass*,
 	loader?,sql-insert?,sql-update?,sql-delete?,
+    fetch-profile*,
     resultset*,
 	(query|sql-query)*
 )>
@@ -298,6 +318,7 @@
 	(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*,
 	union-subclass*,
 	loader?,sql-insert?,sql-update?,sql-delete?,
+    fetch-profile*,
     resultset*,
 	(query|sql-query)*
 )>

Modified: core/trunk/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java
===================================================================
--- core/trunk/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/jmx/src/main/java/org/hibernate/jmx/SessionFactoryStub.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -198,4 +198,8 @@
 	public FilterDefinition getFilterDefinition(String filterName) throws HibernateException {
 		return getImpl().getFilterDefinition( filterName );
 	}
+
+	public boolean containsFetchProfileDefition(String name) {
+		return getImpl().containsFetchProfileDefition( name );
+	}
 }

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/BasicFetchProfileTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/BasicFetchProfileTest.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/BasicFetchProfileTest.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,281 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.test.fetchprofiles.basic;
+
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.UnknownProfileException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class BasicFetchProfileTest extends FunctionalTestCase {
+	public BasicFetchProfileTest(String string) {
+		super( string );
+	}
+
+	public String[] getMappings() {
+		return new String[] { "fetchprofiles/basic/Mappings.hbm.xml" };
+	}
+
+	public String getCacheConcurrencyStrategy() {
+		return null;
+	}
+
+	public void configure(Configuration cfg) {
+		cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
+	}
+
+	private static interface TestData {
+		public Long getStudentId();
+		public Long getDepartmentId();
+		public Long getCourseId();
+		public Long getSectionId();
+		public Long getEnrollmentId();
+	}
+
+	private interface TestCode {
+		public void perform(TestData data);
+	}
+
+	private void performWithStandardData(TestCode testCode) {
+		Session session = openSession();
+		session.beginTransaction();
+		final Department literatureDepartment = new Department( "lit", "Literature" );
+		session.save( literatureDepartment );
+		final Course lit101 = new Course( new Course.Code( literatureDepartment, 101 ), "Introduction to Literature" );
+		session.save( lit101 );
+		final CourseOffering section = new CourseOffering( lit101, 1, 2008 );
+		session.save( section );
+		final Student me = new Student( "Steve" );
+		session.save( me );
+		final Enrollment enrollment = new Enrollment( section, me );
+		section.getEnrollments().add( enrollment );
+		session.save( enrollment );
+		session.getTransaction().commit();
+		session.close();
+
+		sfi().getStatistics().clear();
+
+		testCode.perform(
+				new TestData() {
+					public Long getStudentId() {
+						return me.getId();
+					}
+
+					public Long getDepartmentId() {
+						return literatureDepartment.getId();
+					}
+
+					public Long getCourseId() {
+						return lit101.getId();
+					}
+
+					public Long getSectionId() {
+						return section.getId();
+					}
+
+					public Long getEnrollmentId() {
+						return enrollment.getId();
+					}
+				}
+		);
+
+		session = openSession();
+		session.beginTransaction();
+		session.delete( enrollment );
+		session.delete( me );
+		session.delete( enrollment.getOffering() );
+		session.delete( enrollment.getOffering().getCourse() );
+		session.delete( enrollment.getOffering().getCourse().getCode().getDepartment() );
+		session.getTransaction().commit();
+		session.close();
+	}
+
+	public void testNormalLoading() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						CourseOffering section = ( CourseOffering ) session.get( CourseOffering.class, data.getSectionId() );
+						assertEquals( 1, sfi().getStatistics().getEntityLoadCount() );
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertFalse( Hibernate.isInitialized( section.getCourse() ) );
+						assertFalse( Hibernate.isInitialized( section.getEnrollments() ) );
+						assertFalse( Hibernate.isInitialized( section.getCourse().getCode().getDepartment() ) );
+						assertTrue( Hibernate.isInitialized( section.getCourse() ) );
+						assertEquals( 1, sfi().getStatistics().getEntityFetchCount() );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+
+	public void testNormalCriteria() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						CourseOffering section = ( CourseOffering ) session.createCriteria( CourseOffering.class ).uniqueResult();
+						assertEquals( 1, sfi().getStatistics().getEntityLoadCount() );
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertFalse( Hibernate.isInitialized( section.getCourse() ) );
+						assertFalse( Hibernate.isInitialized( section.getEnrollments() ) );
+						assertFalse( Hibernate.isInitialized( section.getCourse().getCode().getDepartment() ) );
+						assertTrue( Hibernate.isInitialized( section.getCourse() ) );
+						assertEquals( 1, sfi().getStatistics().getEntityFetchCount() );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+
+	public void testBasicFetchProfileOperation() {
+		assertTrue( "fetch profile not parsed properly", sfi().containsFetchProfileDefition( "enrollment.details" ) );
+		assertTrue( "fetch profile not parsed properly", sfi().containsFetchProfileDefition( "offering.details" ) );
+		assertTrue( "fetch profile not parsed properly", sfi().containsFetchProfileDefition( "course.details" ) );
+		Session s = openSession();
+		SessionImplementor si = ( SessionImplementor ) s;
+		s.enableFetchProfile( "enrollment.details" );
+		assertTrue( si.getLoadQueryInfluencers().hasEnabledFetchProfiles() );
+		s.disableFetchProfile( "enrollment.details" );
+		assertFalse( si.getLoadQueryInfluencers().hasEnabledFetchProfiles() );
+		try {
+			s.enableFetchProfile( "never-gonna-get-it" );
+			fail( "expecting failure on undefined fetch-profile" );
+		}
+		catch ( UnknownProfileException expected ) {
+		}
+		s.close();
+	}
+
+	public void testLoadManyToOneFetchProfile() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						session.enableFetchProfile( "enrollment.details" );
+						Enrollment enrollment = ( Enrollment ) session.get( Enrollment.class, data.getEnrollmentId() );
+						assertEquals( 3, sfi().getStatistics().getEntityLoadCount() ); // enrollment + (section + student)
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertTrue( Hibernate.isInitialized( enrollment.getOffering() ) );
+						assertTrue( Hibernate.isInitialized( enrollment.getStudent() ) );
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+
+	public void testCriteriaManyToOneFetchProfile() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						session.enableFetchProfile( "enrollment.details" );
+						Enrollment enrollment = ( Enrollment ) session.createCriteria( Enrollment.class ).uniqueResult();
+						assertEquals( 3, sfi().getStatistics().getEntityLoadCount() ); // enrollment + (section + student)
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertTrue( Hibernate.isInitialized( enrollment.getOffering() ) );
+						assertTrue( Hibernate.isInitialized( enrollment.getStudent() ) );
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+
+	public void testLoadOneToManyFetchProfile() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						session.enableFetchProfile( "offering.details" );
+						CourseOffering section = ( CourseOffering ) session.get( CourseOffering.class, data.getSectionId() );
+						assertEquals( 3, sfi().getStatistics().getEntityLoadCount() ); // section + (enrollments + course)
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertTrue( Hibernate.isInitialized( section.getEnrollments() ) );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+
+	public void testLoadDeepFetchProfile() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						// enable both enrollment and offering detail profiles;
+						// then loading the section/offering should fetch the enrollment
+						// which in turn should fetch student (+ offering).
+						session.enableFetchProfile( "offering.details" );
+						session.enableFetchProfile( "enrollment.details" );
+						CourseOffering section = ( CourseOffering ) session.get( CourseOffering.class, data.getSectionId() );
+						assertEquals( 4, sfi().getStatistics().getEntityLoadCount() ); // section + (course + enrollments + (student))
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertTrue( Hibernate.isInitialized( section.getEnrollments() ) );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+
+	public void testLoadComponentDerefFetchProfile() {
+		performWithStandardData(
+				new TestCode() {
+					public void perform(TestData data) {
+						Session session = openSession();
+						session.beginTransaction();
+						session.enableFetchProfile( "course.details" );
+						Course course = ( Course ) session.get( Course.class, data.getCourseId() );
+						assertEquals( 2, sfi().getStatistics().getEntityLoadCount() ); // course + department
+						assertEquals( 0, sfi().getStatistics().getEntityFetchCount() );
+						assertTrue( Hibernate.isInitialized( course.getCode().getDepartment() ) );
+						session.getTransaction().commit();
+						session.close();
+					}
+				}
+		);
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Course.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Course.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Course.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,123 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.test.fetchprofiles.basic;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Course {
+	private Long id;
+	private Code code;
+	private String name;
+
+	public Course() {
+	}
+
+	public Course(Code code, String name) {
+		this.code = code;
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Code getCode() {
+		return code;
+	}
+
+	public void setCode(Code code) {
+		this.code = code;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+	public static class Code {
+		private Department department;
+		private int number;
+
+		public Code() {
+		}
+
+		public Code(Department department, int number) {
+			this.department = department;
+			this.number = number;
+		}
+
+		public Department getDepartment() {
+			return department;
+		}
+
+		public void setDepartment(Department department) {
+			this.department = department;
+		}
+
+		public int getNumber() {
+			return number;
+		}
+
+		public void setNumber(int number) {
+			this.number = number;
+		}
+
+		public boolean equals(Object o) {
+			if ( this == o ) {
+				return true;
+			}
+			if ( !( o instanceof Code ) ) {
+				return false;
+			}
+
+			Code code = ( Code ) o;
+
+			if ( number != code.number ) {
+				return false;
+			}
+			if ( !department.equals( code.department ) ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		public int hashCode() {
+			int result;
+			result = department.hashCode();
+			result = 31 * result + number;
+			return result;
+		}
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/CourseOffering.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/CourseOffering.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/CourseOffering.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,90 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.test.fetchprofiles.basic;
+
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class CourseOffering {
+	private Long id;
+	private Course course;
+	private int semester;
+	private int year;
+	private Set enrollments = new HashSet();
+
+	public CourseOffering() {
+	}
+
+	public CourseOffering(Course course, int semester, int year) {
+		this.course = course;
+		this.semester = semester;
+		this.year = year;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Course getCourse() {
+		return course;
+	}
+
+	public void setCourse(Course course) {
+		this.course = course;
+	}
+
+	public int getSemester() {
+		return semester;
+	}
+
+	public void setSemester(int semester) {
+		this.semester = semester;
+	}
+
+	public int getYear() {
+		return year;
+	}
+
+	public void setYear(int year) {
+		this.year = year;
+	}
+
+	public Set getEnrollments() {
+		return enrollments;
+	}
+
+	public void setEnrollments(Set enrollments) {
+		this.enrollments = enrollments;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Department.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Department.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Department.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,68 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.test.fetchprofiles.basic;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Department {
+	private Long id;
+	private String code;
+	private String name;
+
+	public Department() {
+	}
+
+	public Department(String code, String name) {
+		this.code = code;
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Enrollment.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Enrollment.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Enrollment.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,77 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.test.fetchprofiles.basic;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Enrollment {
+	private Long id;
+	private CourseOffering offering;
+	private Student student;
+	private int finalGrade;
+
+	public Enrollment() {
+	}
+
+	public Enrollment(CourseOffering offering, Student student) {
+		this.offering = offering;
+		this.student = student;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public CourseOffering getOffering() {
+		return offering;
+	}
+
+	public void setOffering(CourseOffering offering) {
+		this.offering = offering;
+	}
+
+	public Student getStudent() {
+		return student;
+	}
+
+	public void setStudent(Student student) {
+		this.student = student;
+	}
+
+	public int getFinalGrade() {
+		return finalGrade;
+	}
+
+	public void setFinalGrade(int finalGrade) {
+		this.finalGrade = finalGrade;
+	}
+}

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Mappings.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Mappings.hbm.xml	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Mappings.hbm.xml	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping
+        SYSTEM
+        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
+
+<!--
+  ~ Hibernate, Relational Persistence for Idiomatic Java
+  ~
+  ~ Copyright (c) 2008, Red Hat Middleware LLC 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.
+  ~
+  ~ 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
+  ~
+  -->
+
+<hibernate-mapping package="org.hibernate.test.fetchprofiles.basic">
+
+    <class name="Department">
+    	<id name="id" type="long">
+    		<generator class="increment"/>
+    	</id>
+        <property name="code" column="CODE" type="string"/>
+        <property name="name" column="NAME" type="string"/>
+	</class>
+
+    <class name="Student">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+    </class>
+
+    <class name="Course">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <property name="name" column="NAME" type="string"/>
+        <component name="code" class="Course$Code">
+            <many-to-one name="department" class="Department" column="DEPT_ID" cascade="save-update"/>
+            <property name="number" type="int" column="CODE_NUMBER"/>
+        </component>
+        <fetch-profile name="course.details">
+            <fetch association="code.department" style="join"/>
+        </fetch-profile>
+    </class>
+
+    <class name="CourseOffering" table="SECTION">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <many-to-one name="course" column="COURSE_ID" class="Course"/>
+        <property name="semester" type="int" column="SEMESTER"/>
+        <property name="year" type="int" column="YEAR"/>
+        <set name="enrollments" lazy="true" cascade="all">
+            <key column="SECTION_ID"/>
+            <one-to-many class="Enrollment"/>
+        </set>
+        <fetch-profile name="offering.details">
+            <fetch association="enrollments" style="join"/>
+            <fetch association="course" style="join"/>
+        </fetch-profile>
+        <fetch-profile name="offering.details2">
+            <fetch entity="CourseOffering" association="enrollments" style="join"/>
+        </fetch-profile>
+    </class>
+
+    <class name="Enrollment">
+        <id name="id" type="long">
+            <generator class="increment"/>
+        </id>
+        <many-to-one name="offering" column="SECTION_ID" class="CourseOffering" cascade="none"/>
+        <many-to-one name="student" column="STUDENT_ID" class="Student" cascade="none"/>
+        <property name="finalGrade" column="FINAL_GRADE" type="int"/>
+    </class>
+
+    <fetch-profile name="enrollment.details">
+        <fetch entity="Enrollment" association="student" style="join"/>
+        <fetch entity="Enrollment" association="offering" style="join"/>
+    </fetch-profile>
+
+</hibernate-mapping>

Added: core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Student.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Student.java	                        (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/fetchprofiles/basic/Student.java	2008-08-15 21:20:15 UTC (rev 15091)
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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.
+ *
+ * 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.test.fetchprofiles.basic;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Student {
+	private Long id;
+	private String name;
+
+	public Student() {
+	}
+
+	public Student(String name) {
+		this.name = name;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}

Modified: core/trunk/testsuite/src/test/resources/hibernate.properties
===================================================================
--- core/trunk/testsuite/src/test/resources/hibernate.properties	2008-08-15 21:03:38 UTC (rev 15090)
+++ core/trunk/testsuite/src/test/resources/hibernate.properties	2008-08-15 21:20:15 UTC (rev 15091)
@@ -22,6 +22,7 @@
 
 hibernate.connection.pool_size 5
 
+hibernate.show_sql true
 hibernate.format_sql true
 
 hibernate.max_fetch_depth 5




More information about the hibernate-commits mailing list