HHH-3414 : fetch profiles, phase 1 : join fetching

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15091 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2008-08-15 21:20:15 +00:00
parent 8f3ce7a6e7
commit fbae6db0ab
54 changed files with 2411 additions and 533 deletions

View File

@ -813,4 +813,40 @@ public interface Session extends Serializable {
* @see #disconnect() * @see #disconnect()
*/ */
void reconnect(Connection connection) throws HibernateException; 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;
} }

View File

@ -244,4 +244,13 @@ public interface SessionFactory extends Referenceable, Serializable {
* @throws HibernateException If no filter defined with the given name. * @throws HibernateException If no filter defined with the given name.
*/ */
public FilterDefinition getFilterDefinition(String filterName) throws HibernateException; 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);
} }

View File

@ -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;
}
}

View File

@ -114,6 +114,7 @@ import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey; import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.FetchProfile;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.secure.JACCConfiguration; import org.hibernate.secure.JACCConfiguration;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata; import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
@ -163,6 +164,7 @@ public class Configuration implements Serializable {
*/ */
protected Map sqlResultSetMappings; protected Map sqlResultSetMappings;
protected Map filterDefinitions; protected Map filterDefinitions;
protected Map fetchProfiles;
protected List secondPasses; protected List secondPasses;
protected List propertyReferences; protected List propertyReferences;
// protected List extendsQueue; // protected List extendsQueue;
@ -202,6 +204,7 @@ public class Configuration implements Serializable {
entityResolver = XMLHelper.DEFAULT_DTD_RESOLVER; entityResolver = XMLHelper.DEFAULT_DTD_RESOLVER;
eventListeners = new EventListeners(); eventListeners = new EventListeners();
filterDefinitions = new HashMap(); filterDefinitions = new HashMap();
fetchProfiles = new HashMap();
// extendsQueue = new ArrayList(); // extendsQueue = new ArrayList();
extendsQueue = new HashMap(); extendsQueue = new HashMap();
auxiliaryDatabaseObjects = new ArrayList(); auxiliaryDatabaseObjects = new ArrayList();
@ -720,6 +723,7 @@ public class Configuration implements Serializable {
namingStrategy, namingStrategy,
typeDefs, typeDefs,
filterDefinitions, filterDefinitions,
fetchProfiles,
extendsQueue, extendsQueue,
auxiliaryDatabaseObjects, auxiliaryDatabaseObjects,
tableNameBinding, tableNameBinding,
@ -2181,6 +2185,14 @@ public class Configuration implements Serializable {
filterDefinitions.put( definition.getFilterName(), definition ); 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) { public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject object) {
auxiliaryDatabaseObjects.add( object ); auxiliaryDatabaseObjects.add( object );
} }

View File

@ -89,6 +89,7 @@ import org.hibernate.mapping.TypeDef;
import org.hibernate.mapping.UnionSubclass; import org.hibernate.mapping.UnionSubclass;
import org.hibernate.mapping.UniqueKey; import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.Value; import org.hibernate.mapping.Value;
import org.hibernate.mapping.FetchProfile;
import org.hibernate.persister.entity.JoinedSubclassEntityPersister; import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister; import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.persister.entity.UnionSubclassEntityPersister; import org.hibernate.persister.entity.UnionSubclassEntityPersister;
@ -158,6 +159,9 @@ public final class HbmBinder {
if ( "filter-def".equals( elementName ) ) { if ( "filter-def".equals( elementName ) ) {
parseFilterDef( element, mappings ); parseFilterDef( element, mappings );
} }
else if ( "fetch-profile".equals( elementName ) ) {
parseFetchProfile( element, mappings, null );
}
else if ( "typedef".equals( elementName ) ) { else if ( "typedef".equals( elementName ) ) {
bindTypeDef( element, mappings ); bindTypeDef( element, mappings );
} }
@ -546,8 +550,13 @@ public final class HbmBinder {
bindDom4jRepresentation( node, persistentClass, mappings, inheritedMetas ); bindDom4jRepresentation( node, persistentClass, mappings, inheritedMetas );
bindMapRepresentation( node, persistentClass, mappings, inheritedMetas ); bindMapRepresentation( node, persistentClass, mappings, inheritedMetas );
bindPersistentClassCommonValues( 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, private static void bindPojoRepresentation(Element node, PersistentClass entity,
@ -2963,6 +2972,25 @@ public final class HbmBinder {
filterable.addFilter( name, condition ); 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) { private static String getSubselect(Element element) {
String subselect = element.attributeValue( "subselect" ); String subselect = element.attributeValue( "subselect" );
if ( subselect != null ) { if ( subselect != null ) {

View File

@ -46,6 +46,7 @@ import org.hibernate.mapping.Table;
import org.hibernate.mapping.TypeDef; import org.hibernate.mapping.TypeDef;
import org.hibernate.mapping.AuxiliaryDatabaseObject; import org.hibernate.mapping.AuxiliaryDatabaseObject;
import org.hibernate.mapping.Column; import org.hibernate.mapping.Column;
import org.hibernate.mapping.FetchProfile;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
/** /**
@ -77,6 +78,7 @@ public class Mappings implements Serializable {
protected final List propertyReferences; protected final List propertyReferences;
protected final NamingStrategy namingStrategy; protected final NamingStrategy namingStrategy;
protected final Map filterDefinitions; protected final Map filterDefinitions;
protected final Map fetchProfiles;
protected final List auxiliaryDatabaseObjects; protected final List auxiliaryDatabaseObjects;
protected final Map extendsQueue; protected final Map extendsQueue;
@ -111,12 +113,12 @@ public class Mappings implements Serializable {
final NamingStrategy namingStrategy, final NamingStrategy namingStrategy,
final Map typeDefs, final Map typeDefs,
final Map filterDefinitions, final Map filterDefinitions,
final Map fetchProfiles,
// final List extendsQueue, // final List extendsQueue,
final Map extendsQueue, final Map extendsQueue,
final List auxiliaryDatabaseObjects, final List auxiliaryDatabaseObjects,
final Map tableNamebinding, final Map tableNamebinding,
final Map columnNameBindingPerTable final Map columnNameBindingPerTable) {
) {
this.classes = classes; this.classes = classes;
this.collections = collections; this.collections = collections;
this.queries = queries; this.queries = queries;
@ -129,6 +131,7 @@ public class Mappings implements Serializable {
this.namingStrategy = namingStrategy; this.namingStrategy = namingStrategy;
this.typeDefs = typeDefs; this.typeDefs = typeDefs;
this.filterDefinitions = filterDefinitions; this.filterDefinitions = filterDefinitions;
this.fetchProfiles = fetchProfiles;
this.extendsQueue = extendsQueue; this.extendsQueue = extendsQueue;
this.auxiliaryDatabaseObjects = auxiliaryDatabaseObjects; this.auxiliaryDatabaseObjects = auxiliaryDatabaseObjects;
this.tableNameBinding = tableNamebinding; this.tableNameBinding = tableNamebinding;
@ -418,7 +421,20 @@ public class Mappings implements Serializable {
public FilterDefinition getFilterDefinition(String name) { public FilterDefinition getFilterDefinition(String name) {
return (FilterDefinition) filterDefinitions.get(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() { public boolean isDefaultLazy() {
return defaultLazy; return defaultLazy;
} }

View File

@ -32,6 +32,7 @@ import org.hibernate.HibernateException;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.TypedValue; import org.hibernate.engine.TypedValue;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.impl.CriteriaImpl; import org.hibernate.impl.CriteriaImpl;
import org.hibernate.loader.criteria.CriteriaJoinWalker; import org.hibernate.loader.criteria.CriteriaJoinWalker;
import org.hibernate.loader.criteria.CriteriaQueryTranslator; import org.hibernate.loader.criteria.CriteriaQueryTranslator;
@ -76,8 +77,9 @@ public abstract class SubqueryExpression implements Criterion {
factory, factory,
criteriaImpl, criteriaImpl,
criteriaImpl.getEntityOrClassName(), criteriaImpl.getEntityOrClassName(),
new HashMap(), LoadQueryInfluencers.NONE,
innerQuery.getRootSQLALias()); innerQuery.getRootSQLALias()
);
String sql = walker.getSQLString(); String sql = walker.getSQLString();

View File

@ -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 );
}
}

View File

@ -37,6 +37,7 @@ import org.hibernate.SessionFactory;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.engine.query.QueryPlanCache; import org.hibernate.engine.query.QueryPlanCache;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.cache.QueryCache; import org.hibernate.cache.QueryCache;
@ -219,5 +220,13 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
public EntityNotFoundDelegate getEntityNotFoundDelegate(); public EntityNotFoundDelegate getEntityNotFoundDelegate();
public SQLFunctionRegistry getSqlFunctionRegistry(); 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);
} }

View File

@ -29,6 +29,7 @@ import java.sql.Connection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
@ -237,6 +238,7 @@ public interface SessionImplementor extends Serializable {
* @param filterParameterName The filter parameter name in the format * @param filterParameterName The filter parameter name in the format
* {FILTER_NAME.PARAMETER_NAME}. * {FILTER_NAME.PARAMETER_NAME}.
* @return The filter parameter value. * @return The filter parameter value.
* @deprecated use #getLoadQueryInfluencers instead
*/ */
public Object getFilterParameterValue(String filterParameterName); public Object getFilterParameterValue(String filterParameterName);
@ -245,6 +247,8 @@ public interface SessionImplementor extends Serializable {
* *
* @param filterParameterName The filter parameter name in the format * @param filterParameterName The filter parameter name in the format
* {FILTER_NAME.PARAMETER_NAME}. * {FILTER_NAME.PARAMETER_NAME}.
* @return The filter param type
* @deprecated use #getLoadQueryInfluencers instead
*/ */
public Type getFilterParameterType(String filterParameterName); public Type getFilterParameterType(String filterParameterName);
@ -253,6 +257,7 @@ public interface SessionImplementor extends Serializable {
* name, with values corresponding to the {@link org.hibernate.impl.FilterImpl} * name, with values corresponding to the {@link org.hibernate.impl.FilterImpl}
* instance. * instance.
* @return The currently enabled filters. * @return The currently enabled filters.
* @deprecated use #getLoadQueryInfluencers instead
*/ */
public Map getEnabledFilters(); public Map getEnabledFilters();
@ -307,10 +312,22 @@ public interface SessionImplementor extends Serializable {
public void afterScrollOperation(); public void afterScrollOperation();
public void setFetchProfile(String name); /**
* 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(); 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 JDBCContext getJDBCContext(); public JDBCContext getJDBCContext();
/** /**
@ -322,4 +339,12 @@ public interface SessionImplementor extends Serializable {
* @return True if the session is closed; false otherwise. * @return True if the session is closed; false otherwise.
*/ */
public boolean isClosed(); 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();
} }

View File

@ -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;
}
}

View File

@ -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() + "}]";
}
}

View File

@ -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;
}
}

View File

@ -84,6 +84,9 @@ import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition; import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.SessionFactoryImplementor; 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.QueryPlanCache;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.event.EventListeners; import org.hibernate.event.EventListeners;
@ -100,6 +103,7 @@ import org.hibernate.persister.PersisterFactory;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.stat.Statistics; import org.hibernate.stat.Statistics;
@ -156,6 +160,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
private final transient Map namedSqlQueries; private final transient Map namedSqlQueries;
private final transient Map sqlResultSetMappings; private final transient Map sqlResultSetMappings;
private final transient Map filters; private final transient Map filters;
private final transient Map fetchProfiles;
private final transient Map imports; private final transient Map imports;
private final transient Interceptor interceptor; private final transient Interceptor interceptor;
private final transient Settings settings; private final transient Settings settings;
@ -198,6 +203,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
public void sessionFactoryClosed(SessionFactory factory) { public void sessionFactoryClosed(SessionFactory factory) {
} }
}; };
this.filters = new HashMap(); this.filters = new HashMap();
this.filters.putAll( cfg.getFilterDefinitions() ); this.filters.putAll( cfg.getFilterDefinitions() );
@ -412,6 +418,43 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
} }
this.entityNotFoundDelegate = entityNotFoundDelegate; 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 ); this.observer.sessionFactoryCreated( this );
} }
@ -1004,6 +1047,10 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return def; return def;
} }
public boolean containsFetchProfileDefition(String name) {
return fetchProfiles.containsKey( name );
}
public Set getDefinedFilterNames() { public Set getDefinedFilterNames() {
return filters.keySet(); return filters.keySet();
} }
@ -1061,6 +1108,14 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return entityNotFoundDelegate; return entityNotFoundDelegate;
} }
public SQLFunctionRegistry getSqlFunctionRegistry() {
return sqlFunctionRegistry;
}
public FetchProfile getFetchProfile(String name) {
return ( FetchProfile ) fetchProfiles.get( name );
}
/** /**
* Custom serialization hook used during Session serialization. * Custom serialization hook used during Session serialization.
* *
@ -1102,8 +1157,4 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
} }
return ( SessionFactoryImpl ) result; return ( SessionFactoryImpl ) result;
} }
public SQLFunctionRegistry getSqlFunctionRegistry() {
return sqlFunctionRegistry;
}
} }

View File

@ -66,6 +66,7 @@ import org.hibernate.SessionFactory;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.TransientObjectException; import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException; import org.hibernate.UnresolvableObjectException;
import org.hibernate.UnknownProfileException;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.ActionQueue; import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.CollectionEntry; import org.hibernate.engine.CollectionEntry;
@ -76,6 +77,7 @@ import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.StatefulPersistenceContext; import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.engine.Status; import org.hibernate.engine.Status;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.query.FilterQueryPlan; import org.hibernate.engine.query.FilterQueryPlan;
import org.hibernate.engine.query.HQLQueryPlan; import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan; import org.hibernate.engine.query.NativeSQLQueryPlan;
@ -167,10 +169,8 @@ public final class SessionImpl extends AbstractSessionImpl
private transient boolean flushBeforeCompletionEnabled; private transient boolean flushBeforeCompletionEnabled;
private transient boolean autoCloseSessionEnabled; private transient boolean autoCloseSessionEnabled;
private transient ConnectionReleaseMode connectionReleaseMode; private transient ConnectionReleaseMode connectionReleaseMode;
private transient String fetchProfile;
private transient Map enabledFilters = new HashMap(); private transient LoadQueryInfluencers loadQueryInfluencers;
private transient Session rootSession; private transient Session rootSession;
private transient Map childSessionsByEntityMode; private transient Map childSessionsByEntityMode;
@ -195,6 +195,8 @@ public final class SessionImpl extends AbstractSessionImpl
this.autoCloseSessionEnabled = false; this.autoCloseSessionEnabled = false;
this.connectionReleaseMode = null; this.connectionReleaseMode = null;
loadQueryInfluencers = new LoadQueryInfluencers( factory );
if ( factory.getStatistics().isStatisticsEnabled() ) { if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().openSession(); factory.getStatisticsImplementor().openSession();
} }
@ -239,6 +241,8 @@ public final class SessionImpl extends AbstractSessionImpl
this.connectionReleaseMode = connectionReleaseMode; this.connectionReleaseMode = connectionReleaseMode;
this.jdbcContext = new JDBCContext( this, connection, interceptor ); this.jdbcContext = new JDBCContext( this, connection, interceptor );
loadQueryInfluencers = new LoadQueryInfluencers( factory );
if ( factory.getStatistics().isStatisticsEnabled() ) { if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().openSession(); factory.getStatisticsImplementor().openSession();
} }
@ -1048,75 +1052,6 @@ public final class SessionImpl extends AbstractSessionImpl
flush(); 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 * Retrieve a list of persistent objects using a hibernate query
@ -1432,7 +1367,7 @@ public final class SessionImpl extends AbstractSessionImpl
return listFilter( collection, filter, new QueryParameters( new Type[]{null, type}, new Object[]{null, value} ) ); 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 { throws HibernateException {
Object[] vals = new Object[values.length + 1]; Object[] vals = new Object[values.length + 1];
Type[] typs = new Type[types.length + 1]; Type[] typs = new Type[types.length + 1];
@ -1491,7 +1426,7 @@ public final class SessionImpl extends AbstractSessionImpl
return plan; return plan;
} }
public List listFilter(Object collection, String filter, QueryParameters queryParameters) public List listFilter(Object collection, String filter, QueryParameters queryParameters)
throws HibernateException { throws HibernateException {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
@ -1511,7 +1446,7 @@ public final class SessionImpl extends AbstractSessionImpl
return results; return results;
} }
public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters)
throws HibernateException { throws HibernateException {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
@ -1552,7 +1487,7 @@ public final class SessionImpl extends AbstractSessionImpl
factory, factory,
criteria, criteria,
entityName, entityName,
getEnabledFilters() getLoadQueryInfluencers()
); );
autoFlushIfRequired( loader.getQuerySpaces() ); autoFlushIfRequired( loader.getQuerySpaces() );
dontFlushFromFind++; dontFlushFromFind++;
@ -1579,7 +1514,7 @@ public final class SessionImpl extends AbstractSessionImpl
factory, factory,
criteria, criteria,
implementors[i], implementors[i],
getEnabledFilters() getLoadQueryInfluencers()
); );
spaces.addAll( loaders[i].getQuerySpaces() ); spaces.addAll( loaders[i].getQuerySpaces() );
@ -1680,7 +1615,7 @@ public final class SessionImpl extends AbstractSessionImpl
); );
} }
public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters)
throws HibernateException { throws HibernateException {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
@ -1734,7 +1669,7 @@ public final class SessionImpl extends AbstractSessionImpl
return factory; return factory;
} }
public void initializeCollection(PersistentCollection collection, boolean writing) public void initializeCollection(PersistentCollection collection, boolean writing)
throws HibernateException { throws HibernateException {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
@ -1882,23 +1817,107 @@ public final class SessionImpl extends AbstractSessionImpl
// nothing to do in a stateful session // nothing to do in a stateful session
} }
public String getFetchProfile() {
checkTransactionSynchStatus();
return fetchProfile;
}
public JDBCContext getJDBCContext() { public JDBCContext getJDBCContext() {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
return jdbcContext; return jdbcContext;
} }
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 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) { public void setFetchProfile(String fetchProfile) {
errorIfClosed(); errorIfClosed();
checkTransactionSynchStatus(); 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() { private void checkTransactionSynchStatus() {
if ( jdbcContext != null && !isClosed() ) { if ( jdbcContext != null && !isClosed() ) {
jdbcContext.registerSynchronizationIfPossible(); jdbcContext.registerSynchronizationIfPossible();
@ -1923,7 +1942,6 @@ public final class SessionImpl extends AbstractSessionImpl
cacheMode = CacheMode.parse( ( String ) ois.readObject() ); cacheMode = CacheMode.parse( ( String ) ois.readObject() );
flushBeforeCompletionEnabled = ois.readBoolean(); flushBeforeCompletionEnabled = ois.readBoolean();
autoCloseSessionEnabled = ois.readBoolean(); autoCloseSessionEnabled = ois.readBoolean();
fetchProfile = ( String ) ois.readObject();
interceptor = ( Interceptor ) ois.readObject(); interceptor = ( Interceptor ) ois.readObject();
factory = SessionFactoryImpl.deserialize( ois ); factory = SessionFactoryImpl.deserialize( ois );
@ -1936,12 +1954,13 @@ public final class SessionImpl extends AbstractSessionImpl
persistenceContext = StatefulPersistenceContext.deserialize( ois, this ); persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
actionQueue = ActionQueue.deserialize( ois, this ); actionQueue = ActionQueue.deserialize( ois, this );
enabledFilters = ( Map ) ois.readObject(); loadQueryInfluencers = ( LoadQueryInfluencers ) ois.readObject();
childSessionsByEntityMode = ( Map ) ois.readObject(); childSessionsByEntityMode = ( Map ) ois.readObject();
Iterator iter = enabledFilters.values().iterator(); Iterator iter = loadQueryInfluencers.getEnabledFilters().values().iterator();
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
( ( FilterImpl ) iter.next() ).afterDeserialize(factory); ( ( FilterImpl ) iter.next() ).afterDeserialize( factory );
} }
if ( isRootSession && childSessionsByEntityMode != null ) { if ( isRootSession && childSessionsByEntityMode != null ) {
@ -1975,7 +1994,6 @@ public final class SessionImpl extends AbstractSessionImpl
oos.writeObject( cacheMode.toString() ); oos.writeObject( cacheMode.toString() );
oos.writeBoolean( flushBeforeCompletionEnabled ); oos.writeBoolean( flushBeforeCompletionEnabled );
oos.writeBoolean( autoCloseSessionEnabled ); oos.writeBoolean( autoCloseSessionEnabled );
oos.writeObject( fetchProfile );
// we need to writeObject() on this since interceptor is user defined // we need to writeObject() on this since interceptor is user defined
oos.writeObject( interceptor ); oos.writeObject( interceptor );
@ -1989,7 +2007,7 @@ public final class SessionImpl extends AbstractSessionImpl
actionQueue.serialize( oos ); actionQueue.serialize( oos );
// todo : look at optimizing these... // todo : look at optimizing these...
oos.writeObject( enabledFilters ); oos.writeObject( loadQueryInfluencers );
oos.writeObject( childSessionsByEntityMode ); oos.writeObject( childSessionsByEntityMode );
} }
} }

View File

@ -57,6 +57,7 @@ import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.StatefulPersistenceContext; import org.hibernate.engine.StatefulPersistenceContext;
import org.hibernate.engine.Versioning; import org.hibernate.engine.Versioning;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.engine.query.HQLQueryPlan; import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan; import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification; import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
@ -527,12 +528,12 @@ public class StatelessSessionImpl extends AbstractSessionImpl
errorIfClosed(); errorIfClosed();
String entityName = criteria.getEntityOrClassName(); String entityName = criteria.getEntityOrClassName();
CriteriaLoader loader = new CriteriaLoader( CriteriaLoader loader = new CriteriaLoader(
getOuterJoinLoadable(entityName), getOuterJoinLoadable( entityName ),
factory, factory,
criteria, criteria,
entityName, entityName,
getEnabledFilters() getLoadQueryInfluencers()
); );
return loader.scroll(this, scrollMode); return loader.scroll(this, scrollMode);
} }
@ -548,7 +549,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl
factory, factory,
criteria, criteria,
implementors[i], implementors[i],
getEnabledFilters() getLoadQueryInfluencers()
); );
} }
@ -623,6 +624,10 @@ public class StatelessSessionImpl extends AbstractSessionImpl
return jdbcContext; return jdbcContext;
} }
public LoadQueryInfluencers getLoadQueryInfluencers() {
return null;
}
public void setFetchProfile(String name) {} public void setFetchProfile(String name) {}
public void afterTransactionBegin(Transaction tx) {} public void afterTransactionBegin(Transaction tx) {}

View File

@ -26,13 +26,16 @@ package org.hibernate.loader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Iterator;
import org.hibernate.FetchMode; import org.hibernate.FetchMode;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.CascadeStyle; import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.SessionFactoryImplementor; 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.Loadable;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinFragment;
@ -51,55 +54,60 @@ public abstract class AbstractEntityJoinWalker extends JoinWalker {
private final OuterJoinLoadable persister; private final OuterJoinLoadable persister;
private final String alias; private final String alias;
public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters) { public AbstractEntityJoinWalker(
this( persister, factory, enabledFilters, null ); OuterJoinLoadable persister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
this( persister, factory, loadQueryInfluencers, null );
} }
public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters, String alias) { public AbstractEntityJoinWalker(
super( factory, enabledFilters ); OuterJoinLoadable persister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers,
String alias) {
super( factory, loadQueryInfluencers );
this.persister = persister; this.persister = persister;
this.alias = ( alias == null ) ? generateRootAlias( persister.getEntityName() ) : alias; this.alias = ( alias == null ) ? generateRootAlias( persister.getEntityName() ) : alias;
} }
protected final void initAll( protected final void initAll(
final String whereString, final String whereString,
final String orderByString, final String orderByString,
final LockMode lockMode) final LockMode lockMode) throws MappingException {
throws MappingException {
walkEntityTree( persister, getAlias() ); walkEntityTree( persister, getAlias() );
List allAssociations = new ArrayList(); List allAssociations = new ArrayList();
allAssociations.addAll(associations); allAssociations.addAll(associations);
allAssociations.add( new OuterJoinableAssociation( allAssociations.add(
persister.getEntityType(), new OuterJoinableAssociation(
null, persister.getEntityType(),
null, null,
alias, null,
JoinFragment.LEFT_OUTER_JOIN, alias,
getFactory(), JoinFragment.LEFT_OUTER_JOIN,
CollectionHelper.EMPTY_MAP getFactory(),
) ); CollectionHelper.EMPTY_MAP
)
);
initPersisters(allAssociations, lockMode); initPersisters(allAssociations, lockMode);
initStatementString( whereString, orderByString, lockMode); initStatementString( whereString, orderByString, lockMode);
} }
protected final void initProjection( protected final void initProjection(
final String projectionString, final String projectionString,
final String whereString, final String whereString,
final String orderByString, final String orderByString,
final String groupByString, final String groupByString,
final LockMode lockMode) final LockMode lockMode) throws MappingException {
throws MappingException {
walkEntityTree( persister, getAlias() ); walkEntityTree( persister, getAlias() );
persisters = new Loadable[0]; persisters = new Loadable[0];
initStatementString(projectionString, whereString, orderByString, groupByString, lockMode); initStatementString(projectionString, whereString, orderByString, groupByString, lockMode);
} }
private void initStatementString( private void initStatementString(
final String condition, final String condition,
final String orderBy, final String orderBy,
final LockMode lockMode) final LockMode lockMode) throws MappingException {
throws MappingException {
initStatementString(null, condition, orderBy, "", lockMode); initStatementString(null, condition, orderBy, "", lockMode);
} }
@ -149,7 +157,33 @@ public abstract class AbstractEntityJoinWalker extends JoinWalker {
* The superclass deliberately excludes collections * The superclass deliberately excludes collections
*/ */
protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) { 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(); public abstract String getComment();

View File

@ -29,7 +29,6 @@ import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hibernate.FetchMode; import org.hibernate.FetchMode;
@ -39,6 +38,9 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.engine.CascadeStyle; import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.JoinHelper; import org.hibernate.engine.JoinHelper;
import org.hibernate.engine.SessionFactoryImplementor; 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.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
@ -69,7 +71,7 @@ public class JoinWalker {
private final SessionFactoryImplementor factory; private final SessionFactoryImplementor factory;
protected final List associations = new ArrayList(); protected final List associations = new ArrayList();
private final Set visitedAssociationKeys = new HashSet(); private final Set visitedAssociationKeys = new HashSet();
private final Map enabledFilters; private final LoadQueryInfluencers loadQueryInfluencers;
protected String[] suffixes; protected String[] suffixes;
protected String[] collectionSuffixes; protected String[] collectionSuffixes;
@ -81,6 +83,14 @@ public class JoinWalker {
protected String[] aliases; protected String[] aliases;
protected LockMode[] lockModeArray; protected LockMode[] lockModeArray;
protected String sql; protected String sql;
protected JoinWalker(
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
this.factory = factory;
this.loadQueryInfluencers = loadQueryInfluencers;
}
public String[] getCollectionSuffixes() { public String[] getCollectionSuffixes() {
return collectionSuffixes; return collectionSuffixes;
@ -169,14 +179,9 @@ public class JoinWalker {
protected Dialect getDialect() { protected Dialect getDialect() {
return factory.getDialect(); return factory.getDialect();
} }
protected Map getEnabledFilters() {
return enabledFilters;
}
protected JoinWalker(SessionFactoryImplementor factory, Map enabledFilters) { public LoadQueryInfluencers getLoadQueryInfluencers() {
this.factory = factory; return loadQueryInfluencers;
this.enabledFilters = enabledFilters;
} }
/** /**
@ -184,15 +189,13 @@ public class JoinWalker {
* of associations to be fetched by outerjoin (if necessary) * of associations to be fetched by outerjoin (if necessary)
*/ */
private void addAssociationToJoinTreeIfNecessary( private void addAssociationToJoinTreeIfNecessary(
final AssociationType type, final AssociationType type,
final String[] aliasedLhsColumns, final String[] aliasedLhsColumns,
final String alias, final String alias,
final String path, final String path,
int currentDepth, int currentDepth,
final int joinType) final int joinType) throws MappingException {
throws MappingException { if ( joinType >= 0 ) {
if (joinType>=0) {
addAssociationToJoinTree( addAssociationToJoinTree(
type, type,
aliasedLhsColumns, aliasedLhsColumns,
@ -200,9 +203,8 @@ public class JoinWalker {
path, path,
currentDepth, currentDepth,
joinType joinType
); );
} }
} }
/** /**
@ -210,35 +212,37 @@ public class JoinWalker {
* of associations to be fetched by outerjoin * of associations to be fetched by outerjoin
*/ */
private void addAssociationToJoinTree( private void addAssociationToJoinTree(
final AssociationType type, final AssociationType type,
final String[] aliasedLhsColumns, final String[] aliasedLhsColumns,
final String alias, final String alias,
final String path, String path,
final int currentDepth, final int currentDepth,
final int joinType) final int joinType) throws MappingException {
throws MappingException {
Joinable joinable = type.getAssociatedJoinable( getFactory() ); Joinable joinable = type.getAssociatedJoinable( getFactory() );
String subalias = generateTableAlias( // important to generate alias based on size of association collection
associations.size()+1, //before adding to collection! // *before* adding this join to that collection
path, String subalias = generateTableAlias( associations.size() + 1, path, joinable );
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( OuterJoinableAssociation assoc = new OuterJoinableAssociation(
type, type,
alias, alias,
aliasedLhsColumns, aliasedLhsColumns,
subalias, subalias,
joinType, joinType,
getFactory(), getFactory(),
enabledFilters loadQueryInfluencers.getEnabledFilters()
); );
assoc.validateJoin(path); assoc.validateJoin( path );
associations.add(assoc); associations.add( assoc );
int nextDepth = currentDepth+1; int nextDepth = currentDepth + 1;
// path = "";
if ( !joinable.isCollection() ) { if ( !joinable.isCollection() ) {
if (joinable instanceof OuterJoinLoadable) { if (joinable instanceof OuterJoinLoadable) {
walkEntityTree( walkEntityTree(
@ -263,11 +267,19 @@ public class JoinWalker {
} }
/** /**
* 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) protected final void walkEntityTree(
throws MappingException { OuterJoinLoadable persister,
walkEntityTree(persister, alias, "", 0); String alias) throws MappingException {
walkEntityTree( persister, alias, "", 0 );
} }
/** /**
@ -344,38 +356,49 @@ public class JoinWalker {
} }
/** /**
* 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( private void walkEntityAssociationTree(
final AssociationType associationType, final AssociationType associationType,
final OuterJoinLoadable persister, final OuterJoinLoadable persister,
final int propertyNumber, final int propertyNumber,
final String alias, final String alias,
final String path, final String path,
final boolean nullable, final boolean nullable,
final int currentDepth) final int currentDepth) throws MappingException {
throws MappingException {
String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames( String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames(
associationType, alias, propertyNumber, persister, getFactory() associationType, alias, propertyNumber, persister, getFactory()
); );
String[] lhsColumns = JoinHelper.getLHSColumnNames( String[] lhsColumns = JoinHelper.getLHSColumnNames(
associationType, propertyNumber, persister, getFactory() associationType, propertyNumber, persister, getFactory()
); );
String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister); String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister);
String subpath = subPath( path, persister.getSubclassPropertyName(propertyNumber) ); String subpath = subPath( path, persister.getSubclassPropertyName(propertyNumber) );
int joinType = getJoinType( int joinType = getJoinType(
associationType, persister,
persister.getFetchMode(propertyNumber),
subpath, subpath,
propertyNumber,
associationType,
persister.getFetchMode( propertyNumber ),
persister.getCascadeStyle( propertyNumber ),
lhsTable, lhsTable,
lhsColumns, lhsColumns,
nullable, nullable,
currentDepth, currentDepth
persister.getCascadeStyle(propertyNumber) );
);
addAssociationToJoinTreeIfNecessary( addAssociationToJoinTreeIfNecessary(
associationType, associationType,
aliasedLhsColumns, aliasedLhsColumns,
@ -383,27 +406,110 @@ public class JoinWalker {
subpath, subpath,
currentDepth, currentDepth,
joinType joinType
); );
} }
/** /**
* For an entity class, add to a list of associations to be fetched * Determine the appropriate type of join (if any) to use to fetch the
* by outerjoin * 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 ??
*/ */
private final void walkEntityTree( protected int getJoinType(
final OuterJoinLoadable persister, OuterJoinLoadable persister,
final String alias, final String path,
final String path, int propertyNumber,
final int currentDepth) AssociationType associationType,
throws MappingException { 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
);
}
/**
* 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 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(); int n = persister.countSubclassProperties();
for ( int i=0; i<n; i++ ) { for ( int i = 0; i < n; i++ ) {
Type type = persister.getSubclassPropertyType(i); Type type = persister.getSubclassPropertyType(i);
if ( type.isAssociationType() ) { if ( type.isAssociationType() ) {
walkEntityAssociationTree( walkEntityAssociationTree(
(AssociationType) type, ( AssociationType ) type,
persister, persister,
i, i,
alias, alias,
@ -414,7 +520,7 @@ public class JoinWalker {
} }
else if ( type.isComponentType() ) { else if ( type.isComponentType() ) {
walkComponentTree( walkComponentTree(
(AbstractComponentType) type, ( AbstractComponentType ) type,
i, i,
0, 0,
persister, persister,
@ -428,28 +534,34 @@ public class JoinWalker {
/** /**
* For a component, add to a list of associations to be fetched by outerjoin * 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( private void walkComponentTree(
final AbstractComponentType componentType, final AbstractComponentType componentType,
final int propertyNumber, final int propertyNumber,
int begin, int begin,
final OuterJoinLoadable persister, final OuterJoinLoadable persister,
final String alias, final String alias,
final String path, final String path,
final int currentDepth final int currentDepth) throws MappingException {
) throws MappingException {
Type[] types = componentType.getSubtypes(); Type[] types = componentType.getSubtypes();
String[] propertyNames = componentType.getPropertyNames(); String[] propertyNames = componentType.getPropertyNames();
for ( int i=0; i <types.length; i++ ) { for ( int i = 0; i < types.length; i++ ) {
if ( types[i].isAssociationType() ) { if ( types[i].isAssociationType() ) {
AssociationType associationType = (AssociationType) types[i]; AssociationType associationType = (AssociationType) types[i];
String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames( String[] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames(
associationType, alias, propertyNumber, begin, persister, getFactory() associationType, alias, propertyNumber, begin, persister, getFactory()
); );
String[] lhsColumns = JoinHelper.getLHSColumnNames( String[] lhsColumns = JoinHelper.getLHSColumnNames(
associationType, propertyNumber, begin, persister, getFactory() associationType, propertyNumber, begin, persister, getFactory()
); );
@ -458,15 +570,17 @@ public class JoinWalker {
String subpath = subPath( path, propertyNames[i] ); String subpath = subPath( path, propertyNames[i] );
final boolean[] propertyNullability = componentType.getPropertyNullability(); final boolean[] propertyNullability = componentType.getPropertyNullability();
final int joinType = getJoinType( final int joinType = getJoinType(
persister,
subpath,
propertyNumber,
associationType, associationType,
componentType.getFetchMode(i), componentType.getFetchMode(i),
subpath, componentType.getCascadeStyle(i),
lhsTable, lhsTable,
lhsColumns, lhsColumns,
propertyNullability==null || propertyNullability[i], propertyNullability==null || propertyNullability[i],
currentDepth, currentDepth
componentType.getCascadeStyle(i) );
);
addAssociationToJoinTreeIfNecessary( addAssociationToJoinTreeIfNecessary(
associationType, associationType,
aliasedLhsColumns, aliasedLhsColumns,
@ -474,23 +588,22 @@ public class JoinWalker {
subpath, subpath,
currentDepth, currentDepth,
joinType joinType
); );
} }
else if ( types[i].isComponentType() ) { else if ( types[i].isComponentType() ) {
String subpath = subPath( path, propertyNames[i] ); String subpath = subPath( path, propertyNames[i] );
walkComponentTree( walkComponentTree(
(AbstractComponentType) types[i], ( AbstractComponentType ) types[i],
propertyNumber, propertyNumber,
begin, begin,
persister, persister,
alias, alias,
subpath, subpath,
currentDepth currentDepth
); );
} }
begin += types[i].getColumnSpan( getFactory() );
begin+=types[i].getColumnSpan( getFactory() );
} }
} }
@ -499,13 +612,12 @@ public class JoinWalker {
* For a composite element, add to a list of associations to be fetched by outerjoin * For a composite element, add to a list of associations to be fetched by outerjoin
*/ */
private void walkCompositeElementTree( private void walkCompositeElementTree(
final AbstractComponentType compositeType, final AbstractComponentType compositeType,
final String[] cols, final String[] cols,
final QueryableCollection persister, final QueryableCollection persister,
final String alias, final String alias,
final String path, final String path,
final int currentDepth) final int currentDepth) throws MappingException {
throws MappingException {
Type[] types = compositeType.getSubtypes(); Type[] types = compositeType.getSubtypes();
String[] propertyNames = compositeType.getPropertyNames(); String[] propertyNames = compositeType.getPropertyNames();
@ -570,33 +682,6 @@ public class JoinWalker {
} }
} }
/**
* 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 * Use an inner join if it is a non-null association and this
* is the "first" join in a series * is the "first" join in a series
@ -604,9 +689,9 @@ public class JoinWalker {
protected int getJoinType(boolean nullable, int currentDepth) { protected int getJoinType(boolean nullable, int currentDepth) {
//TODO: this is too conservative; if all preceding joins were //TODO: this is too conservative; if all preceding joins were
// also inner joins, we could use an inner join here // also inner joins, we could use an inner join here
return !nullable && currentDepth==0 ? return !nullable && currentDepth == 0
JoinFragment.INNER_JOIN : ? JoinFragment.INNER_JOIN
JoinFragment.LEFT_OUTER_JOIN; : JoinFragment.LEFT_OUTER_JOIN;
} }
protected boolean isTooDeep(int currentDepth) { protected boolean isTooDeep(int currentDepth) {
@ -654,8 +739,7 @@ public class JoinWalker {
protected String generateTableAlias( protected String generateTableAlias(
final int n, final int n,
final String path, final String path,
final Joinable joinable final Joinable joinable) {
) {
return StringHelper.generateAlias( joinable.getName(), n ); return StringHelper.generateAlias( joinable.getName(), n );
} }

View File

@ -25,10 +25,12 @@
package org.hibernate.loader; package org.hibernate.loader;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Loadable;
import org.hibernate.type.EntityType; import org.hibernate.type.EntityType;
@ -54,15 +56,17 @@ public abstract class OuterJoinLoader extends BasicLoader {
protected String[] suffixes; protected String[] suffixes;
protected String[] collectionSuffixes; protected String[] collectionSuffixes;
private Map enabledFilters; private LoadQueryInfluencers loadQueryInfluencers;
protected final Dialect getDialect() { protected final Dialect getDialect() {
return getFactory().getDialect(); return getFactory().getDialect();
} }
public OuterJoinLoader(SessionFactoryImplementor factory, Map enabledFilters) { public OuterJoinLoader(
super(factory); SessionFactoryImplementor factory,
this.enabledFilters = enabledFilters; LoadQueryInfluencers loadQueryInfluencers) {
super( factory );
this.loadQueryInfluencers = loadQueryInfluencers;
} }
protected String[] getSuffixes() { protected String[] getSuffixes() {
@ -92,9 +96,9 @@ public abstract class OuterJoinLoader extends BasicLoader {
protected LockMode[] getLockModes(Map lockModes) { protected LockMode[] getLockModes(Map lockModes) {
return lockModeArray; return lockModeArray;
} }
public Map getEnabledFilters() { public LoadQueryInfluencers getLoadQueryInfluencers() {
return enabledFilters; return loadQueryInfluencers;
} }
protected final String[] getAliases() { protected final String[] getAliases() {

View File

@ -36,6 +36,12 @@ import org.hibernate.sql.JoinFragment;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
import org.hibernate.type.EntityType; 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 { public final class OuterJoinableAssociation {
private final AssociationType joinableType; private final AssociationType joinableType;
private final Joinable joinable; private final Joinable joinable;
@ -48,14 +54,13 @@ public final class OuterJoinableAssociation {
private final Map enabledFilters; private final Map enabledFilters;
public OuterJoinableAssociation( public OuterJoinableAssociation(
AssociationType joinableType, AssociationType joinableType,
String lhsAlias, String lhsAlias,
String[] lhsColumns, String[] lhsColumns,
String rhsAlias, String rhsAlias,
int joinType, int joinType,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) Map enabledFilters) throws MappingException {
throws MappingException {
this.joinableType = joinableType; this.joinableType = joinableType;
this.lhsAlias = lhsAlias; this.lhsAlias = lhsAlias;
this.lhsColumns = lhsColumns; this.lhsColumns = lhsColumns;

View File

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

View File

@ -24,12 +24,11 @@
*/ */
package org.hibernate.loader.collection; package org.hibernate.loader.collection;
import java.util.Map;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.JoinWalker; import org.hibernate.loader.JoinWalker;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
@ -49,18 +48,16 @@ public class BasicCollectionLoader extends CollectionLoader {
public BasicCollectionLoader( public BasicCollectionLoader(
QueryableCollection collectionPersister, QueryableCollection collectionPersister,
SessionFactoryImplementor session, SessionFactoryImplementor session,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { this( collectionPersister, 1, session, loadQueryInfluencers );
this(collectionPersister, 1, session, enabledFilters);
} }
public BasicCollectionLoader( public BasicCollectionLoader(
QueryableCollection collectionPersister, QueryableCollection collectionPersister,
int batchSize, int batchSize,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { this( collectionPersister, batchSize, null, factory, loadQueryInfluencers );
this(collectionPersister, batchSize, null, factory, enabledFilters);
} }
protected BasicCollectionLoader( protected BasicCollectionLoader(
@ -68,18 +65,16 @@ public class BasicCollectionLoader extends CollectionLoader {
int batchSize, int batchSize,
String subquery, String subquery,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { super( collectionPersister, factory, loadQueryInfluencers );
super(collectionPersister, factory, enabledFilters);
JoinWalker walker = new BasicCollectionJoinWalker( JoinWalker walker = new BasicCollectionJoinWalker(
collectionPersister, collectionPersister,
batchSize, batchSize,
subquery, subquery,
factory, factory,
enabledFilters loadQueryInfluencers
); );
initFromWalker( walker ); initFromWalker( walker );
postInstantiate(); postInstantiate();

View File

@ -31,6 +31,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.Loader; import org.hibernate.loader.Loader;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
@ -77,42 +78,38 @@ public class BatchingCollectionInitializer implements CollectionInitializer {
} }
public static CollectionInitializer createBatchingOneToManyInitializer( public static CollectionInitializer createBatchingOneToManyInitializer(
final QueryableCollection persister, final QueryableCollection persister,
final int maxBatchSize, final int maxBatchSize,
final SessionFactoryImplementor factory, final SessionFactoryImplementor factory,
final Map enabledFilters) final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { if ( maxBatchSize > 1 ) {
if ( maxBatchSize>1 ) {
int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize); int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ]; Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
for ( int i=0; i<batchSizesToCreate.length; i++ ) { 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 { else {
return new OneToManyLoader(persister, factory, enabledFilters); return new OneToManyLoader( persister, factory, loadQueryInfluencers );
} }
} }
public static CollectionInitializer createBatchingCollectionInitializer( public static CollectionInitializer createBatchingCollectionInitializer(
final QueryableCollection persister, final QueryableCollection persister,
final int maxBatchSize, final int maxBatchSize,
final SessionFactoryImplementor factory, final SessionFactoryImplementor factory,
final Map enabledFilters) final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { if ( maxBatchSize > 1 ) {
if ( maxBatchSize>1 ) {
int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize); int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ]; Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
for ( int i=0; i<batchSizesToCreate.length; i++ ) { 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); return new BatchingCollectionInitializer(persister, batchSizesToCreate, loadersToCreate);
} }
else { else {
return new BasicCollectionLoader(persister, factory, enabledFilters); return new BasicCollectionLoader( persister, factory, loadQueryInfluencers );
} }
} }

View File

@ -24,9 +24,8 @@
*/ */
package org.hibernate.loader.collection; package org.hibernate.loader.collection;
import java.util.Map;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.JoinWalker; import org.hibernate.loader.JoinWalker;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
@ -40,8 +39,8 @@ import org.hibernate.util.StringHelper;
*/ */
public abstract class CollectionJoinWalker extends JoinWalker { public abstract class CollectionJoinWalker extends JoinWalker {
public CollectionJoinWalker(SessionFactoryImplementor factory, Map enabledFilters) { public CollectionJoinWalker(SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) {
super( factory, enabledFilters ); super( factory, loadQueryInfluencers );
} }
protected StringBuffer whereString(String alias, String[] columnNames, String subselect, int batchSize) { protected StringBuffer whereString(String alias, String[] columnNames, String subselect, int batchSize) {

View File

@ -25,11 +25,11 @@
package org.hibernate.loader.collection; package org.hibernate.loader.collection;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.OuterJoinLoader; import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -45,8 +45,11 @@ public class CollectionLoader extends OuterJoinLoader implements CollectionIniti
private final QueryableCollection collectionPersister; private final QueryableCollection collectionPersister;
public CollectionLoader(QueryableCollection collectionPersister, SessionFactoryImplementor factory, Map enabledFilters) { public CollectionLoader(
super( factory, enabledFilters ); QueryableCollection collectionPersister,
SessionFactoryImplementor factory,
LoadQueryInfluencers loadQueryInfluencers) {
super( factory, loadQueryInfluencers );
this.collectionPersister = collectionPersister; this.collectionPersister = collectionPersister;
} }

View File

@ -27,11 +27,11 @@ package org.hibernate.loader.collection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.BasicLoader; import org.hibernate.loader.BasicLoader;
import org.hibernate.loader.OuterJoinableAssociation; import org.hibernate.loader.OuterJoinableAssociation;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
@ -67,10 +67,8 @@ public class OneToManyJoinWalker extends CollectionJoinWalker {
int batchSize, int batchSize,
String subquery, String subquery,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { super( factory, loadQueryInfluencers );
super(factory, enabledFilters);
this.oneToManyPersister = oneToManyPersister; this.oneToManyPersister = oneToManyPersister;
@ -93,7 +91,6 @@ public class OneToManyJoinWalker extends CollectionJoinWalker {
initPersisters(allAssociations, LockMode.NONE); initPersisters(allAssociations, LockMode.NONE);
initStatementString(elementPersister, alias, batchSize, subquery); initStatementString(elementPersister, alias, batchSize, subquery);
} }
private void initStatementString( private void initStatementString(
@ -115,7 +112,7 @@ public class OneToManyJoinWalker extends CollectionJoinWalker {
subquery, subquery,
batchSize batchSize
); );
String filter = oneToManyPersister.filterFragment( alias, getEnabledFilters() ); String filter = oneToManyPersister.filterFragment( alias, getLoadQueryInfluencers().getEnabledFilters() );
whereString.insert( 0, StringHelper.moveAndToBeginning(filter) ); whereString.insert( 0, StringHelper.moveAndToBeginning(filter) );
JoinFragment ojf = mergeOuterJoins(associations); JoinFragment ojf = mergeOuterJoins(associations);

View File

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

View File

@ -35,6 +35,7 @@ import org.hibernate.engine.EntityKey;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -57,10 +58,8 @@ public class SubselectCollectionLoader extends BasicCollectionLoader {
QueryParameters queryParameters, QueryParameters queryParameters,
Map namedParameterLocMap, Map namedParameterLocMap,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { super( persister, 1, subquery, factory, loadQueryInfluencers );
super(persister, 1, subquery, factory, enabledFilters);
keys = new Serializable[ entityKeys.size() ]; keys = new Serializable[ entityKeys.size() ];
Iterator iter = entityKeys.iterator(); Iterator iter = entityKeys.iterator();
@ -77,7 +76,7 @@ public class SubselectCollectionLoader extends BasicCollectionLoader {
} }
public void initialize(Serializable id, SessionImplementor session) public void initialize(Serializable id, SessionImplementor session)
throws HibernateException { throws HibernateException {
loadCollectionSubselect( loadCollectionSubselect(
session, session,
keys, keys,
@ -85,7 +84,7 @@ public class SubselectCollectionLoader extends BasicCollectionLoader {
types, types,
namedParameters, namedParameters,
getKeyType() getKeyType()
); );
} }
public int[] getNamedParameterLocs(String name) { public int[] getNamedParameterLocs(String name) {

View File

@ -35,6 +35,7 @@ import org.hibernate.engine.EntityKey;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -57,10 +58,8 @@ public class SubselectOneToManyLoader extends OneToManyLoader {
QueryParameters queryParameters, QueryParameters queryParameters,
Map namedParameterLocMap, Map namedParameterLocMap,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { super( persister, 1, subquery, factory, loadQueryInfluencers );
super(persister, 1, subquery, factory, enabledFilters);
keys = new Serializable[ entityKeys.size() ]; keys = new Serializable[ entityKeys.size() ];
Iterator iter = entityKeys.iterator(); Iterator iter = entityKeys.iterator();
@ -73,11 +72,9 @@ public class SubselectOneToManyLoader extends OneToManyLoader {
this.types = queryParameters.getFilteredPositionalParameterTypes(); this.types = queryParameters.getFilteredPositionalParameterTypes();
this.values = queryParameters.getFilteredPositionalParameterValues(); this.values = queryParameters.getFilteredPositionalParameterValues();
this.namedParameterLocMap = namedParameterLocMap; this.namedParameterLocMap = namedParameterLocMap;
} }
public void initialize(Serializable id, SessionImplementor session) public void initialize(Serializable id, SessionImplementor session) throws HibernateException {
throws HibernateException {
loadCollectionSubselect( loadCollectionSubselect(
session, session,
keys, keys,
@ -85,7 +82,7 @@ public class SubselectOneToManyLoader extends OneToManyLoader {
types, types,
namedParameters, namedParameters,
getKeyType() getKeyType()
); );
} }
public int[] getNamedParameterLocs(String name) { public int[] getNamedParameterLocs(String name) {

View File

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

View File

@ -30,7 +30,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Iterator;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
@ -41,6 +40,7 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.engine.QueryParameters; import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.impl.CriteriaImpl; import org.hibernate.impl.CriteriaImpl;
import org.hibernate.loader.OuterJoinLoader; import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
@ -75,9 +75,8 @@ public class CriteriaLoader extends OuterJoinLoader {
final SessionFactoryImplementor factory, final SessionFactoryImplementor factory,
final CriteriaImpl criteria, final CriteriaImpl criteria,
final String rootEntityName, final String rootEntityName,
final Map enabledFilters) final LoadQueryInfluencers loadQueryInfluencers) throws HibernateException {
throws HibernateException { super( factory, loadQueryInfluencers );
super(factory, enabledFilters);
translator = new CriteriaQueryTranslator( translator = new CriteriaQueryTranslator(
factory, factory,
@ -94,7 +93,7 @@ public class CriteriaLoader extends OuterJoinLoader {
factory, factory,
criteria, criteria,
rootEntityName, rootEntityName,
enabledFilters loadQueryInfluencers
); );
initFromWalker(walker); initFromWalker(walker);

View File

@ -29,12 +29,14 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.OuterJoinLoader; import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.transform.ResultTransformer; import org.hibernate.transform.ResultTransformer;
@ -52,8 +54,8 @@ public abstract class AbstractEntityLoader extends OuterJoinLoader
OuterJoinLoadable persister, OuterJoinLoadable persister,
Type uniqueKeyType, Type uniqueKeyType,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) { LoadQueryInfluencers loadQueryInfluencers) {
super( factory, enabledFilters ); super( factory, loadQueryInfluencers );
this.uniqueKeyType = uniqueKeyType; this.uniqueKeyType = uniqueKeyType;
this.entityName = persister.getEntityName(); this.entityName = persister.getEntityName();
this.persister = persister; this.persister = persister;

View File

@ -28,12 +28,14 @@ import java.io.Serializable;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.Loader; import org.hibernate.loader.Loader;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
@ -111,19 +113,18 @@ public class BatchingEntityLoader implements UniqueEntityLoader {
final int maxBatchSize, final int maxBatchSize,
final LockMode lockMode, final LockMode lockMode,
final SessionFactoryImplementor factory, final SessionFactoryImplementor factory,
final Map enabledFilters) final LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException {
if ( maxBatchSize>1 ) { if ( maxBatchSize>1 ) {
int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize); int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ]; Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
for ( int i=0; i<batchSizesToCreate.length; i++ ) { 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); return new BatchingEntityLoader(persister, batchSizesToCreate, loadersToCreate);
} }
else { else {
return new EntityLoader(persister, lockMode, factory, enabledFilters); return new EntityLoader(persister, lockMode, factory, loadQueryInfluencers);
} }
} }

View File

@ -30,6 +30,7 @@ import org.hibernate.MappingException;
import org.hibernate.engine.CascadeStyle; import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.CascadingAction; import org.hibernate.engine.CascadingAction;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.AbstractEntityJoinWalker; import org.hibernate.loader.AbstractEntityJoinWalker;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
@ -41,7 +42,7 @@ public class CascadeEntityJoinWalker extends AbstractEntityJoinWalker {
public CascadeEntityJoinWalker(OuterJoinLoadable persister, CascadingAction action, SessionFactoryImplementor factory) public CascadeEntityJoinWalker(OuterJoinLoadable persister, CascadingAction action, SessionFactoryImplementor factory)
throws MappingException { throws MappingException {
super( persister, factory, CollectionHelper.EMPTY_MAP ); super( persister, factory, LoadQueryInfluencers.NONE );
this.cascadeAction = action; this.cascadeAction = action;
StringBuffer whereCondition = whereString( getAlias(), persister.getIdentifierColumnNames(), 1 ) StringBuffer whereCondition = whereString( getAlias(), persister.getIdentifierColumnNames(), 1 )
//include the discriminator and class-level where, but not filters //include the discriminator and class-level where, but not filters

View File

@ -27,29 +27,28 @@ package org.hibernate.loader.entity;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.CascadingAction; import org.hibernate.engine.CascadingAction;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.JoinWalker; import org.hibernate.loader.JoinWalker;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.util.CollectionHelper;
public class CascadeEntityLoader extends AbstractEntityLoader { public class CascadeEntityLoader extends AbstractEntityLoader {
public CascadeEntityLoader( public CascadeEntityLoader(
OuterJoinLoadable persister, OuterJoinLoadable persister,
CascadingAction action, CascadingAction action,
SessionFactoryImplementor factory) SessionFactoryImplementor factory) throws MappingException {
throws MappingException {
super( super(
persister, persister,
persister.getIdentifierType(), persister.getIdentifierType(),
factory, factory,
CollectionHelper.EMPTY_MAP LoadQueryInfluencers.NONE
); );
JoinWalker walker = new CascadeEntityJoinWalker( JoinWalker walker = new CascadeEntityJoinWalker(
persister, persister,
action, action,
factory factory
); );
initFromWalker( walker ); initFromWalker( walker );
postInstantiate(); postInstantiate();

View File

@ -27,7 +27,6 @@ package org.hibernate.loader.entity;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Map;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -36,6 +35,7 @@ import org.hibernate.LockMode;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.loader.JoinWalker; import org.hibernate.loader.JoinWalker;
import org.hibernate.loader.OuterJoinLoader; import org.hibernate.loader.OuterJoinLoader;
import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.collection.QueryableCollection;
@ -61,9 +61,8 @@ public class CollectionElementLoader extends OuterJoinLoader {
public CollectionElementLoader( public CollectionElementLoader(
QueryableCollection collectionPersister, QueryableCollection collectionPersister,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { super( factory, loadQueryInfluencers );
super(factory, enabledFilters);
this.keyType = collectionPersister.getKeyType(); this.keyType = collectionPersister.getKeyType();
this.indexType = collectionPersister.getIndexType(); this.indexType = collectionPersister.getIndexType();
@ -79,7 +78,7 @@ public class CollectionElementLoader extends OuterJoinLoader {
1, 1,
LockMode.NONE, LockMode.NONE,
factory, factory,
enabledFilters loadQueryInfluencers
); );
initFromWalker( walker ); initFromWalker( walker );
@ -130,5 +129,4 @@ public class CollectionElementLoader extends OuterJoinLoader {
return true; return true;
} }
} }

View File

@ -25,13 +25,16 @@
package org.hibernate.loader.entity; package org.hibernate.loader.entity;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Iterator;
import org.hibernate.FetchMode; import org.hibernate.FetchMode;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.engine.CascadeStyle; import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.SessionFactoryImplementor; 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.loader.AbstractEntityJoinWalker;
import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
@ -52,28 +55,47 @@ public class EntityJoinWalker extends AbstractEntityJoinWalker {
int batchSize, int batchSize,
LockMode lockMode, LockMode lockMode,
SessionFactoryImplementor factory, SessionFactoryImplementor factory,
Map enabledFilters) LoadQueryInfluencers loadQueryInfluencers) throws MappingException {
throws MappingException { super( persister, factory, loadQueryInfluencers );
super(persister, factory, enabledFilters);
this.lockMode = lockMode; this.lockMode = lockMode;
StringBuffer whereCondition = whereString( getAlias(), uniqueKey, batchSize ) StringBuffer whereCondition = whereString( getAlias(), uniqueKey, batchSize )
//include the discriminator and class-level where, but not filters //include the discriminator and class-level where, but not filters
.append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) ); .append( persister.filterFragment( getAlias(), Collections.EMPTY_MAP ) );
initAll( whereCondition.toString(), "", lockMode ); initAll( whereCondition.toString(), "", lockMode );
} }
/** protected int getJoinType(
* Disable outer join fetching if this loader obtains an OuterJoinLoadable persister,
* upgrade lock mode String path,
*/ int propertyNumber,
protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config, CascadeStyle cascadeStyle) { AssociationType associationType,
return lockMode.greaterThan(LockMode.READ) ? FetchMode metadataFetchMode,
false : CascadeStyle metadataCascadeStyle,
super.isJoinedFetchEnabled(type, config, cascadeStyle); 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() { public String getComment() {

View File

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

View File

@ -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;
}
}
}

View File

@ -58,6 +58,7 @@ import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SubselectFetch; import org.hibernate.engine.SubselectFetch;
import org.hibernate.engine.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.exception.SQLExceptionConverter; import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
@ -561,7 +562,7 @@ public abstract class AbstractCollectionPersister
public void postInstantiate() throws MappingException { public void postInstantiate() throws MappingException {
initializer = queryLoaderName == null ? initializer = queryLoaderName == null ?
createCollectionInitializer( CollectionHelper.EMPTY_MAP ) : createCollectionInitializer( LoadQueryInfluencers.NONE ) :
new NamedQueryCollectionInitializer( queryLoaderName, this ); new NamedQueryCollectionInitializer( queryLoaderName, this );
} }
@ -601,7 +602,7 @@ public abstract class AbstractCollectionPersister
return initializer; return initializer;
} }
else { else {
return createCollectionInitializer( session.getEnabledFilters() ); return createCollectionInitializer( session.getLoadQueryInfluencers() );
} }
} }
@ -637,7 +638,7 @@ public abstract class AbstractCollectionPersister
protected abstract CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session); protected abstract CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session);
protected abstract CollectionInitializer createCollectionInitializer(Map enabledFilters) protected abstract CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers)
throws MappingException; throws MappingException;
public CollectionRegionAccessStrategy getCacheAccessStrategy() { public CollectionRegionAccessStrategy getCacheAccessStrategy() {

View File

@ -42,6 +42,7 @@ import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SubselectFetch; import org.hibernate.engine.SubselectFetch;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.loader.collection.BatchingCollectionInitializer; import org.hibernate.loader.collection.BatchingCollectionInitializer;
import org.hibernate.loader.collection.CollectionInitializer; import org.hibernate.loader.collection.CollectionInitializer;
@ -315,9 +316,9 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
* *
* @see org.hibernate.loader.collection.BasicCollectionLoader * @see org.hibernate.loader.collection.BasicCollectionLoader
*/ */
protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters) protected CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers)
throws MappingException { 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) { public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
@ -336,8 +337,8 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
subselect.getQueryParameters(), subselect.getQueryParameters(),
subselect.getNamedParameterLocMap(), subselect.getNamedParameterLocMap(),
session.getFactory(), session.getFactory(),
session.getEnabledFilters() session.getLoadQueryInfluencers()
); );
} }
} }

View File

@ -40,6 +40,7 @@ import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SubselectFetch; import org.hibernate.engine.SubselectFetch;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.loader.collection.BatchingCollectionInitializer; import org.hibernate.loader.collection.BatchingCollectionInitializer;
import org.hibernate.loader.collection.CollectionInitializer; import org.hibernate.loader.collection.CollectionInitializer;
@ -338,8 +339,9 @@ public class OneToManyPersister extends AbstractCollectionPersister {
* *
* @see org.hibernate.loader.collection.OneToManyLoader * @see org.hibernate.loader.collection.OneToManyLoader
*/ */
protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters) throws MappingException { protected CollectionInitializer createCollectionInitializer(LoadQueryInfluencers loadQueryInfluencers)
return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), enabledFilters ); throws MappingException {
return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), loadQueryInfluencers );
} }
public String fromJoinFragment(String alias, public String fromJoinFragment(String alias,
@ -375,12 +377,12 @@ public class OneToManyPersister extends AbstractCollectionPersister {
subselect.getQueryParameters(), subselect.getQueryParameters(),
subselect.getNamedParameterLocMap(), subselect.getNamedParameterLocMap(),
session.getFactory(), session.getFactory(),
session.getEnabledFilters() session.getLoadQueryInfluencers()
); );
} }
public Object getElementByIndex(Serializable key, Object index, SessionImplementor session, Object owner) { 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) ); .loadElement( session, key, incrementIndexByBase(index) );
} }

View File

@ -52,7 +52,6 @@ import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations; import org.hibernate.jdbc.Expectations;
import org.hibernate.jdbc.TooManyRowsAffectedException; import org.hibernate.jdbc.TooManyRowsAffectedException;
import org.hibernate.dialect.lock.LockingStrategy; import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.CacheKey; import org.hibernate.cache.CacheKey;
import org.hibernate.cache.access.EntityRegionAccessStrategy; import org.hibernate.cache.access.EntityRegionAccessStrategy;
import org.hibernate.cache.entry.CacheEntry; import org.hibernate.cache.entry.CacheEntry;
@ -69,6 +68,7 @@ import org.hibernate.engine.Versioning;
import org.hibernate.engine.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.EntityKey; import org.hibernate.engine.EntityKey;
import org.hibernate.engine.ValueInclusion; import org.hibernate.engine.ValueInclusion;
import org.hibernate.engine.LoadQueryInfluencers;
import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.PostInsertIdentifierGenerator; import org.hibernate.id.PostInsertIdentifierGenerator;
@ -109,7 +109,6 @@ import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory; import org.hibernate.type.TypeFactory;
import org.hibernate.type.VersionType; import org.hibernate.type.VersionType;
import org.hibernate.util.ArrayHelper; import org.hibernate.util.ArrayHelper;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.FilterHelper; import org.hibernate.util.FilterHelper;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
@ -196,6 +195,8 @@ public abstract class AbstractEntityPersister
// dynamic filters attached to the class-level // dynamic filters attached to the class-level
private final FilterHelper filterHelper; private final FilterHelper filterHelper;
private final Set affectingFetchProfileNames = new HashSet();
private final Map uniqueKeyLoaders = new HashMap(); private final Map uniqueKeyLoaders = new HashMap();
private final Map lockers = new HashMap(); private final Map lockers = new HashMap();
private final Map loaders = new HashMap(); private final Map loaders = new HashMap();
@ -1667,26 +1668,27 @@ public abstract class AbstractEntityPersister
} }
public Object loadByUniqueKey(String propertyName, Object uniqueKey, SessionImplementor session) public Object loadByUniqueKey(
throws HibernateException { String propertyName,
return getAppropriateUniqueKeyLoader( propertyName, session.getEnabledFilters() ) Object uniqueKey,
.loadByUniqueKey( session, uniqueKey ); SessionImplementor session) throws HibernateException {
return getAppropriateUniqueKeyLoader( propertyName, session ).loadByUniqueKey( session, uniqueKey );
} }
private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, Map enabledFilters) { private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, SessionImplementor session) {
final boolean useStaticLoader = !session.getLoadQueryInfluencers().hasEnabledFilters()
final boolean useStaticLoader = ( enabledFilters == null || enabledFilters.isEmpty() ) && !session.getLoadQueryInfluencers().hasEnabledFetchProfiles()
&& propertyName.indexOf('.')<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties && propertyName.indexOf('.')<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
if ( useStaticLoader ) { if ( useStaticLoader ) {
return (EntityLoader) uniqueKeyLoaders.get( propertyName ); return ( EntityLoader ) uniqueKeyLoaders.get( propertyName );
} }
else { else {
return createUniqueKeyLoader( return createUniqueKeyLoader(
propertyMapping.toType(propertyName), propertyMapping.toType( propertyName ),
propertyMapping.toColumns(propertyName), propertyMapping.toColumns( propertyName ),
enabledFilters session.getLoadQueryInfluencers()
); );
} }
} }
@ -1705,21 +1707,31 @@ public abstract class AbstractEntityPersister
createUniqueKeyLoader( createUniqueKeyLoader(
propertyTypes[i], propertyTypes[i],
getPropertyColumnNames( i ), getPropertyColumnNames( i ),
CollectionHelper.EMPTY_MAP LoadQueryInfluencers.NONE
) )
); );
//TODO: create uk loaders for component properties //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() ) { if ( uniqueKeyType.isEntityType() ) {
String className = ( ( EntityType ) uniqueKeyType ).getAssociatedEntityName(); String className = ( ( EntityType ) uniqueKeyType ).getAssociatedEntityName();
uniqueKeyType = getFactory().getEntityPersister( className ).getIdentifierType(); uniqueKeyType = getFactory().getEntityPersister( className ).getIdentifierType();
} }
return new EntityLoader(
return new EntityLoader( this, columns, uniqueKeyType, 1, LockMode.NONE, getFactory(), enabledFilters ); this,
columns,
uniqueKeyType,
1,
LockMode.NONE,
getFactory(),
loadQueryInfluencers
);
} }
protected String getSQLWhereString(String alias) { protected String getSQLWhereString(String alias) {
@ -1770,13 +1782,21 @@ public abstract class AbstractEntityPersister
} }
} }
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? //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 { 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 { protected boolean check(int rows, Serializable id, int tableNumber, Expectation expectation, PreparedStatement statement) throws HibernateException {
@ -3072,21 +3092,49 @@ public abstract class AbstractEntityPersister
return loader.load( id, optionalObject, session ); 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) { private UniqueEntityLoader getAppropriateLoader(LockMode lockMode, SessionImplementor session) {
final Map enabledFilters = session.getEnabledFilters();
if ( queryLoader != null ) { if ( queryLoader != null ) {
// if the user specified a custom query loader we need to that
// regardless of any other consideration
return queryLoader; return queryLoader;
} }
else if ( enabledFilters == null || enabledFilters.isEmpty() ) { else if ( isAffectedByEnabledFilters( session ) ) {
if ( session.getFetchProfile()!=null && LockMode.UPGRADE.greaterThan(lockMode) ) { // because filters affect the rows returned (because they add
return (UniqueEntityLoader) loaders.get( session.getFetchProfile() ); // restirctions) these need to be next in precendence
} return createEntityLoader( lockMode, session.getLoadQueryInfluencers() );
else { }
return (UniqueEntityLoader) loaders.get( lockMode ); 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 { else {
return createEntityLoader( lockMode, enabledFilters ); return ( UniqueEntityLoader ) loaders.get( lockMode );
} }
} }

View File

@ -108,4 +108,12 @@ public interface Loadable extends EntityPersister {
public boolean isAbstract(); 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);
} }

View File

@ -19,11 +19,12 @@ arbitrary number of queries, and import declarations of arbitrary classes.
<!ELEMENT hibernate-mapping ( <!ELEMENT hibernate-mapping (
meta*, meta*,
typedef*, typedef*,
import*, import*,
(class|subclass|joined-subclass|union-subclass)*, (class|subclass|joined-subclass|union-subclass)*,
resultset*, resultset*,
(query|sql-query)*, (query|sql-query)*,
filter-def*, filter-def*,
fetch-profile*,
database-object* database-object*
)> )>
<!ATTLIST hibernate-mapping schema CDATA #IMPLIED> <!-- default: none --> <!ATTLIST hibernate-mapping schema CDATA #IMPLIED> <!-- default: none -->
@ -78,6 +79,7 @@ arbitrary number of queries, and import declarations of arbitrary classes.
((join*,subclass*)|joined-subclass*|union-subclass*), ((join*,subclass*)|joined-subclass*|union-subclass*),
loader?,sql-insert?,sql-update?,sql-delete?, loader?,sql-insert?,sql-update?,sql-delete?,
filter*, filter*,
fetch-profile*,
resultset*, resultset*,
(query|sql-query)* (query|sql-query)*
)> )>
@ -133,6 +135,22 @@ arbitrary number of queries, and import declarations of arbitrary classes.
<!ATTLIST filter name CDATA #REQUIRED> <!ATTLIST filter name CDATA #REQUIRED>
<!ATTLIST filter condition CDATA #IMPLIED> <!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 --> <!-- A join allows some properties of a class to be persisted to a second table -->
@ -231,6 +249,7 @@ application through a property of the Java class. -->
join*, join*,
subclass*, subclass*,
loader?,sql-insert?,sql-update?,sql-delete?, loader?,sql-insert?,sql-update?,sql-delete?,
fetch-profile*,
resultset*, resultset*,
(query|sql-query)* (query|sql-query)*
)> )>
@ -263,6 +282,7 @@ application through a property of the Java class. -->
(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*, (property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*,
joined-subclass*, joined-subclass*,
loader?,sql-insert?,sql-update?,sql-delete?, loader?,sql-insert?,sql-update?,sql-delete?,
fetch-profile*,
resultset*, resultset*,
(query|sql-query)* (query|sql-query)*
)> )>
@ -298,6 +318,7 @@ application through a property of the Java class. -->
(property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*, (property|many-to-one|one-to-one|component|dynamic-component|properties|any|map|set|list|bag|idbag|array|primitive-array)*,
union-subclass*, union-subclass*,
loader?,sql-insert?,sql-update?,sql-delete?, loader?,sql-insert?,sql-update?,sql-delete?,
fetch-profile*,
resultset*, resultset*,
(query|sql-query)* (query|sql-query)*
)> )>

View File

@ -198,4 +198,8 @@ public class SessionFactoryStub implements SessionFactory {
public FilterDefinition getFilterDefinition(String filterName) throws HibernateException { public FilterDefinition getFilterDefinition(String filterName) throws HibernateException {
return getImpl().getFilterDefinition( filterName ); return getImpl().getFilterDefinition( filterName );
} }
public boolean containsFetchProfileDefition(String name) {
return getImpl().containsFetchProfileDefition( name );
}
} }

View File

@ -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();
}
}
);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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;
}
}

View File

@ -22,6 +22,7 @@ hibernate.connection.isolation ${jdbc.isolation}
hibernate.connection.pool_size 5 hibernate.connection.pool_size 5
hibernate.show_sql true
hibernate.format_sql true hibernate.format_sql true
hibernate.max_fetch_depth 5 hibernate.max_fetch_depth 5