HHH-8285 Initial JPA 2.1 entity graph support (EntityManager.find())

This commit is contained in:
Strong Liu 2013-10-31 17:22:03 +01:00
parent dd28adb1ae
commit b3871f319b
23 changed files with 1010 additions and 237 deletions

View File

@ -35,13 +35,13 @@ public interface AvailableSettings {
*
* @see #SESSION_FACTORY_NAME_IS_JNDI
*/
public static final String SESSION_FACTORY_NAME = "hibernate.session_factory_name";
String SESSION_FACTORY_NAME = "hibernate.session_factory_name";
/**
* Does the value defined by {@link #SESSION_FACTORY_NAME} represent a {@literal JNDI} namespace into which
* the {@link org.hibernate.SessionFactory} should be bound?
*/
public static final String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi";
String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi";
/**
* Names the {@link org.hibernate.engine.jdbc.connections.spi.ConnectionProvider} to use for obtaining
@ -50,17 +50,17 @@ public interface AvailableSettings {
* reference to the {@link org.hibernate.engine.jdbc.connections.spi.ConnectionProvider} implementation
* class.
*/
public static final String CONNECTION_PROVIDER ="hibernate.connection.provider_class";
String CONNECTION_PROVIDER ="hibernate.connection.provider_class";
/**
* Names the {@literal JDBC} driver class
*/
public static final String DRIVER ="hibernate.connection.driver_class";
String DRIVER ="hibernate.connection.driver_class";
/**
* Names the {@literal JDBC} connection url.
*/
public static final String URL ="hibernate.connection.url";
String URL ="hibernate.connection.url";
/**
* Names the connection user. This might mean one of 2 things in out-of-the-box Hibernate
@ -69,210 +69,210 @@ public interface AvailableSettings {
* <li>The username used to obtain a JDBC connection from a data source</li>
* </ul>
*/
public static final String USER ="hibernate.connection.username";
String USER ="hibernate.connection.username";
/**
* Names the connection password. See usage discussion on {@link #USER}
*/
public static final String PASS ="hibernate.connection.password";
String PASS ="hibernate.connection.password";
/**
* Names the {@literal JDBC} transaction isolation level
*/
public static final String ISOLATION ="hibernate.connection.isolation";
String ISOLATION ="hibernate.connection.isolation";
/**
* Names the {@literal JDBC} autocommit mode
*/
public static final String AUTOCOMMIT ="hibernate.connection.autocommit";
String AUTOCOMMIT ="hibernate.connection.autocommit";
/**
* Maximum number of inactive connections for the built-in Hibernate connection pool.
*/
public static final String POOL_SIZE ="hibernate.connection.pool_size";
String POOL_SIZE ="hibernate.connection.pool_size";
/**
* Names a {@link javax.sql.DataSource}. Can either reference a {@link javax.sql.DataSource} instance or
* a {@literal JNDI} name under which to locate the {@link javax.sql.DataSource}.
*/
public static final String DATASOURCE ="hibernate.connection.datasource";
String DATASOURCE ="hibernate.connection.datasource";
/**
* Names a prefix used to define arbitrary JDBC connection properties. These properties are passed along to
* the {@literal JDBC} provider when creating a connection.
*/
public static final String CONNECTION_PREFIX = "hibernate.connection";
String CONNECTION_PREFIX = "hibernate.connection";
/**
* Names the {@literal JNDI} {@link javax.naming.InitialContext} class.
*
* @see javax.naming.Context#INITIAL_CONTEXT_FACTORY
*/
public static final String JNDI_CLASS ="hibernate.jndi.class";
String JNDI_CLASS ="hibernate.jndi.class";
/**
* Names the {@literal JNDI} provider/connection url
*
* @see javax.naming.Context#PROVIDER_URL
*/
public static final String JNDI_URL ="hibernate.jndi.url";
String JNDI_URL ="hibernate.jndi.url";
/**
* Names a prefix used to define arbitrary {@literal JNDI} {@link javax.naming.InitialContext} properties. These
* properties are passed along to {@link javax.naming.InitialContext#InitialContext(java.util.Hashtable)}
*/
public static final String JNDI_PREFIX = "hibernate.jndi";
String JNDI_PREFIX = "hibernate.jndi";
/**
* Names the Hibernate {@literal SQL} {@link org.hibernate.dialect.Dialect} class
*/
public static final String DIALECT ="hibernate.dialect";
String DIALECT ="hibernate.dialect";
/**
* Names any additional {@link org.hibernate.engine.jdbc.dialect.spi.DialectResolver} implementations to
* register with the standard {@link org.hibernate.engine.jdbc.dialect.spi.DialectFactory}.
*/
public static final String DIALECT_RESOLVERS = "hibernate.dialect_resolvers";
String DIALECT_RESOLVERS = "hibernate.dialect_resolvers";
/**
* A default database schema (owner) name to use for unqualified tablenames
*/
public static final String DEFAULT_SCHEMA = "hibernate.default_schema";
String DEFAULT_SCHEMA = "hibernate.default_schema";
/**
* A default database catalog name to use for unqualified tablenames
*/
public static final String DEFAULT_CATALOG = "hibernate.default_catalog";
String DEFAULT_CATALOG = "hibernate.default_catalog";
/**
* Enable logging of generated SQL to the console
*/
public static final String SHOW_SQL ="hibernate.show_sql";
String SHOW_SQL ="hibernate.show_sql";
/**
* Enable formatting of SQL logged to the console
*/
public static final String FORMAT_SQL ="hibernate.format_sql";
String FORMAT_SQL ="hibernate.format_sql";
/**
* Add comments to the generated SQL
*/
public static final String USE_SQL_COMMENTS ="hibernate.use_sql_comments";
String USE_SQL_COMMENTS ="hibernate.use_sql_comments";
/**
* Maximum depth of outer join fetching
*/
public static final String MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
String MAX_FETCH_DEPTH = "hibernate.max_fetch_depth";
/**
* The default batch size for batch fetching
*/
public static final String DEFAULT_BATCH_FETCH_SIZE = "hibernate.default_batch_fetch_size";
String DEFAULT_BATCH_FETCH_SIZE = "hibernate.default_batch_fetch_size";
/**
* Use <tt>java.io</tt> streams to read / write binary data from / to JDBC
*/
public static final String USE_STREAMS_FOR_BINARY = "hibernate.jdbc.use_streams_for_binary";
String USE_STREAMS_FOR_BINARY = "hibernate.jdbc.use_streams_for_binary";
/**
* Use JDBC scrollable <tt>ResultSet</tt>s. This property is only necessary when there is
* no <tt>ConnectionProvider</tt>, ie. the user is supplying JDBC connections.
*/
public static final String USE_SCROLLABLE_RESULTSET = "hibernate.jdbc.use_scrollable_resultset";
String USE_SCROLLABLE_RESULTSET = "hibernate.jdbc.use_scrollable_resultset";
/**
* Tells the JDBC driver to attempt to retrieve row Id with the JDBC 3.0 PreparedStatement.getGeneratedKeys()
* method. In general, performance will be better if this property is set to true and the underlying
* JDBC driver supports getGeneratedKeys().
*/
public static final String USE_GET_GENERATED_KEYS = "hibernate.jdbc.use_get_generated_keys";
String USE_GET_GENERATED_KEYS = "hibernate.jdbc.use_get_generated_keys";
/**
* Gives the JDBC driver a hint as to the number of rows that should be fetched from the database
* when more rows are needed. If <tt>0</tt>, JDBC driver default settings will be used.
*/
public static final String STATEMENT_FETCH_SIZE = "hibernate.jdbc.fetch_size";
String STATEMENT_FETCH_SIZE = "hibernate.jdbc.fetch_size";
/**
* Maximum JDBC batch size. A nonzero value enables batch updates.
*/
public static final String STATEMENT_BATCH_SIZE = "hibernate.jdbc.batch_size";
String STATEMENT_BATCH_SIZE = "hibernate.jdbc.batch_size";
/**
* Select a custom batcher.
*/
public static final String BATCH_STRATEGY = "hibernate.jdbc.factory_class";
String BATCH_STRATEGY = "hibernate.jdbc.factory_class";
/**
* Should versioned data be included in batching?
*/
public static final String BATCH_VERSIONED_DATA = "hibernate.jdbc.batch_versioned_data";
String BATCH_VERSIONED_DATA = "hibernate.jdbc.batch_versioned_data";
/**
* An XSLT resource used to generate "custom" XML
*/
public static final String OUTPUT_STYLESHEET ="hibernate.xml.output_stylesheet";
String OUTPUT_STYLESHEET ="hibernate.xml.output_stylesheet";
/**
* Maximum size of C3P0 connection pool
*/
public static final String C3P0_MAX_SIZE = "hibernate.c3p0.max_size";
String C3P0_MAX_SIZE = "hibernate.c3p0.max_size";
/**
* Minimum size of C3P0 connection pool
*/
public static final String C3P0_MIN_SIZE = "hibernate.c3p0.min_size";
String C3P0_MIN_SIZE = "hibernate.c3p0.min_size";
/**
* Maximum idle time for C3P0 connection pool
*/
public static final String C3P0_TIMEOUT = "hibernate.c3p0.timeout";
String C3P0_TIMEOUT = "hibernate.c3p0.timeout";
/**
* Maximum size of C3P0 statement cache
*/
public static final String C3P0_MAX_STATEMENTS = "hibernate.c3p0.max_statements";
String C3P0_MAX_STATEMENTS = "hibernate.c3p0.max_statements";
/**
* Number of connections acquired when pool is exhausted
*/
public static final String C3P0_ACQUIRE_INCREMENT = "hibernate.c3p0.acquire_increment";
String C3P0_ACQUIRE_INCREMENT = "hibernate.c3p0.acquire_increment";
/**
* Idle time before a C3P0 pooled connection is validated
*/
public static final String C3P0_IDLE_TEST_PERIOD = "hibernate.c3p0.idle_test_period";
String C3P0_IDLE_TEST_PERIOD = "hibernate.c3p0.idle_test_period";
/**
* Proxool/Hibernate property prefix
* @deprecated Use {@link #PROXOOL_CONFIG_PREFIX} instead
*/
public static final String PROXOOL_PREFIX = "hibernate.proxool";
String PROXOOL_PREFIX = "hibernate.proxool";
/**
* Proxool property to configure the Proxool Provider using an XML (<tt>/path/to/file.xml</tt>)
*/
public static final String PROXOOL_XML = "hibernate.proxool.xml";
String PROXOOL_XML = "hibernate.proxool.xml";
/**
* Proxool property to configure the Proxool Provider using a properties file (<tt>/path/to/proxool.properties</tt>)
*/
public static final String PROXOOL_PROPERTIES = "hibernate.proxool.properties";
String PROXOOL_PROPERTIES = "hibernate.proxool.properties";
/**
* Proxool property to configure the Proxool Provider from an already existing pool (<tt>true</tt> / <tt>false</tt>)
*/
public static final String PROXOOL_EXISTING_POOL = "hibernate.proxool.existing_pool";
String PROXOOL_EXISTING_POOL = "hibernate.proxool.existing_pool";
/**
* Proxool property with the Proxool pool alias to use
* (Required for <tt>PROXOOL_EXISTING_POOL</tt>, <tt>PROXOOL_PROPERTIES</tt>, or
* <tt>PROXOOL_XML</tt>)
*/
public static final String PROXOOL_POOL_ALIAS = "hibernate.proxool.pool_alias";
String PROXOOL_POOL_ALIAS = "hibernate.proxool.pool_alias";
/**
* Enable automatic session close at end of transaction
*/
public static final String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session";
String AUTO_CLOSE_SESSION = "hibernate.transaction.auto_close_session";
/**
* Enable automatic flush during the JTA <tt>beforeCompletion()</tt> callback
*/
public static final String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion";
String FLUSH_BEFORE_COMPLETION = "hibernate.transaction.flush_before_completion";
/**
* Specifies how Hibernate should release JDBC connections.
*/
public static final String RELEASE_CONNECTIONS = "hibernate.connection.release_mode";
String RELEASE_CONNECTIONS = "hibernate.connection.release_mode";
/**
* Context scoping impl for {@link org.hibernate.SessionFactory#getCurrentSession()} processing.
*/
public static final String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";
String CURRENT_SESSION_CONTEXT_CLASS = "hibernate.current_session_context_class";
/**
* Names the implementation of {@link org.hibernate.engine.transaction.spi.TransactionFactory} to use for
* creating {@link org.hibernate.Transaction} instances
*/
public static final String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class";
String TRANSACTION_STRATEGY = "hibernate.transaction.factory_class";
/**
* Names the {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform} implementation to use for integrating
@ -280,91 +280,91 @@ public interface AvailableSettings {
* instance or the name of the {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform} implementation class
* @since 4.0
*/
public static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";
String JTA_PLATFORM = "hibernate.transaction.jta.platform";
/**
* Names the {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver} implementation to use.
* @since 4.3
*/
public static final String JTA_PLATFORM_RESOLVER = "hibernate.transaction.jta.platform_resolver";
String JTA_PLATFORM_RESOLVER = "hibernate.transaction.jta.platform_resolver";
/**
* The {@link org.hibernate.cache.spi.RegionFactory} implementation class
*/
public static final String CACHE_REGION_FACTORY = "hibernate.cache.region.factory_class";
String CACHE_REGION_FACTORY = "hibernate.cache.region.factory_class";
/**
* The <tt>CacheProvider</tt> implementation class
*/
public static final String CACHE_PROVIDER_CONFIG = "hibernate.cache.provider_configuration_file_resource_path";
String CACHE_PROVIDER_CONFIG = "hibernate.cache.provider_configuration_file_resource_path";
/**
* The <tt>CacheProvider</tt> JNDI namespace, if pre-bound to JNDI.
*/
public static final String CACHE_NAMESPACE = "hibernate.cache.jndi";
String CACHE_NAMESPACE = "hibernate.cache.jndi";
/**
* Enable the query cache (disabled by default)
*/
public static final String USE_QUERY_CACHE = "hibernate.cache.use_query_cache";
String USE_QUERY_CACHE = "hibernate.cache.use_query_cache";
/**
* The <tt>QueryCacheFactory</tt> implementation class.
*/
public static final String QUERY_CACHE_FACTORY = "hibernate.cache.query_cache_factory";
String QUERY_CACHE_FACTORY = "hibernate.cache.query_cache_factory";
/**
* Enable the second-level cache (enabled by default)
*/
public static final String USE_SECOND_LEVEL_CACHE = "hibernate.cache.use_second_level_cache";
String USE_SECOND_LEVEL_CACHE = "hibernate.cache.use_second_level_cache";
/**
* Optimize the cache for minimal puts instead of minimal gets
*/
public static final String USE_MINIMAL_PUTS = "hibernate.cache.use_minimal_puts";
String USE_MINIMAL_PUTS = "hibernate.cache.use_minimal_puts";
/**
* The <tt>CacheProvider</tt> region name prefix
*/
public static final String CACHE_REGION_PREFIX = "hibernate.cache.region_prefix";
String CACHE_REGION_PREFIX = "hibernate.cache.region_prefix";
/**
* Enable use of structured second-level cache entries
*/
public static final String USE_STRUCTURED_CACHE = "hibernate.cache.use_structured_entries";
String USE_STRUCTURED_CACHE = "hibernate.cache.use_structured_entries";
/**
* Enables the automatic eviction of a bi-directional association's collection cache when an element in the
* ManyToOne collection is added/updated/removed without properly managing the change on the OneToMany side.
*/
public static final String AUTO_EVICT_COLLECTION_CACHE = "hibernate.cache.auto_evict_collection_cache";
String AUTO_EVICT_COLLECTION_CACHE = "hibernate.cache.auto_evict_collection_cache";
/**
* Enable statistics collection
*/
public static final String GENERATE_STATISTICS = "hibernate.generate_statistics";
String GENERATE_STATISTICS = "hibernate.generate_statistics";
public static final String USE_IDENTIFIER_ROLLBACK = "hibernate.use_identifier_rollback";
String USE_IDENTIFIER_ROLLBACK = "hibernate.use_identifier_rollback";
/**
* Use bytecode libraries optimized property access
*/
public static final String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer";
String USE_REFLECTION_OPTIMIZER = "hibernate.bytecode.use_reflection_optimizer";
/**
* The classname of the HQL query parser factory
*/
public static final String QUERY_TRANSLATOR = "hibernate.query.factory_class";
String QUERY_TRANSLATOR = "hibernate.query.factory_class";
/**
* A comma-separated list of token substitutions to use when translating a Hibernate
* query to SQL
*/
public static final String QUERY_SUBSTITUTIONS = "hibernate.query.substitutions";
String QUERY_SUBSTITUTIONS = "hibernate.query.substitutions";
/**
* Should named queries be checked during startup (the default is enabled).
* <p/>
* Mainly intended for test environments.
*/
public static final String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check";
String QUERY_STARTUP_CHECKING = "hibernate.query.startup_check";
/**
* Auto export/update schema using hbm2ddl tool. Valid values are <tt>update</tt>,
* <tt>create</tt>, <tt>create-drop</tt> and <tt>validate</tt>.
*/
public static final String HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
String HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
/**
* Comma-separated names of the optional files containing SQL DML statements executed
@ -377,7 +377,7 @@ public interface AvailableSettings {
*
* The default value is <tt>/import.sql</tt>
*/
public static final String HBM2DDL_IMPORT_FILES = "hibernate.hbm2ddl.import_files";
String HBM2DDL_IMPORT_FILES = "hibernate.hbm2ddl.import_files";
/**
* {@link String} reference to {@link org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor} implementation class.
@ -385,46 +385,46 @@ public interface AvailableSettings {
*
* The default value is <tt>org.hibernate.tool.hbm2ddl.SingleLineSqlCommandExtractor</tt>.
*/
public static final String HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR = "hibernate.hbm2ddl.import_files_sql_extractor";
String HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR = "hibernate.hbm2ddl.import_files_sql_extractor";
/**
* The {@link org.hibernate.exception.spi.SQLExceptionConverter} to use for converting SQLExceptions
* to Hibernate's JDBCException hierarchy. The default is to use the configured
* {@link org.hibernate.dialect.Dialect}'s preferred SQLExceptionConverter.
*/
public static final String SQL_EXCEPTION_CONVERTER = "hibernate.jdbc.sql_exception_converter";
String SQL_EXCEPTION_CONVERTER = "hibernate.jdbc.sql_exception_converter";
/**
* Enable wrapping of JDBC result sets in order to speed up column name lookups for
* broken JDBC drivers
*/
public static final String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets";
String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets";
/**
* Enable ordering of update statements by primary key value
*/
public static final String ORDER_UPDATES = "hibernate.order_updates";
String ORDER_UPDATES = "hibernate.order_updates";
/**
* Enable ordering of insert statements for the purpose of more efficient JDBC batching.
*/
public static final String ORDER_INSERTS = "hibernate.order_inserts";
String ORDER_INSERTS = "hibernate.order_inserts";
/**
* Default precedence of null values in {@code ORDER BY} clause. Supported options: {@code none} (default),
* {@code first}, {@code last}.
*/
public static final String DEFAULT_NULL_ORDERING = "hibernate.order_by.default_null_ordering";
String DEFAULT_NULL_ORDERING = "hibernate.order_by.default_null_ordering";
/**
* The EntityMode in which set the Session opened from the SessionFactory.
*/
public static final String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode";
String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode";
/**
* Should all database identifiers be quoted.
*/
public static final String GLOBALLY_QUOTED_IDENTIFIERS = "hibernate.globally_quoted_identifiers";
String GLOBALLY_QUOTED_IDENTIFIERS = "hibernate.globally_quoted_identifiers";
/**
* Enable nullability checking.
@ -432,32 +432,32 @@ public interface AvailableSettings {
* Default to false if Bean Validation is present in the classpath and Hibernate Annotations is used,
* true otherwise.
*/
public static final String CHECK_NULLABILITY = "hibernate.check_nullability";
String CHECK_NULLABILITY = "hibernate.check_nullability";
public static final String BYTECODE_PROVIDER = "hibernate.bytecode.provider";
String BYTECODE_PROVIDER = "hibernate.bytecode.provider";
public static final String JPAQL_STRICT_COMPLIANCE= "hibernate.query.jpaql_strict_compliance";
String JPAQL_STRICT_COMPLIANCE= "hibernate.query.jpaql_strict_compliance";
/**
* When using pooled {@link org.hibernate.id.enhanced.Optimizer optimizers}, prefer interpreting the
* database value as the lower (lo) boundary. The default is to interpret it as the high boundary.
*/
public static final String PREFER_POOLED_VALUES_LO = "hibernate.id.optimizer.pooled.prefer_lo";
String PREFER_POOLED_VALUES_LO = "hibernate.id.optimizer.pooled.prefer_lo";
/**
* The maximum number of strong references maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 128.
* @deprecated in favor of {@link #QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE}
*/
@Deprecated
public static final String QUERY_PLAN_CACHE_MAX_STRONG_REFERENCES = "hibernate.query.plan_cache_max_strong_references";
String QUERY_PLAN_CACHE_MAX_STRONG_REFERENCES = "hibernate.query.plan_cache_max_strong_references";
/**
* The maximum number of soft references maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 2048.
* @deprecated in favor of {@link #QUERY_PLAN_CACHE_MAX_SIZE}
*/
@Deprecated
public static final String QUERY_PLAN_CACHE_MAX_SOFT_REFERENCES = "hibernate.query.plan_cache_max_soft_references";
String QUERY_PLAN_CACHE_MAX_SOFT_REFERENCES = "hibernate.query.plan_cache_max_soft_references";
/**
* The maximum number of entries including:
@ -469,18 +469,18 @@ public interface AvailableSettings {
*
* maintained by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 2048.
*/
public static final String QUERY_PLAN_CACHE_MAX_SIZE = "hibernate.query.plan_cache_max_size";
String QUERY_PLAN_CACHE_MAX_SIZE = "hibernate.query.plan_cache_max_size";
/**
* The maximum number of {@link org.hibernate.engine.query.spi.ParameterMetadata} maintained
* by {@link org.hibernate.engine.query.spi.QueryPlanCache}. Default is 128.
*/
public static final String QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE = "hibernate.query.plan_parameter_metadata_max_size";
String QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE = "hibernate.query.plan_parameter_metadata_max_size";
/**
* Should we not use contextual LOB creation (aka based on {@link java.sql.Connection#createBlob()} et al).
*/
public static final String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation";
String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation";
/**
* Used to define a {@link java.util.Collection} of the {@link ClassLoader} instances Hibernate should use for
@ -488,7 +488,7 @@ public interface AvailableSettings {
*
* @since 5.0
*/
public static final String CLASSLOADERS = "hibernate.classLoaders";
String CLASSLOADERS = "hibernate.classLoaders";
/**
* Names the {@link ClassLoader} used to load user application classes.
@ -497,7 +497,7 @@ public interface AvailableSettings {
* @deprecated Use {@link #CLASSLOADERS} instead
*/
@Deprecated
public static final String APP_CLASSLOADER = "hibernate.classLoader.application";
String APP_CLASSLOADER = "hibernate.classLoader.application";
/**
* Names the {@link ClassLoader} Hibernate should use to perform resource loading.
@ -505,7 +505,7 @@ public interface AvailableSettings {
* @deprecated Use {@link #CLASSLOADERS} instead
*/
@Deprecated
public static final String RESOURCES_CLASSLOADER = "hibernate.classLoader.resources";
String RESOURCES_CLASSLOADER = "hibernate.classLoader.resources";
/**
* Names the {@link ClassLoader} responsible for loading Hibernate classes. By default this is
@ -514,7 +514,7 @@ public interface AvailableSettings {
* @deprecated Use {@link #CLASSLOADERS} instead
*/
@Deprecated
public static final String HIBERNATE_CLASSLOADER = "hibernate.classLoader.hibernate";
String HIBERNATE_CLASSLOADER = "hibernate.classLoader.hibernate";
/**
* Names the {@link ClassLoader} used when Hibernate is unable to locates classes on the
@ -523,54 +523,54 @@ public interface AvailableSettings {
* @deprecated Use {@link #CLASSLOADERS} instead
*/
@Deprecated
public static final String ENVIRONMENT_CLASSLOADER = "hibernate.classLoader.environment";
String ENVIRONMENT_CLASSLOADER = "hibernate.classLoader.environment";
public static final String C3P0_CONFIG_PREFIX = "hibernate.c3p0";
String C3P0_CONFIG_PREFIX = "hibernate.c3p0";
public static final String PROXOOL_CONFIG_PREFIX = "hibernate.proxool";
String PROXOOL_CONFIG_PREFIX = "hibernate.proxool";
public static final String JMX_ENABLED = "hibernate.jmx.enabled";
public static final String JMX_PLATFORM_SERVER = "hibernate.jmx.usePlatformServer";
public static final String JMX_AGENT_ID = "hibernate.jmx.agentId";
public static final String JMX_DOMAIN_NAME = "hibernate.jmx.defaultDomain";
public static final String JMX_SF_NAME = "hibernate.jmx.sessionFactoryName";
public static final String JMX_DEFAULT_OBJ_NAME_DOMAIN = "org.hibernate.core";
String JMX_ENABLED = "hibernate.jmx.enabled";
String JMX_PLATFORM_SERVER = "hibernate.jmx.usePlatformServer";
String JMX_AGENT_ID = "hibernate.jmx.agentId";
String JMX_DOMAIN_NAME = "hibernate.jmx.defaultDomain";
String JMX_SF_NAME = "hibernate.jmx.sessionFactoryName";
String JMX_DEFAULT_OBJ_NAME_DOMAIN = "org.hibernate.core";
/**
* A configuration value key used to indicate that it is safe to cache
* {@link javax.transaction.TransactionManager} references.
* @since 4.0
*/
public static final String JTA_CACHE_TM = "hibernate.jta.cacheTransactionManager";
String JTA_CACHE_TM = "hibernate.jta.cacheTransactionManager";
/**
* A configuration value key used to indicate that it is safe to cache
* {@link javax.transaction.UserTransaction} references.
* @since 4.0
*/
public static final String JTA_CACHE_UT = "hibernate.jta.cacheUserTransaction";
String JTA_CACHE_UT = "hibernate.jta.cacheUserTransaction";
/**
* Setting used to give the name of the default {@link org.hibernate.annotations.CacheConcurrencyStrategy}
* to use when either {@link javax.persistence.Cacheable @Cacheable} or
* {@link org.hibernate.annotations.Cache @Cache} is used. {@link org.hibernate.annotations.Cache @Cache(strategy="..")} is used to override.
*/
public static final String DEFAULT_CACHE_CONCURRENCY_STRATEGY = "hibernate.cache.default_cache_concurrency_strategy";
String DEFAULT_CACHE_CONCURRENCY_STRATEGY = "hibernate.cache.default_cache_concurrency_strategy";
/**
* Setting which indicates whether or not the new {@link org.hibernate.id.IdentifierGenerator} are used
* for AUTO, TABLE and SEQUENCE.
* Default to false to keep backward compatibility.
*/
public static final String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id.new_generator_mappings";
String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id.new_generator_mappings";
/**
* Setting to identify a {@link org.hibernate.CustomEntityDirtinessStrategy} to use. May point to
* either a class name or instance.
*/
public static final String CUSTOM_ENTITY_DIRTINESS_STRATEGY = "hibernate.entity_dirtiness_strategy";
String CUSTOM_ENTITY_DIRTINESS_STRATEGY = "hibernate.entity_dirtiness_strategy";
/**
* Strategy for multi-tenancy.
@ -578,7 +578,7 @@ public interface AvailableSettings {
* @see org.hibernate.MultiTenancyStrategy
* @since 4.0
*/
public static final String MULTI_TENANT = "hibernate.multiTenancy";
String MULTI_TENANT = "hibernate.multiTenancy";
/**
* Names a {@link org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider} implementation to
@ -587,7 +587,7 @@ public interface AvailableSettings {
*
* @since 4.1
*/
public static final String MULTI_TENANT_CONNECTION_PROVIDER = "hibernate.multi_tenant_connection_provider";
String MULTI_TENANT_CONNECTION_PROVIDER = "hibernate.multi_tenant_connection_provider";
/**
* Names a {@link org.hibernate.context.spi.CurrentTenantIdentifierResolver} implementation to use.
@ -600,33 +600,33 @@ public interface AvailableSettings {
*
* @since 4.1
*/
public static final String MULTI_TENANT_IDENTIFIER_RESOLVER = "hibernate.tenant_identifier_resolver";
String MULTI_TENANT_IDENTIFIER_RESOLVER = "hibernate.tenant_identifier_resolver";
public static final String FORCE_DISCRIMINATOR_IN_SELECTS_BY_DEFAULT = "hibernate.discriminator.force_in_select";
String FORCE_DISCRIMINATOR_IN_SELECTS_BY_DEFAULT = "hibernate.discriminator.force_in_select";
public static final String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";
String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";
public static final String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy";
String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy";
/**
* Names the {@link org.hibernate.loader.BatchFetchStyle} to use. Can specify either the
* {@link org.hibernate.loader.BatchFetchStyle} name (insensitively), or a
* {@link org.hibernate.loader.BatchFetchStyle} instance.
*/
public static final String BATCH_FETCH_STYLE = "hibernate.batch_fetch_style";
String BATCH_FETCH_STYLE = "hibernate.batch_fetch_style";
/**
* Enable direct storage of entity references into the second level cache when applicable (immutable data, etc).
* Default is to not store direct references.
*/
public static final String USE_DIRECT_REFERENCE_CACHE_ENTRIES = "hibernate.cache.use_reference_entries";
String USE_DIRECT_REFERENCE_CACHE_ENTRIES = "hibernate.cache.use_reference_entries";
/**
* Enable nationalized character support on all string / clob based attribute ( string, char, clob, text etc ).
*
* Default is <clode>false</clode>.
*/
public static final String USE_NATIONALIZED_CHARACTER_DATA = "hibernate.use_nationalized_character_data";
String USE_NATIONALIZED_CHARACTER_DATA = "hibernate.use_nationalized_character_data";
/**
* A transaction can be rolled back by another thread ("tracking by thread")
@ -637,11 +637,11 @@ public interface AvailableSettings {
*
* Default is <code>true</code> (enabled).
*/
public static final String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread";
String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread";
public static final String JACC_CONTEXT_ID = "hibernate.jacc_context_id";
public static final String JACC_PREFIX = "hibernate.jacc";
public static final String JACC_ENABLED = "hibernate.jacc.enabled";
String JACC_CONTEXT_ID = "hibernate.jacc_context_id";
String JACC_PREFIX = "hibernate.jacc";
String JACC_ENABLED = "hibernate.jacc.enabled";
/**
* If enabled, allows {@link org.hibernate.tool.hbm2ddl.DatabaseMetadata} to
@ -649,7 +649,7 @@ public interface AvailableSettings {
* possibility that this would return duplicate tables (especially in
* Oracle), this is disabled by default.
*/
public static final String ENABLE_SYNONYMS = "hibernate.synonyms";
String ENABLE_SYNONYMS = "hibernate.synonyms";
/**
* Unique columns and unique keys both use unique constraints in most dialects.
@ -667,5 +667,5 @@ public interface AvailableSettings {
* {@link org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy#SKIP}:
* do not attempt to create unique constraints on a schema update
*/
public static final String UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY = "hibernate.schema_update.unique_constraint_strategy";
String UNIQUE_CONSTRAINT_SCHEMA_UPDATE_STRATEGY = "hibernate.schema_update.unique_constraint_strategy";
}

View File

@ -30,6 +30,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityGraph;
import org.hibernate.Filter;
import org.hibernate.UnknownProfileException;
import org.hibernate.internal.FilterImpl;
@ -57,6 +59,8 @@ public class LoadQueryInfluencers implements Serializable {
private String internalFetchProfile;
private final Map<String,Filter> enabledFilters;
private final Set<String> enabledFetchProfileNames;
private EntityGraph fetchGraph;
private EntityGraph loadGraph;
public LoadQueryInfluencers() {
this( null );
@ -195,4 +199,19 @@ public class LoadQueryInfluencers implements Serializable {
enabledFetchProfileNames.remove( name );
}
public EntityGraph getFetchGraph() {
return fetchGraph;
}
public void setFetchGraph(final EntityGraph fetchGraph) {
this.fetchGraph = fetchGraph;
}
public EntityGraph getLoadGraph() {
return loadGraph;
}
public void setLoadGraph(final EntityGraph loadGraph) {
this.loadGraph = loadGraph;
}
}

View File

@ -21,20 +21,15 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.graph.spi;
package org.hibernate.graph.spi;
import javax.persistence.AttributeNode;
import javax.persistence.metamodel.Attribute;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
* @author Steve Ebersole
* @author Strong Liu <stliu@hibernate.org>
*/
public interface AttributeNodeImplementor<T> extends AttributeNode<T> {
public HibernateEntityManagerFactory entityManagerFactory();
public Attribute<?,T> getAttribute();
public AttributeNodeImplementor<T> makeImmutableCopy();
}

View File

@ -21,20 +21,15 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.graph.spi;
package org.hibernate.graph.spi;
import javax.persistence.AttributeNode;
import java.util.List;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import javax.persistence.AttributeNode;
/**
* Extended contract for a "graph node" (entity-graph or sub-graph).
*
* @author Steve Ebersole
* @author Strong Liu <stliu@hibernate.org>
*/
public interface GraphNodeImplementor {
public HibernateEntityManagerFactory entityManagerFactory();
public List<AttributeNodeImplementor<?>> attributeImplementorNodes();
public List<AttributeNode<?>> attributeNodes();
List<AttributeNodeImplementor<?>> attributeImplementorNodes();
List<AttributeNode<?>> attributeNodes();
}

View File

@ -40,7 +40,10 @@ import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.loader.entity.UniqueEntityLoader;
import org.hibernate.loader.plan2.build.internal.FetchGraphLoadPlanBuildingStrategy;
import org.hibernate.loader.plan2.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan2.build.internal.LoadGraphLoadPlanBuildingStrategy;
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan2.build.spi.MetamodelDrivenLoadPlanBuilder;
import org.hibernate.loader.plan2.exec.internal.AbstractLoadPlanBasedLoader;
import org.hibernate.loader.plan2.exec.query.spi.NamedParameterContext;
@ -80,11 +83,22 @@ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlan
this.uniqueKeyType = uniqueKeyType;
this.entityName = entityPersister.getEntityName();
final FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(
factory,
buildingParameters.getQueryInfluencers(),
buildingParameters.getLockMode()
);
final LoadPlanBuildingAssociationVisitationStrategy strategy;
if ( buildingParameters.getQueryInfluencers().getFetchGraph() != null ) {
strategy = new FetchGraphLoadPlanBuildingStrategy(
factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode()
);
}
else if ( buildingParameters.getQueryInfluencers().getLoadGraph() != null ) {
strategy = new LoadGraphLoadPlanBuildingStrategy(
factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode()
);
}
else {
strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(
factory, buildingParameters.getQueryInfluencers(),buildingParameters.getLockMode()
);
}
this.plan = MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
this.staticLoadQuery = EntityLoadQueryDetails.makeForBatching(

View File

@ -0,0 +1,359 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. 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 Inc..
*
* 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.loader.plan2.build.internal;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.loader.plan2.build.spi.AbstractLoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan2.spi.EntityReturn;
import org.hibernate.loader.plan2.spi.LoadPlan;
import org.hibernate.loader.plan2.spi.Return;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.hibernate.persister.walking.spi.CollectionDefinition;
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
import org.hibernate.persister.walking.spi.CompositionDefinition;
import org.hibernate.persister.walking.spi.EntityDefinition;
import org.hibernate.persister.walking.spi.WalkingException;
/**
* Abstract strategy of building loadplan based on entity graph.
*
* The problem we're resolving here is, we have TWO trees to walk (only entity loading here):
* <ul>
* <ol>entity metadata and its associations</ol>
* <ol>entity graph and attribute nodes</ol>
* </ul>
*
* And most time, the entity graph tree is partial of entity metadata tree.
*
* So, the idea here is, we walk the entity metadata tree, just as how we build the static loadplan from mappings,
* and we try to match the node to entity graph ( and subgraph ), if there is a match, then the attribute is fetched,
* it is not, then depends on which property is used to apply this entity graph.
*
* @author Strong Liu <stliu@hibernate.org>
*/
public abstract class AbstractEntityGraphVisitationStrategy
extends AbstractLoadPlanBuildingAssociationVisitationStrategy {
private static final Logger LOG = CoreLogging.logger( AbstractEntityGraphVisitationStrategy.class );
/**
* The JPA 2.1 SPEC's Entity Graph only defines _WHEN_ to load an attribute, it doesn't define _HOW_ to load it
* So I'm here just making an assumption that when it is EAGER, then we use JOIN, and when it is LAZY, then we use SELECT.
*
* NOTE: this may be changed in the near further, though ATM I have no idea how this will be changed to :)
* -- stliu
*/
protected static final FetchStrategy DEFAULT_EAGER = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
protected static final FetchStrategy DEFAULT_LAZY = new FetchStrategy( FetchTiming.DELAYED, FetchStyle.SELECT );
protected final LoadQueryInfluencers loadQueryInfluencers;
protected final ArrayDeque<GraphNodeImplementor> graphStack = new ArrayDeque<GraphNodeImplementor>();
protected final ArrayDeque<AttributeNodeImplementor> attributeStack = new ArrayDeque<AttributeNodeImplementor>();
//the attribute nodes defined in the current graph node (entity graph or subgraph) we're working on
protected Map<String, AttributeNodeImplementor> attributeNodeImplementorMap = Collections.emptyMap();
private EntityReturn rootEntityReturn;
private final LockMode lockMode;
protected AbstractEntityGraphVisitationStrategy(
final SessionFactoryImplementor sessionFactory, final LoadQueryInfluencers loadQueryInfluencers,
final LockMode lockMode) {
super( sessionFactory );
this.loadQueryInfluencers = loadQueryInfluencers;
this.lockMode = lockMode;
}
@Override
public void start() {
super.start();
graphStack.addLast( getRootEntityGraph() );
}
@Override
public void finish() {
super.finish();
graphStack.removeLast();
//applying a little internal stack checking
if ( !graphStack.isEmpty() || !attributeStack.isEmpty() || !attributeNodeImplementorMap.isEmpty() ) {
throw new WalkingException( "Internal stack error" );
}
}
@Override
public void startingEntity(final EntityDefinition entityDefinition) {
//TODO check if the passed in entity definition is the same as the root entity graph (a.k.a they are came from same entity class)?
//this maybe the root entity graph or a sub graph.
attributeNodeImplementorMap = buildAttributeNodeMap();
super.startingEntity( entityDefinition );
}
/**
* Build "name" -- "attribute node" map from the current entity graph we're visiting.
*/
protected Map<String, AttributeNodeImplementor> buildAttributeNodeMap() {
GraphNodeImplementor graphNode = graphStack.peekLast();
List<AttributeNodeImplementor<?>> attributeNodeImplementors = graphNode.attributeImplementorNodes();
Map<String, AttributeNodeImplementor> attributeNodeImplementorMap = attributeNodeImplementors.isEmpty() ? Collections
.<String, AttributeNodeImplementor>emptyMap() : new HashMap<String, AttributeNodeImplementor>(
attributeNodeImplementors.size()
);
for ( AttributeNodeImplementor attribute : attributeNodeImplementors ) {
attributeNodeImplementorMap.put( attribute.getAttributeName(), attribute );
}
return attributeNodeImplementorMap;
}
@Override
public void finishingEntity(final EntityDefinition entityDefinition) {
attributeNodeImplementorMap = Collections.emptyMap();
super.finishingEntity( entityDefinition );
}
/**
* I'm using NULL-OBJECT pattern here, for attributes that not existing in the EntityGraph,
* a predefined NULL-ATTRIBUTE-NODE is pushed to the stack.
*
* and for an not existing sub graph, a predefined NULL-SUBGRAPH is pushed to the stack.
*
* So, whenever we're start visiting an attribute, there will be a attribute node pushed to the attribute stack,
* and a subgraph node pushed to the graph stack.
*
* when we're finish visiting an attribute, these two will be poped from each stack.
*/
@Override
public boolean startingAttribute(AttributeDefinition attributeDefinition) {
final String attrName = attributeDefinition.getName();
AttributeNodeImplementor attributeNode = NON_EXIST_ATTRIBUTE_NODE;
GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE;
//the attribute is in the EntityGraph, so, let's continue
if ( attributeNodeImplementorMap.containsKey( attrName ) ) {
attributeNode = attributeNodeImplementorMap.get( attrName );
//here we need to check if there is a subgraph (or sub key graph if it is an indexed attribute )
Map<Class, Subgraph> subGraphs = attributeNode.getSubgraphs();
Class javaType = attributeDefinition.getType().getReturnedClass();
if ( !subGraphs.isEmpty() && subGraphs.containsKey( javaType ) ) {
subGraphNode = (GraphNodeImplementor) subGraphs.get( javaType );
}
}
attributeStack.addLast( attributeNode );
graphStack.addLast( subGraphNode );
return super.startingAttribute( attributeDefinition );
}
@Override
public void finishingAttribute(final AttributeDefinition attributeDefinition) {
attributeStack.removeLast();
graphStack.removeLast();
super.finishingAttribute( attributeDefinition );
}
@Override
protected boolean handleAssociationAttribute(
final AssociationAttributeDefinition attributeDefinition) {
return super.handleAssociationAttribute( attributeDefinition );
}
@Override
protected boolean handleCompositeAttribute(
final CompositionDefinition attributeDefinition) {
return super.handleCompositeAttribute( attributeDefinition );
}
@Override
public void startingComposite(final CompositionDefinition compositionDefinition) {
super.startingComposite( compositionDefinition );
}
@Override
public void finishingComposite(final CompositionDefinition compositionDefinition) {
super.finishingComposite( compositionDefinition );
}
@Override
public void startingCollection(final CollectionDefinition collectionDefinition) {
super.startingCollection( collectionDefinition );
}
@Override
public void finishingCollection(final CollectionDefinition collectionDefinition) {
super.finishingCollection( collectionDefinition );
}
@Override
public void startingCollectionElements(
final CollectionElementDefinition elementDefinition) {
super.startingCollectionElements( elementDefinition );
}
@Override
public void finishingCollectionElements(
final CollectionElementDefinition elementDefinition) {
super.finishingCollectionElements( elementDefinition );
}
@Override
public void startingCollectionIndex(final CollectionIndexDefinition indexDefinition) {
AttributeNodeImplementor attributeNode = attributeStack.peekLast();
GraphNodeImplementor subGraphNode = NON_EXIST_SUBGRAPH_NODE;
Map<Class, Subgraph> subGraphs = attributeNode.getKeySubgraphs();
Class javaType = indexDefinition.getType().getReturnedClass();
if ( !subGraphs.isEmpty() && subGraphs.containsKey( javaType ) ) {
subGraphNode = (GraphNodeImplementor) subGraphs.get( javaType );
}
graphStack.addLast( subGraphNode );
super.startingCollectionIndex( indexDefinition );
}
@Override
public void finishingCollectionIndex(final CollectionIndexDefinition indexDefinition) {
super.finishingCollectionIndex( indexDefinition );
graphStack.removeLast();
}
@Override
protected boolean supportsRootCollectionReturns() {
return false; //entity graph doesn't support root collection.
}
@Override
protected void addRootReturn(final Return rootReturn) {
if ( this.rootEntityReturn != null ) {
throw new HibernateException( "Root return already identified" );
}
if ( !( rootReturn instanceof EntityReturn ) ) {
throw new HibernateException( "Load entity graph only supports EntityReturn" );
}
this.rootEntityReturn = (EntityReturn) rootReturn;
}
@Override
protected FetchStrategy determineFetchStrategy(
final AssociationAttributeDefinition attributeDefinition) {
return attributeStack.peekLast() != NON_EXIST_ATTRIBUTE_NODE ? DEFAULT_EAGER : resolveImplicitFetchStrategyFromEntityGraph(
attributeDefinition
);
}
protected abstract FetchStrategy resolveImplicitFetchStrategyFromEntityGraph(
final AssociationAttributeDefinition attributeDefinition);
protected FetchStrategy adjustJoinFetchIfNeeded(
AssociationAttributeDefinition attributeDefinition, FetchStrategy fetchStrategy) {
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT );
}
final Integer maxFetchDepth = sessionFactory().getSettings().getMaximumFetchDepth();
if ( maxFetchDepth != null && currentDepth() > maxFetchDepth ) {
return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT );
}
if ( attributeDefinition.getType().isCollectionType() && isTooManyCollections() ) {
// todo : have this revert to batch or subselect fetching once "sql gen redesign" is in place
return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT );
}
return fetchStrategy;
}
@Override
public LoadPlan buildLoadPlan() {
LOG.debug( "Building LoadPlan..." );
return new LoadPlanImpl( rootEntityReturn, getQuerySpaces() );
}
abstract protected GraphNodeImplementor getRootEntityGraph();
private static final AttributeNodeImplementor NON_EXIST_ATTRIBUTE_NODE = new AttributeNodeImplementor() {
@Override
public Attribute getAttribute() {
return null;
}
@Override
public AttributeNodeImplementor makeImmutableCopy() {
return this;
}
@Override
public String getAttributeName() {
return null;
}
@Override
public Map<Class, Subgraph> getSubgraphs() {
return Collections.emptyMap();
}
@Override
public Map<Class, Subgraph> getKeySubgraphs() {
return Collections.emptyMap();
}
@Override
public String toString() {
return "Mocked NON-EXIST attribute node";
}
};
private static final GraphNodeImplementor NON_EXIST_SUBGRAPH_NODE = new GraphNodeImplementor() {
@Override
public List<AttributeNodeImplementor<?>> attributeImplementorNodes() {
return Collections.EMPTY_LIST;
}
@Override
public List<AttributeNode<?>> attributeNodes() {
return Collections.EMPTY_LIST;
}
};
}

View File

@ -0,0 +1,61 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. 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 Inc..
*
* 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.loader.plan2.build.internal;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
/**
* Loadplan building strategy for {@link javax.persistence.EntityGraph} is applied in {@code javax.persistence.fetchgraph} mode.
*
* @author Strong Liu <stliu@hibernate.org>
*/
public class FetchGraphLoadPlanBuildingStrategy extends AbstractEntityGraphVisitationStrategy {
private final GraphNodeImplementor rootEntityGraph;
public FetchGraphLoadPlanBuildingStrategy(
final SessionFactoryImplementor sessionFactory, final LoadQueryInfluencers loadQueryInfluencers,
final LockMode lockMode) {
super( sessionFactory, loadQueryInfluencers, lockMode );
this.rootEntityGraph = (GraphNodeImplementor) loadQueryInfluencers.getFetchGraph();
}
@Override
protected GraphNodeImplementor getRootEntityGraph() {
return rootEntityGraph;
}
@Override
protected FetchStrategy resolveImplicitFetchStrategyFromEntityGraph(
final AssociationAttributeDefinition attributeDefinition) {
//under fetchgraph mode, according to the SPEC, all other attributes that no in entity graph are supposed to be lazily loaded
return DEFAULT_LAZY;
}
}

View File

@ -0,0 +1,71 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. 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 Inc..
*
* 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.loader.plan2.build.internal;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
/**
* Loadplan building strategy for {@link javax.persistence.EntityGraph} is applied in {@code javax.persistence.loadgraph} mode.
*
* @author Strong Liu <stliu@hibernate.org>
*/
public class LoadGraphLoadPlanBuildingStrategy extends AbstractEntityGraphVisitationStrategy {
private final GraphNodeImplementor rootEntityGraph;
public LoadGraphLoadPlanBuildingStrategy(
final SessionFactoryImplementor sessionFactory, final LoadQueryInfluencers loadQueryInfluencers,final LockMode lockMode) {
super( sessionFactory, loadQueryInfluencers , lockMode);
this.rootEntityGraph = (GraphNodeImplementor) loadQueryInfluencers.getLoadGraph();
}
@Override
protected GraphNodeImplementor getRootEntityGraph() {
return rootEntityGraph;
}
@Override
protected FetchStrategy resolveImplicitFetchStrategyFromEntityGraph(
final AssociationAttributeDefinition attributeDefinition) {
FetchStrategy fetchStrategy = attributeDefinition.determineFetchPlan(
loadQueryInfluencers,
currentPropertyPath
);
if ( fetchStrategy.getTiming() == FetchTiming.IMMEDIATE && fetchStrategy.getStyle() == FetchStyle.JOIN ) {
// see if we need to alter the join fetch to another form for any reason
fetchStrategy = adjustJoinFetchIfNeeded( attributeDefinition, fetchStrategy );
}
return fetchStrategy;
}
}

View File

@ -4031,6 +4031,11 @@ public abstract class AbstractEntityPersister
affectingFetchProfileNames.add( fetchProfileName );
}
private boolean isAffectedByEntityGraph(SessionImplementor session) {
return session.getLoadQueryInfluencers().getFetchGraph() != null || session.getLoadQueryInfluencers()
.getLoadGraph() != null;
}
private boolean isAffectedByEnabledFetchProfiles(SessionImplementor session) {
for ( String s : session.getLoadQueryInfluencers().getEnabledFetchProfileNames() ) {
if ( affectingFetchProfileNames.contains( s ) ) {
@ -4067,6 +4072,9 @@ public abstract class AbstractEntityPersister
// SQL query used for loading based on those influencers
return createEntityLoader(lockOptions, session.getLoadQueryInfluencers() );
}
else if ( isAffectedByEntityGraph( session ) ) {
return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() );
}
else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) {
return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() );
}

View File

@ -41,28 +41,28 @@ public interface AvailableSettings {
* <p/>
* See JPA 2 sections 9.4.3 and 8.2.1.4
*/
public static final String PROVIDER = "javax.persistence.provider";
String PROVIDER = "javax.persistence.provider";
/**
* The type of transactions supported by the entity managers.
* <p/>
* See JPA 2 sections 9.4.3 and 8.2.1.2
*/
public static final String TRANSACTION_TYPE = "javax.persistence.transactionType";
String TRANSACTION_TYPE = "javax.persistence.transactionType";
/**
* The JNDI name of a JTA {@link javax.sql.DataSource}.
* <p/>
* See JPA 2 sections 9.4.3 and 8.2.1.5
*/
public static final String JTA_DATASOURCE = "javax.persistence.jtaDataSource";
String JTA_DATASOURCE = "javax.persistence.jtaDataSource";
/**
* The JNDI name of a non-JTA {@link javax.sql.DataSource}.
* <p/>
* See JPA 2 sections 9.4.3 and 8.2.1.5
*/
public static final String NON_JTA_DATASOURCE = "javax.persistence.nonJtaDataSource";
String NON_JTA_DATASOURCE = "javax.persistence.nonJtaDataSource";
/**
* The name of a JDBC driver to use to connect to the database.
@ -73,7 +73,7 @@ public interface AvailableSettings {
* <p/>
* See section 8.2.1.9
*/
public static final String JDBC_DRIVER = "javax.persistence.jdbc.driver";
String JDBC_DRIVER = "javax.persistence.jdbc.driver";
/**
* The JDBC connection url to use to connect to the database.
@ -84,7 +84,7 @@ public interface AvailableSettings {
* <p/>
* See section 8.2.1.9
*/
public static final String JDBC_URL = "javax.persistence.jdbc.url";
String JDBC_URL = "javax.persistence.jdbc.url";
/**
* The JDBC connection user name.
@ -95,7 +95,7 @@ public interface AvailableSettings {
* <p/>
* See section 8.2.1.9
*/
public static final String JDBC_USER = "javax.persistence.jdbc.user";
String JDBC_USER = "javax.persistence.jdbc.user";
/**
* The JDBC connection password.
@ -106,7 +106,7 @@ public interface AvailableSettings {
* <p/>
* See JPA 2 section 8.2.1.9
*/
public static final String JDBC_PASSWORD = "javax.persistence.jdbc.password";
String JDBC_PASSWORD = "javax.persistence.jdbc.password";
/**
* Used to indicate whether second-level (what JPA terms shared cache) caching is
@ -115,7 +115,7 @@ public interface AvailableSettings {
* See JPA 2 sections 9.4.3 and 8.2.1.7
* @see javax.persistence.SharedCacheMode
*/
public static final String SHARED_CACHE_MODE = "javax.persistence.sharedCache.mode";
String SHARED_CACHE_MODE = "javax.persistence.sharedCache.mode";
/**
* NOTE : Not a valid EMF property...
@ -125,7 +125,7 @@ public interface AvailableSettings {
*
* @see javax.persistence.CacheRetrieveMode
*/
public static final String SHARED_CACHE_RETRIEVE_MODE ="javax.persistence.cache.retrieveMode";
String SHARED_CACHE_RETRIEVE_MODE ="javax.persistence.cache.retrieveMode";
/**
* NOTE : Not a valid EMF property...
@ -135,7 +135,7 @@ public interface AvailableSettings {
*
* @see javax.persistence.CacheStoreMode
*/
public static final String SHARED_CACHE_STORE_MODE ="javax.persistence.cache.storeMode";
String SHARED_CACHE_STORE_MODE ="javax.persistence.cache.storeMode";
/**
* Used to indicate what form of automatic validation is in effect as per rules defined
@ -144,52 +144,52 @@ public interface AvailableSettings {
* See JPA 2 sections 9.4.3 and 8.2.1.8
* @see javax.persistence.ValidationMode
*/
public static final String VALIDATION_MODE = "javax.persistence.validation.mode";
String VALIDATION_MODE = "javax.persistence.validation.mode";
/**
* Used to pass along any discovered validator factory.
*/
public static final String VALIDATION_FACTORY = "javax.persistence.validation.factory";
String VALIDATION_FACTORY = "javax.persistence.validation.factory";
/**
* Used to request (hint) a pessimistic lock scope.
* <p/>
* See JPA 2 sections 8.2.1.9 and 3.4.4.3
*/
public static final String LOCK_SCOPE = "javax.persistence.lock.scope";
String LOCK_SCOPE = "javax.persistence.lock.scope";
/**
* Used to request (hint) a pessimistic lock timeout (in milliseconds).
* <p/>
* See JPA 2 sections 8.2.1.9 and 3.4.4.3
*/
public static final String LOCK_TIMEOUT = "javax.persistence.lock.timeout";
String LOCK_TIMEOUT = "javax.persistence.lock.timeout";
/**
* Used to coordinate with bean validators
* <p/>
* See JPA 2 section 8.2.1.9
*/
public static final String PERSIST_VALIDATION_GROUP = "javax.persistence.validation.group.pre-persist";
String PERSIST_VALIDATION_GROUP = "javax.persistence.validation.group.pre-persist";
/**
* Used to coordinate with bean validators
* <p/>
* See JPA 2 section 8.2.1.9
*/
public static final String UPDATE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-update";
String UPDATE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-update";
/**
* Used to coordinate with bean validators
* <p/>
* See JPA 2 section 8.2.1.9
*/
public static final String REMOVE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-remove";
String REMOVE_VALIDATION_GROUP = "javax.persistence.validation.group.pre-remove";
/**
* Used to pass along the CDI BeanManager, if any, to be used.
*/
public static final String CDI_BEAN_MANAGER = "javax.persistence.bean.manager";
String CDI_BEAN_MANAGER = "javax.persistence.bean.manager";
/**
* Specifies whether schema generation commands for schema creation are to be determine based on object/relational
@ -205,7 +205,7 @@ public interface AvailableSettings {
*
* @see SchemaGenSource
*/
public static final String SCHEMA_GEN_CREATE_SOURCE = "javax.persistence.schema-generation.create-source";
String SCHEMA_GEN_CREATE_SOURCE = "javax.persistence.schema-generation.create-source";
/**
* Specifies whether schema generation commands for schema dropping are to be determine based on object/relational
@ -221,7 +221,7 @@ public interface AvailableSettings {
*
* @see SchemaGenSource
*/
public static final String SCHEMA_GEN_DROP_SOURCE = "javax.persistence.schema-generation.drop-source";
String SCHEMA_GEN_DROP_SOURCE = "javax.persistence.schema-generation.drop-source";
/**
* Specifies the CREATE script file as either a {@link java.io.Reader} configured for reading of the DDL script
@ -230,7 +230,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_CREATE_SOURCE
* @see #SCHEMA_GEN_DROP_SCRIPT_SOURCE
*/
public static final String SCHEMA_GEN_CREATE_SCRIPT_SOURCE = "javax.persistence.schema-generation.create-script-source";
String SCHEMA_GEN_CREATE_SCRIPT_SOURCE = "javax.persistence.schema-generation.create-script-source";
/**
* Specifies the DROP script file as either a {@link java.io.Reader} configured for reading of the DDL script
@ -239,7 +239,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_DROP_SOURCE
* @see #SCHEMA_GEN_CREATE_SCRIPT_SOURCE
*/
public static final String SCHEMA_GEN_DROP_SCRIPT_SOURCE = "javax.persistence.schema-generation.drop-script-source";
String SCHEMA_GEN_DROP_SCRIPT_SOURCE = "javax.persistence.schema-generation.drop-script-source";
/**
* Specifies the type of schema generation action to be taken by the persistence provider in regards to sending
@ -249,7 +249,7 @@ public interface AvailableSettings {
*
* @see SchemaGenAction
*/
public static final String SCHEMA_GEN_DATABASE_ACTION = "javax.persistence.schema-generation.database.action";
String SCHEMA_GEN_DATABASE_ACTION = "javax.persistence.schema-generation.database.action";
/**
* Specifies the type of schema generation action to be taken by the persistence provider in regards to writing
@ -259,7 +259,7 @@ public interface AvailableSettings {
*
* @see SchemaGenAction
*/
public static final String SCHEMA_GEN_SCRIPTS_ACTION = "javax.persistence.schema-generation.scripts.action";
String SCHEMA_GEN_SCRIPTS_ACTION = "javax.persistence.schema-generation.scripts.action";
/**
* For cases where the {@value #SCHEMA_GEN_SCRIPTS_ACTION} value indicates that schema creation commands should
@ -270,7 +270,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_SCRIPTS_ACTION
*/
@SuppressWarnings("JavaDoc")
public static final String SCHEMA_GEN_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target";
String SCHEMA_GEN_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target";
/**
* For cases where the {@value #SCHEMA_GEN_SCRIPTS_ACTION} value indicates that schema drop commands should
@ -281,7 +281,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_SCRIPTS_ACTION
*/
@SuppressWarnings("JavaDoc")
public static final String SCHEMA_GEN_SCRIPTS_DROP_TARGET = "javax.persistence.schema-generation.scripts.drop-target";
String SCHEMA_GEN_SCRIPTS_DROP_TARGET = "javax.persistence.schema-generation.scripts.drop-target";
/**
* Specifies whether the persistence provider is to create the database schema(s) in addition to creating
@ -290,7 +290,7 @@ public interface AvailableSettings {
* contains CREATE SCHEMA commands. If this property is not supplied (or is explicitly {@code false}), the
* provider should not attempt to create database schemas.
*/
public static final String SCHEMA_GEN_CREATE_SCHEMAS = "javax.persistence.create-database-schemas";
String SCHEMA_GEN_CREATE_SCHEMAS = "javax.persistence.create-database-schemas";
/**
* Allows passing the specific {@link java.sql.Connection} instance to be used for performing schema generation
@ -299,7 +299,7 @@ public interface AvailableSettings {
* May also be used to determine the values for {@value #SCHEMA_GEN_DB_NAME},
* {@value #SCHEMA_GEN_DB_MAJOR_VERSION} and {@value #SCHEMA_GEN_DB_MINOR_VERSION}.
*/
public static final String SCHEMA_GEN_CONNECTION = "javax.persistence.schema-generation-connection";
String SCHEMA_GEN_CONNECTION = "javax.persistence.schema-generation-connection";
/**
* Specifies the name of the database provider in cases where a Connection to the underlying database is
@ -316,7 +316,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_DB_MINOR_VERSION
*/
@SuppressWarnings("JavaDoc")
public static final String SCHEMA_GEN_DB_NAME = "javax.persistence.database-product-name";
String SCHEMA_GEN_DB_NAME = "javax.persistence.database-product-name";
/**
* Specifies the major version of the underlying database, as would be returned by
@ -327,7 +327,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_DB_NAME
* @see #SCHEMA_GEN_DB_MINOR_VERSION
*/
public static final String SCHEMA_GEN_DB_MAJOR_VERSION = "javax.persistence.database-major-version";
String SCHEMA_GEN_DB_MAJOR_VERSION = "javax.persistence.database-major-version";
/**
* Specifies the minor version of the underlying database, as would be returned by
@ -339,7 +339,7 @@ public interface AvailableSettings {
* @see #SCHEMA_GEN_DB_NAME
* @see #SCHEMA_GEN_DB_MAJOR_VERSION
*/
public static final String SCHEMA_GEN_DB_MINOR_VERSION = "javax.persistence.database-minor-version";
String SCHEMA_GEN_DB_MINOR_VERSION = "javax.persistence.database-minor-version";
/**
* Specifies a {@link java.io.Reader} configured for reading of the SQL load script or a string designating the
@ -347,7 +347,7 @@ public interface AvailableSettings {
* <p/>
* A "SQL load script" is a script that performs some database initialization (INSERT, etc).
*/
public static final String SCHEMA_GEN_LOAD_SCRIPT_SOURCE = "javax.persistence.sql-load-script-source";
String SCHEMA_GEN_LOAD_SCRIPT_SOURCE = "javax.persistence.sql-load-script-source";
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -367,75 +367,75 @@ public interface AvailableSettings {
* would apply <code>someLockMode</code> to the alias <code>"a"</code>.
*/
//Use the org.hibernate prefix. instead of hibernate. as it is a query hint se QueryHints
public static final String ALIAS_SPECIFIC_LOCK_MODE = "org.hibernate.lockMode";
String ALIAS_SPECIFIC_LOCK_MODE = "org.hibernate.lockMode";
/**
* JAR autodetection artifacts class, hbm
*/
public static final String AUTODETECTION = "hibernate.archive.autodetection";
String AUTODETECTION = "hibernate.archive.autodetection";
/**
* cfg.xml configuration file used
*/
public static final String CFG_FILE = "hibernate.ejb.cfgfile";
String CFG_FILE = "hibernate.ejb.cfgfile";
/**
* Caching configuration should follow the following pattern
* hibernate.ejb.classcache.<fully.qualified.Classname> usage[, region]
* where usage is the cache strategy used and region the cache region name
*/
public static final String CLASS_CACHE_PREFIX = "hibernate.ejb.classcache";
String CLASS_CACHE_PREFIX = "hibernate.ejb.classcache";
/**
* Caching configuration should follow the following pattern
* hibernate.ejb.collectioncache.<fully.qualified.Classname>.<role> usage[, region]
* where usage is the cache strategy used and region the cache region name
*/
public static final String COLLECTION_CACHE_PREFIX = "hibernate.ejb.collectioncache";
String COLLECTION_CACHE_PREFIX = "hibernate.ejb.collectioncache";
/**
* Interceptor class name, the class has to have a no-arg constructor
* the interceptor instance is shared amongst all EntityManager of a given EntityManagerFactory
*/
public static final String INTERCEPTOR = "hibernate.ejb.interceptor";
String INTERCEPTOR = "hibernate.ejb.interceptor";
/**
* Interceptor class name, the class has to have a no-arg constructor
*/
public static final String SESSION_INTERCEPTOR = "hibernate.ejb.interceptor.session_scoped";
String SESSION_INTERCEPTOR = "hibernate.ejb.interceptor.session_scoped";
/**
* SessionFactoryObserver class name, the class must have a no-arg constructor
*/
public static final String SESSION_FACTORY_OBSERVER = "hibernate.ejb.session_factory_observer";
String SESSION_FACTORY_OBSERVER = "hibernate.ejb.session_factory_observer";
/**
* Naming strategy class name, the class has to have a no-arg constructor
*/
public static final String NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
String NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
/**
* IdentifierGeneratorStrategyProvider class name, the class must have a no-arg constructor
* @deprecated if possible wait of Hibernate 4.1 and theService registry (MutableIdentifierGeneratorStrategy service)
*/
public static final String IDENTIFIER_GENERATOR_STRATEGY_PROVIDER = "hibernate.ejb.identifier_generator_strategy_provider";
String IDENTIFIER_GENERATOR_STRATEGY_PROVIDER = "hibernate.ejb.identifier_generator_strategy_provider";
/**
* Event configuration should follow the following pattern
* hibernate.ejb.event.[eventType] f.q.c.n.EventListener1, f.q.c.n.EventListener12 ...
*/
public static final String EVENT_LISTENER_PREFIX = "hibernate.ejb.event";
String EVENT_LISTENER_PREFIX = "hibernate.ejb.event";
/**
* Enable the class file enhancement
*/
public static final String USE_CLASS_ENHANCER = "hibernate.ejb.use_class_enhancer";
String USE_CLASS_ENHANCER = "hibernate.ejb.use_class_enhancer";
/**
* Whether or not discard persistent context on entityManager.close()
* The EJB3 compliant and default choice is false
*/
public static final String DISCARD_PC_ON_CLOSE = "hibernate.ejb.discard_pc_on_close";
String DISCARD_PC_ON_CLOSE = "hibernate.ejb.discard_pc_on_close";
/**
* Consider this as experimental
@ -445,20 +445,20 @@ public interface AvailableSettings {
* @deprecated Configuration going away.
*/
@Deprecated
public static final String CONFIGURATION_JNDI_NAME = "hibernate.ejb.configuration_jndi_name";
String CONFIGURATION_JNDI_NAME = "hibernate.ejb.configuration_jndi_name";
/**
* Used to determine flush mode.
*/
//Use the org.hibernate prefix. instead of hibernate. as it is a query hint se QueryHints
public static final String FLUSH_MODE = "org.hibernate.flushMode";
String FLUSH_MODE = "org.hibernate.flushMode";
/**
* Pass an implementation of {@link org.hibernate.ejb.packaging.Scanner}:
* - preferably an actual instance
* - or a class name with a no-arg constructor
*/
public static final String SCANNER = "hibernate.ejb.resource_scanner";
String SCANNER = "hibernate.ejb.resource_scanner";
/**
* List of classes names
@ -468,7 +468,7 @@ public interface AvailableSettings {
*/
@Deprecated
@SuppressWarnings("UnusedDeclaration")
public static final String CLASS_NAMES = "hibernate.ejb.classes";
String CLASS_NAMES = "hibernate.ejb.classes";
/**
* List of annotated packages
@ -478,18 +478,18 @@ public interface AvailableSettings {
*/
@Deprecated
@SuppressWarnings("UnusedDeclaration")
public static final String PACKAGE_NAMES = "hibernate.ejb.packages";
String PACKAGE_NAMES = "hibernate.ejb.packages";
/**
* EntityManagerFactory name
*/
public static final String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name";
String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name";
/**
* @deprecated use {@link #JPA_METAMODEL_POPULATION} instead.
*/
@Deprecated
public static final String JPA_METAMODEL_GENERATION = "hibernate.ejb.metamodel.generation";
String JPA_METAMODEL_GENERATION = "hibernate.ejb.metamodel.generation";
/**
* Setting that controls whether we seek out JPA "static metamodel" classes and populate them. Accepts
@ -507,16 +507,16 @@ public interface AvailableSettings {
* </ul>
*
*/
public static final String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population";
String JPA_METAMODEL_POPULATION = "hibernate.ejb.metamodel.population";
/**
* List of classes names
* Internal use only
*/
public static final String XML_FILE_NAMES = "hibernate.ejb.xml_files";
public static final String HBXML_FILES = "hibernate.hbmxml.files";
public static final String LOADED_CLASSES = "hibernate.ejb.loaded.classes";
String XML_FILE_NAMES = "hibernate.ejb.xml_files";
String HBXML_FILES = "hibernate.hbmxml.files";
String LOADED_CLASSES = "hibernate.ejb.loaded.classes";
/**
* Deprecated
@ -524,7 +524,7 @@ public interface AvailableSettings {
* @deprecated Use {@link org.hibernate.cfg.AvailableSettings#JACC_CONTEXT_ID} instead
*/
@Deprecated
public static final String JACC_CONTEXT_ID = org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID;
String JACC_CONTEXT_ID = org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID;
/**
* Deprecated
@ -532,7 +532,7 @@ public interface AvailableSettings {
* @deprecated Use {@link org.hibernate.cfg.AvailableSettings#JACC_PREFIX} instead
*/
@Deprecated
public static final String JACC_PREFIX = org.hibernate.cfg.AvailableSettings.JACC_PREFIX;
String JACC_PREFIX = org.hibernate.cfg.AvailableSettings.JACC_PREFIX;
/**
* Deprecated
@ -540,11 +540,10 @@ public interface AvailableSettings {
* @deprecated Use {@link org.hibernate.cfg.AvailableSettings#JACC_ENABLED} instead
*/
@Deprecated
public static final String JACC_ENABLED = org.hibernate.cfg.AvailableSettings.JACC_ENABLED;
String JACC_ENABLED = org.hibernate.cfg.AvailableSettings.JACC_ENABLED;
/**
* Used to pass along the name of the persistence unit.
*/
public static final String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName";
}

View File

@ -24,7 +24,6 @@
package org.hibernate.jpa.graph.internal;
import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import java.util.ArrayList;
import java.util.Collections;
@ -34,17 +33,18 @@ import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.jpa.graph.spi.GraphNodeImplementor;
import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware;
/**
* Base class for EntityGraph and Subgraph implementations.
*
* @author Steve Ebersole
*/
public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
public abstract class AbstractGraphNode<T> implements GraphNodeImplementor, HibernateEntityManagerFactoryAware{
private static final Logger log = Logger.getLogger( AbstractGraphNode.class );
private final HibernateEntityManagerFactory entityManagerFactory;
@ -80,7 +80,7 @@ public abstract class AbstractGraphNode<T> implements GraphNodeImplementor {
}
@Override
public HibernateEntityManagerFactory entityManagerFactory() {
public HibernateEntityManagerFactory getFactory() {
return entityManagerFactory;
}

View File

@ -34,11 +34,12 @@ import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.jpa.internal.metamodel.Helper;
import org.hibernate.jpa.internal.metamodel.PluralAttributeImpl;
import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
@ -50,7 +51,7 @@ import org.hibernate.type.Type;
*
* @author Steve Ebersole
*/
public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImplementor<T> {
public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImplementor<T>, HibernateEntityManagerFactoryAware {
private final HibernateEntityManagerFactory entityManagerFactory;
private final Attribute<?,T> attribute;
@ -77,12 +78,12 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, AttributeNodeImpl
}
@Override
public HibernateEntityManagerFactory entityManagerFactory() {
public HibernateEntityManagerFactory getFactory() {
return entityManagerFactory;
}
private SessionFactoryImplementor sessionFactory() {
return (SessionFactoryImplementor) entityManagerFactory().getSessionFactory();
return (SessionFactoryImplementor) getFactory().getSessionFactory();
}
@Override

View File

@ -32,6 +32,7 @@ import javax.persistence.metamodel.IdentifiableType;
import java.util.List;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
@ -39,7 +40,7 @@ import org.hibernate.jpa.HibernateEntityManagerFactory;
*
* @author Steve Ebersole
*/
public class EntityGraphImpl<T> extends AbstractGraphNode<T> implements EntityGraph<T> {
public class EntityGraphImpl<T> extends AbstractGraphNode<T> implements EntityGraph<T>, GraphNodeImplementor {
private final String name;
private final EntityType<T> entityType;
@ -150,7 +151,7 @@ public class EntityGraphImpl<T> extends AbstractGraphNode<T> implements EntityGr
@SuppressWarnings("unchecked")
public boolean appliesTo(String entityName) {
return appliesTo( entityManagerFactory().getEntityTypeByName( entityName ) );
return appliesTo( getFactory().getEntityTypeByName( entityName ) );
}
public boolean appliesTo(EntityType<? super T> entityType) {

View File

@ -29,12 +29,13 @@ import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.ManagedType;
import java.util.List;
import org.hibernate.graph.spi.GraphNodeImplementor;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
* @author Steve Ebersole
*/
public class SubgraphImpl<T> extends AbstractGraphNode<T> implements Subgraph<T> {
public class SubgraphImpl<T> extends AbstractGraphNode<T> implements Subgraph<T>, GraphNodeImplementor {
private final ManagedType managedType;
private final Class<T> subclass;

View File

@ -23,20 +23,10 @@
*/
package org.hibernate.jpa.graph.internal.advisor;
import org.hibernate.LockMode;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.jpa.internal.metamodel.Helper;
import org.hibernate.loader.plan.spi.CollectionFetch;
import org.hibernate.loader.plan.spi.CompositeFetch;
import org.hibernate.loader.plan.spi.EntityFetch;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.loader.plan.spi.Fetch;
import org.hibernate.loader.plan.spi.FetchOwner;
import org.hibernate.type.EntityType;
/**
* @author Steve Ebersole

View File

@ -23,7 +23,7 @@
*/
package org.hibernate.jpa.graph.internal.advisor;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.loader.plan.spi.FetchOwner;
/**

View File

@ -30,7 +30,7 @@ import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.loader.plan.spi.FetchOwner;
/**

View File

@ -29,8 +29,8 @@ import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.jpa.graph.internal.EntityGraphImpl;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.loader.plan.spi.FetchOwner;
/**

View File

@ -23,7 +23,8 @@
*/
package org.hibernate.jpa.graph.internal.advisor;
import org.hibernate.jpa.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
/**
* @author Steve Ebersole

View File

@ -26,6 +26,7 @@ package org.hibernate.jpa.spi;
import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityTransaction;
@ -109,7 +110,6 @@ import org.hibernate.engine.transaction.synchronization.spi.AfterCompletionActio
import org.hibernate.engine.transaction.synchronization.spi.ExceptionMapper;
import org.hibernate.engine.transaction.synchronization.spi.ManagedFlushChecker;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernateEntityManagerFactory;
@ -1098,6 +1098,12 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
CacheMode cacheMode = determineAppropriateLocalCacheMode( properties );
LockOptions lockOptions = null;
try {
if ( properties != null && !properties.isEmpty() ) {
( (SessionImplementor) session ).getLoadQueryInfluencers()
.setFetchGraph( (EntityGraph) properties.get( QueryHints.HINT_FETCHGRAPH ) );
( (SessionImplementor) session ).getLoadQueryInfluencers()
.setLoadGraph( (EntityGraph) properties.get( QueryHints.HINT_LOADGRAPH ) );
}
session.setCacheMode( cacheMode );
if ( lockModeType != null ) {
lockOptions = getLockRequest( lockModeType, properties );
@ -1145,6 +1151,9 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
finally {
session.setCacheMode( previousCacheMode );
((SessionImplementor)session).getLoadQueryInfluencers().setFetchGraph( null );
((SessionImplementor)session).getLoadQueryInfluencers().setLoadGraph( null );
}
}

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. 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 Inc.
*
* 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.jpa.spi;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
* Internal contact for things that have {@link HibernateEntityManagerFactory} access.
*
* @author Strong Liu <stliu@hibernate.org>
*/
public interface HibernateEntityManagerFactoryAware {
/**
* Get access to the Hibernate extended EMF contract.
*
* @return The Hibernate EMF contract for this EM.
*/
HibernateEntityManagerFactory getFactory();
}

View File

@ -44,13 +44,8 @@ import org.hibernate.type.Type;
* @author Emmanuel Bernard
* @author Steve Ebersole
*/
public interface HibernateEntityManagerImplementor extends HibernateEntityManager {
/**
* Get access to the Hibernate extended EMF contract.
*
* @return The Hibernate EMF contract for this EM.
*/
public HibernateEntityManagerFactory getFactory();
public interface HibernateEntityManagerImplementor extends HibernateEntityManager, HibernateEntityManagerFactoryAware {
/**
* Used to ensure the EntityManager is open, throwing IllegalStateException if it is closed.

View File

@ -0,0 +1,214 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. 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 Inc..
*
* 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.jpa.test.graphs;
import java.util.Iterator;
import java.util.Set;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.junit.Test;
import static org.junit.Assert.*;
import org.hibernate.LockMode;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.graph.internal.EntityGraphImpl;
import org.hibernate.jpa.graph.internal.SubgraphImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.loader.plan2.build.internal.FetchGraphLoadPlanBuildingStrategy;
import org.hibernate.loader.plan2.build.internal.FetchStyleLoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan2.build.internal.LoadGraphLoadPlanBuildingStrategy;
import org.hibernate.loader.plan2.build.spi.AbstractLoadPlanBuildingAssociationVisitationStrategy;
import org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter;
import org.hibernate.loader.plan2.build.spi.MetamodelDrivenLoadPlanBuilder;
import org.hibernate.loader.plan2.exec.internal.AliasResolutionContextImpl;
import org.hibernate.loader.plan2.spi.Join;
import org.hibernate.loader.plan2.spi.LoadPlan;
import org.hibernate.loader.plan2.spi.QuerySpace;
import org.hibernate.persister.entity.EntityPersister;
/**
* @author Strong Liu <stliu@hibernate.org>
*/
public class EntityGraphLoadPlanBuilderTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Cat.class, Person.class, Country.class };
}
@Entity
public static class Cat {
@Id
String name;
@ManyToOne(fetch = FetchType.LAZY)
Person owner;
}
@Entity
public static class Person {
@Id
String name;
@OneToMany(mappedBy = "owner")
Set<Cat> pets;
@Embedded
Address homeAddress;
}
@Embeddable
public static class Address {
@ManyToOne
Country country;
}
@Entity
public static class Country {
@Id
String name;
}
@Test
public void testBasicFetchLoadPlanBuilding() {
EntityManager em = getOrCreateEntityManager();
EntityGraph eg = em.createEntityGraph( Cat.class );
LoadPlan plan = buildLoadPlan( eg, Mode.FETCH );
LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) );
QuerySpace rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 );
assertFalse(
"With fetchgraph property and an empty EntityGraph, there should be no join at all",
rootQuerySpace.getJoins().iterator().hasNext()
);
// -------------------------------------------------- another a little more complicated case
eg = em.createEntityGraph( Cat.class );
eg.addSubgraph( "owner", Person.class );
plan = buildLoadPlan( eg, Mode.FETCH );
LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) );
rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 );
Iterator<Join> iterator = rootQuerySpace.getJoins().iterator();
assertTrue(
"With fetchgraph property and an empty EntityGraph, there should be no join at all", iterator.hasNext()
);
Join personJoin = iterator.next();
assertNotNull( personJoin );
QuerySpace.Disposition disposition = personJoin.getRightHandSide().getDisposition();
assertEquals(
"This should be an entity join which fetches Person", QuerySpace.Disposition.ENTITY, disposition
);
iterator = personJoin.getRightHandSide().getJoins().iterator();
assertTrue( "The composite address should be fetched", iterator.hasNext() );
Join addressJoin = iterator.next();
assertNotNull( addressJoin );
disposition = addressJoin.getRightHandSide().getDisposition();
assertEquals( QuerySpace.Disposition.COMPOSITE, disposition );
assertFalse( iterator.hasNext() );
assertFalse(
"The ManyToOne attribute in composite should not be fetched",
addressJoin.getRightHandSide().getJoins().iterator().hasNext()
);
em.close();
}
@Test
public void testBasicLoadLoadPlanBuilding() {
EntityManager em = getOrCreateEntityManager();
EntityGraph eg = em.createEntityGraph( Cat.class );
LoadPlan plan = buildLoadPlan( eg, Mode.LOAD );
LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) );
QuerySpace rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 );
assertFalse(
"With fetchgraph property and an empty EntityGraph, there should be no join at all",
rootQuerySpace.getJoins().iterator().hasNext()
);
// -------------------------------------------------- another a little more complicated case
eg = em.createEntityGraph( Cat.class );
eg.addSubgraph( "owner", Person.class );
plan = buildLoadPlan( eg, Mode.LOAD );
LoadPlanTreePrinter.INSTANCE.logTree( plan, new AliasResolutionContextImpl( sfi() ) );
rootQuerySpace = plan.getQuerySpaces().getRootQuerySpaces().get( 0 );
Iterator<Join> iterator = rootQuerySpace.getJoins().iterator();
assertTrue(
"With fetchgraph property and an empty EntityGraph, there should be no join at all", iterator.hasNext()
);
Join personJoin = iterator.next();
assertNotNull( personJoin );
QuerySpace.Disposition disposition = personJoin.getRightHandSide().getDisposition();
assertEquals(
"This should be an entity join which fetches Person", QuerySpace.Disposition.ENTITY, disposition
);
iterator = personJoin.getRightHandSide().getJoins().iterator();
assertTrue( "The composite address should be fetched", iterator.hasNext() );
Join addressJoin = iterator.next();
assertNotNull( addressJoin );
disposition = addressJoin.getRightHandSide().getDisposition();
assertEquals( QuerySpace.Disposition.COMPOSITE, disposition );
iterator = addressJoin.getRightHandSide().getJoins().iterator();
assertTrue( iterator.hasNext() );
Join countryJoin = iterator.next();
assertNotNull( countryJoin );
disposition = countryJoin.getRightHandSide().getDisposition();
assertEquals( QuerySpace.Disposition.ENTITY, disposition );
assertFalse(
"The ManyToOne attribute in composite should not be fetched",
countryJoin.getRightHandSide().getJoins().iterator().hasNext()
);
em.close();
}
private SessionFactoryImplementor sfi() {
return entityManagerFactory().unwrap( SessionFactoryImplementor.class );
}
private LoadPlan buildLoadPlan(EntityGraph entityGraph, Mode mode) {
LoadQueryInfluencers loadQueryInfluencers = new LoadQueryInfluencers( sfi() );
if ( Mode.FETCH == mode ) {
loadQueryInfluencers.setFetchGraph( entityGraph );
}
else {
loadQueryInfluencers.setLoadGraph( entityGraph );
}
EntityPersister ep = (EntityPersister) sfi().getClassMetadata( Cat.class );
AbstractLoadPlanBuildingAssociationVisitationStrategy strategy = Mode.FETCH == mode ? new FetchGraphLoadPlanBuildingStrategy(
sfi(), loadQueryInfluencers, LockMode.NONE
) : new LoadGraphLoadPlanBuildingStrategy( sfi(), loadQueryInfluencers, LockMode.NONE );
return MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan( strategy, ep );
}
public static enum Mode {FETCH, LOAD}
}