diff --git a/hibernate-core/src/main/java/org/hibernate/ForcedFlushMode.java b/hibernate-core/src/main/java/org/hibernate/ForcedFlushMode.java new file mode 100644 index 000000000000..68f4a0cbcb0d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/ForcedFlushMode.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate; + +/** + * Enumerates the possible flush modes for execution of a + * {@link org.hibernate.query.Query}. A "forced" flush mode + * overrides the {@linkplain Session#getHibernateFlushMode() + * flush mode of the session}. + * + * @author Gavin King + * + * @since 6.2 + */ +public enum ForcedFlushMode { + /** + * Flush before executing the query. + */ + FORCE_FLUSH, + /** + * Do not flush before executing the query. + */ + FORCE_NO_FLUSH, + /** + * Let the owning {@link Session session} decide whether + * to flush, depending on its {@link FlushMode}. + */ + NO_FORCING +} diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index 7149dfb61d58..4df8aa6c5931 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -148,7 +148,7 @@ public interface Session extends SharedSessionContract, EntityManager { void flush(); /** - * Set the current {@link FlushModeType JPA flush mode} for this session. + * Set the current {@linkplain FlushModeType JPA flush mode} for this session. *

* Flushing is the process of synchronizing the underlying persistent * store with persistable state held in memory. The current flush mode determines @@ -162,7 +162,7 @@ public interface Session extends SharedSessionContract, EntityManager { void setFlushMode(FlushModeType flushMode); /** - * Set the current {@link FlushMode flush mode} for this session. + * Set the current {@linkplain FlushMode flush mode} for this session. *

* Flushing is the process of synchronizing the underlying persistent * store with persistable state held in memory. The current flush mode determines @@ -180,7 +180,7 @@ public interface Session extends SharedSessionContract, EntityManager { void setHibernateFlushMode(FlushMode flushMode); /** - * Get the current {@link FlushModeType JPA flush mode} for this session. + * Get the current {@linkplain FlushModeType JPA flush mode} for this session. * * @return the {@link FlushModeType} currently in effect */ @@ -188,14 +188,14 @@ public interface Session extends SharedSessionContract, EntityManager { FlushModeType getFlushMode(); /** - * Get the current {@link FlushMode flush mode} for this session. + * Get the current {@linkplain FlushMode flush mode} for this session. * * @return the {@link FlushMode} currently in effect */ FlushMode getHibernateFlushMode(); /** - * Set the current {@link CacheMode cache mode} for this session. + * Set the current {@linkplain CacheMode cache mode} for this session. *

* The cache mode determines the manner in which this session can interact with * the second level cache. @@ -205,7 +205,7 @@ public interface Session extends SharedSessionContract, EntityManager { void setCacheMode(CacheMode cacheMode); /** - * Get the current {@link CacheMode cache mode} for this session. + * Get the current {@linkplain CacheMode cache mode} for this session. * * @return the current cache mode */ diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/FlushModeType.java b/hibernate-core/src/main/java/org/hibernate/annotations/FlushModeType.java index 24818577ec04..f1233b7b68a5 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/FlushModeType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/FlushModeType.java @@ -16,7 +16,10 @@ * * @see NamedQuery * @see NamedNativeQuery + * + * @deprecated use {@link org.hibernate.ForcedFlushMode} */ +@Deprecated(since="6") public enum FlushModeType { /** * Corresponds to {@link org.hibernate.FlushMode#ALWAYS}. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java b/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java index 865fab3a9bb6..a45800f3a3d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java @@ -13,6 +13,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; import org.hibernate.CacheMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Remove; import static java.lang.annotation.ElementType.PACKAGE; @@ -64,12 +65,23 @@ */ String resultSetMapping() default ""; + /** + * Determines whether the session should be flushed before + * executing the query. + * + * @see org.hibernate.query.CommonQueryContract#setForcedFlushMode(ForcedFlushMode) + */ + ForcedFlushMode flush() default ForcedFlushMode.NO_FORCING; + /** * The flush mode for the query. * * @see org.hibernate.query.CommonQueryContract#setFlushMode(jakarta.persistence.FlushModeType) * @see org.hibernate.jpa.HibernateHints#HINT_FLUSH_MODE + * + * @deprecated use {@link #flush()} */ + @Deprecated(since = "6") FlushModeType flushMode() default FlushModeType.PERSISTENCE_CONTEXT; /** diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java b/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java index bc9e152a2bb7..17024432f063 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java @@ -12,6 +12,7 @@ import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Remove; import static java.lang.annotation.ElementType.PACKAGE; @@ -47,12 +48,23 @@ */ String query(); + /** + * Determines whether the session should be flushed before + * executing the query. + * + * @see org.hibernate.query.CommonQueryContract#setForcedFlushMode(ForcedFlushMode) + */ + ForcedFlushMode flush() default ForcedFlushMode.NO_FORCING; + /** * The flush mode for this query. * * @see org.hibernate.query.CommonQueryContract#setFlushMode(jakarta.persistence.FlushModeType) * @see org.hibernate.jpa.HibernateHints#HINT_FLUSH_MODE + * + * @deprecated use {@link #flush()} */ + @Deprecated(since = "6") FlushModeType flushMode() default FlushModeType.PERSISTENCE_CONTEXT; /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java index 5d289807a782..71dc1db05049 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java @@ -14,6 +14,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Remove; import org.hibernate.annotations.CacheModeType; import org.hibernate.annotations.FlushModeType; @@ -29,6 +30,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.jpa.HibernateHints; +import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.query.sql.internal.ParameterParser; import org.hibernate.query.sql.spi.ParameterRecognizer; import org.hibernate.type.BasicType; @@ -184,7 +186,7 @@ public static void bindNativeQuery( .setCacheMode( getCacheMode( namedNativeQuery ) ) .setTimeout( namedNativeQuery.timeout() < 0 ? null : namedNativeQuery.timeout() ) .setFetchSize( namedNativeQuery.fetchSize() < 0 ? null : namedNativeQuery.fetchSize() ) - .setFlushMode( getFlushMode( namedNativeQuery.flushMode() ) ) + .setFlushMode( getFlushMode( namedNativeQuery.flush(), namedNativeQuery.flushMode() ) ) .setReadOnly( namedNativeQuery.readOnly() ) .setQuerySpaces( setOf( namedNativeQuery.querySpaces() ) ) .setComment(nullIfEmpty(namedNativeQuery.comment())); @@ -341,7 +343,7 @@ public static void bindQuery( .setCacheMode( getCacheMode( namedQuery ) ) .setTimeout( namedQuery.timeout() < 0 ? null : namedQuery.timeout() ) .setFetchSize( namedQuery.fetchSize() < 0 ? null : namedQuery.fetchSize() ) - .setFlushMode( getFlushMode( namedQuery.flushMode() ) ) + .setFlushMode( getFlushMode( namedQuery.flush(), namedQuery.flushMode() ) ) .setReadOnly( namedQuery.readOnly() ) .setComment( nullIfEmpty( namedQuery.comment() ) ); @@ -364,6 +366,12 @@ private static CacheMode getCacheMode(org.hibernate.annotations.NamedNativeQuery return cacheMode == null || cacheMode == CacheMode.NORMAL ? getCacheMode( namedNativeQuery.cacheMode() ) : cacheMode; } + private static FlushMode getFlushMode(ForcedFlushMode forcedFlushMode, FlushModeType flushModeType) { + return forcedFlushMode == ForcedFlushMode.NO_FORCING + ? getFlushMode( flushModeType ) + : FlushModeTypeHelper.getFlushMode( forcedFlushMode ); + } + private static FlushMode getFlushMode(FlushModeType flushModeType) { switch ( flushModeType ) { case ALWAYS: diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java index 44b92f090af9..8f27e2164e30 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/parse/GraphParser.java @@ -18,8 +18,6 @@ import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; -import org.jboss.logging.Logger; - import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/FlushModeTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/FlushModeTypeHelper.java index bf79234fa7c4..5462180213c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/FlushModeTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/FlushModeTypeHelper.java @@ -12,6 +12,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.MappingException; import org.jboss.logging.Logger; @@ -28,33 +29,69 @@ private FlushModeTypeHelper() { } public static FlushModeType getFlushModeType(FlushMode flushMode) { - if ( flushMode == FlushMode.ALWAYS ) { - log.debug( "Interpreting Hibernate FlushMode#ALWAYS to JPA FlushModeType#AUTO; may cause problems if relying on FlushMode#ALWAYS-specific behavior" ); - return FlushModeType.AUTO; + if ( flushMode == null ) { + return null; } - else if ( flushMode == FlushMode.MANUAL ) { - log.debug( "Interpreting Hibernate FlushMode#MANUAL to JPA FlushModeType#COMMIT; may cause problems if relying on FlushMode#MANUAL-specific behavior" ); - return FlushModeType.COMMIT; + switch ( flushMode ) { + case ALWAYS: + log.debug( "Interpreting Hibernate FlushMode#ALWAYS to JPA FlushModeType#AUTO; may cause problems if relying on FlushMode#ALWAYS-specific behavior" ); + return FlushModeType.AUTO; + case MANUAL: + log.debug( "Interpreting Hibernate FlushMode#MANUAL to JPA FlushModeType#COMMIT; may cause problems if relying on FlushMode#MANUAL-specific behavior" ); + return FlushModeType.COMMIT; + case COMMIT: + return FlushModeType.COMMIT; + case AUTO: + return FlushModeType.AUTO; + default: + throw new AssertionFailure( "unhandled FlushMode " + flushMode ); } - else if ( flushMode == FlushMode.COMMIT ) { - return FlushModeType.COMMIT; + } + + public static ForcedFlushMode getForcedFlushMode(FlushMode flushMode) { + if ( flushMode == null ) { + return ForcedFlushMode.NO_FORCING; } - else if ( flushMode == FlushMode.AUTO ) { - return FlushModeType.AUTO; + switch ( flushMode ) { + case ALWAYS: + return ForcedFlushMode.FORCE_FLUSH; + case COMMIT: + case MANUAL: + return ForcedFlushMode.FORCE_NO_FLUSH; + case AUTO: + // this is not precisely correctly correct, but good enough + return ForcedFlushMode.NO_FORCING; + default: + throw new AssertionFailure( "unhandled FlushMode " + flushMode ); } - - throw new AssertionFailure( "unhandled FlushMode " + flushMode ); } public static FlushMode getFlushMode(FlushModeType flushModeType) { - if ( flushModeType == FlushModeType.AUTO ) { - return FlushMode.AUTO; + if ( flushModeType == null ) { + return null; } - else if ( flushModeType == FlushModeType.COMMIT ) { - return FlushMode.COMMIT; + switch ( flushModeType ) { + case AUTO: + return FlushMode.AUTO; + case COMMIT: + return FlushMode.COMMIT; + default: + throw new AssertionFailure( "unhandled FlushModeType " + flushModeType ); } + } - throw new AssertionFailure( "unhandled FlushModeType " + flushModeType ); + public static FlushMode getFlushMode(ForcedFlushMode forcedFlushMode) { + if ( forcedFlushMode == null ) { + return null; + } + switch ( forcedFlushMode ) { + case FORCE_FLUSH: + return FlushMode.ALWAYS; + case FORCE_NO_FLUSH: + return FlushMode.MANUAL; + default: + return null; + } } public static FlushMode interpretFlushMode(Object value) { diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java index c635fed53771..80ca84ffef45 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java @@ -784,7 +784,7 @@ public NamedCallableQueryMemento toMemento(String name) { isCacheable(), getCacheRegion(), getCacheMode(), - getHibernateFlushMode(), + getQueryOptions().getFlushMode(), isReadOnly(), getTimeout(), getFetchSize(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java index 19f635e22955..8b663aac9a48 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java @@ -13,6 +13,7 @@ import java.util.Map; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Session; import jakarta.persistence.FlushModeType; @@ -30,36 +31,66 @@ */ public interface CommonQueryContract { + /** + * The {@link ForcedFlushMode} in effect for this query. + *

+ * By default, this is {@link ForcedFlushMode#NO_FORCING}, and the + * {@link FlushMode} of the owning {@link Session} determines whether + * it is flushed. + * + * @see Session#getHibernateFlushMode() + */ + ForcedFlushMode getForcedFlushMode(); + + /** + * Set the {@link ForcedFlushMode} in to use for this query. + * + * @see Session#getHibernateFlushMode() + */ + CommonQueryContract setForcedFlushMode(ForcedFlushMode forcedFlushMode); + /** * The JPA {@link FlushModeType} in effect for this query. By default, the * query inherits the {@link FlushMode} of the {@link Session} from which * it originates. * - * @see #getHibernateFlushMode - * @see Session#getHibernateFlushMode + * @see #getForcedFlushMode() + * @see #getHibernateFlushMode() + * @see Session#getHibernateFlushMode() + * + * @deprecated use {@link #getForcedFlushMode()} */ + @Deprecated(since = "6") FlushModeType getFlushMode(); /** * Set the {@link FlushMode} in to use for this query. + *

+ * Setting this to {@code null} ultimately indicates to use the + * {@link FlushMode} of the Session. Use {@link #setHibernateFlushMode} + * passing {@link FlushMode#MANUAL} instead to indicate that no automatic + * flushing should occur. * - * @implNote Setting to {@code null} ultimately indicates to use the - * FlushMode of the Session. Use {@link #setHibernateFlushMode} passing - * {@link FlushMode#MANUAL} instead to indicate that no automatic flushing - * should occur - * + * @see #getForcedFlushMode() * @see #getHibernateFlushMode() * @see Session#getHibernateFlushMode() + * + * @deprecated use {@link #setForcedFlushMode(ForcedFlushMode)} */ + @Deprecated(since = "6") CommonQueryContract setFlushMode(FlushModeType flushMode); /** - * The {@link FlushMode} in effect for this query. By default, the query + * The {@link FlushMode} in effect for this query. By default, the query * inherits the {@code FlushMode} of the {@link Session} from which it * originates. * - * @see Session#getHibernateFlushMode + * @see #getForcedFlushMode() + * @see Session#getHibernateFlushMode() + * + * @deprecated use {@link #getForcedFlushMode()} */ + @Deprecated(since = "6") FlushMode getHibernateFlushMode(); /** @@ -69,9 +100,13 @@ public interface CommonQueryContract { * {@link FlushMode} of the Session. Use {@link FlushMode#MANUAL} * instead to indicate that no automatic flushing should occur. * + * @see #getForcedFlushMode() * @see #getHibernateFlushMode() * @see Session#getHibernateFlushMode() + * + * @deprecated use {@link #setForcedFlushMode(ForcedFlushMode)} */ + @Deprecated(since = "6") CommonQueryContract setHibernateFlushMode(FlushMode flushMode); /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java b/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java index ee8c7ff619b1..e83d7ecfc8f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java @@ -13,6 +13,7 @@ import java.util.Map; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Incubating; import jakarta.persistence.Parameter; @@ -195,4 +196,7 @@ public interface MutationQuery extends CommonQueryContract { @Override MutationQuery setHibernateFlushMode(FlushMode flushMode); + + @Override + MutationQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java b/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java index 6e2ac20e5cf9..3d0a40ae79e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java @@ -23,6 +23,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; @@ -557,6 +558,9 @@ interface FetchReturn extends ResultNode { @Override NativeQuery setHibernateFlushMode(FlushMode flushMode); + @Override + NativeQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode); + @Override NativeQuery setFlushMode(FlushModeType flushMode); diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index 41815e1da78c..b768dbf04887 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -17,6 +17,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Incubating; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -855,6 +856,9 @@ default Query applyLoadGraph(@SuppressWarnings("rawtypes") RootGraph graph) { @Override Query setHibernateFlushMode(FlushMode flushMode); + @Override + Query setForcedFlushMode(ForcedFlushMode forcedFlushMode); + @Override Query setCacheable(boolean cacheable); diff --git a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java index 3d975d2fe382..06c37958c34e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java @@ -19,6 +19,7 @@ import jakarta.persistence.CacheStoreMode; import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Incubating; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -192,6 +193,9 @@ default Stream stream() { @Override SelectionQuery setHibernateFlushMode(FlushMode flushMode); + @Override + SelectionQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode); + @Override SelectionQuery setTimeout(int timeout); @@ -299,14 +303,13 @@ default Stream stream() { * the query inherits the {@link CacheMode} of the session from which * it originates. *

- * The {@link CacheMode} here describes reading-from/writing-to the - * entity/collection caches as we process query results. For caching - * of the actual query results, see {@link #isCacheable()} and - * {@link #getCacheRegion()} + * The {@link CacheMode} here affects the use of entity and collection + * caches as the query result set is processed. For caching of the actual + * query results, use {@link #isCacheable()} and {@link #getCacheRegion()}. *

* In order for this setting to have any affect, second-level caching - * would have to be enabled and the entities/collections in question - * configured for caching. + * must be enabled and the entities and collections must be eligible + * for storage in the second-level cache. * * @see Session#getCacheMode() */ @@ -328,9 +331,9 @@ default Stream stream() { /** * Set the current {@link CacheMode} in effect for this query. - * - * @implNote Setting it to {@code null} ultimately indicates to use the - * {@code CacheMode} of the session. + *

+ * Set it to {@code null} to indicate that the {@code CacheMode} + * of the {@link Session#getCacheMode() session} should be used. * * @see #getCacheMode() * @see Session#setCacheMode(CacheMode) diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmQueryImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmQueryImplementor.java index 7996718bfd03..015c738f6924 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmQueryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmQueryImplementor.java @@ -14,11 +14,13 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.RootGraph; import org.hibernate.query.BindableType; +import org.hibernate.query.Query; import org.hibernate.query.QueryParameter; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; @@ -107,6 +109,9 @@ default SqmQueryImplementor setResultTransformer(ResultTransformer tra @Override SqmQueryImplementor setHibernateFlushMode(FlushMode flushMode); + @Override + SqmQueryImplementor setForcedFlushMode(ForcedFlushMode forcedFlushMode); + @Override SqmQueryImplementor setMaxResults(int maxResult); diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java index 48f5d013e508..1d1259b5dd91 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java @@ -17,6 +17,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -172,7 +173,7 @@ protected void collectHints(Map hints) { } putIfNotNull( hints, HINT_COMMENT, getComment() ); - putIfNotNull( hints, HINT_FLUSH_MODE, getHibernateFlushMode() ); + putIfNotNull( hints, HINT_FLUSH_MODE, getQueryOptions().getFlushMode() ); putIfNotNull( hints, HINT_READONLY, getQueryOptions().isReadOnly() ); putIfNotNull( hints, HINT_FETCH_SIZE, getQueryOptions().getFetchSize() ); @@ -541,7 +542,8 @@ public CommonQueryContract setComment(String comment) { @Override public FlushMode getHibernateFlushMode() { - return getQueryOptions().getFlushMode(); + FlushMode flushMode = getQueryOptions().getFlushMode(); + return flushMode == null ? getSession().getHibernateFlushMode() : flushMode; } @Override @@ -550,6 +552,17 @@ public CommonQueryContract setHibernateFlushMode(FlushMode flushMode) { return this; } + @Override + public ForcedFlushMode getForcedFlushMode() { + return FlushModeTypeHelper.getForcedFlushMode( getQueryOptions().getFlushMode() ); + } + + @Override + public CommonQueryContract setForcedFlushMode(ForcedFlushMode forcedFlushMode) { + getQueryOptions().setFlushMode( FlushModeTypeHelper.getFlushMode( forcedFlushMode ) ); + return this; + } + protected boolean applyJpaCacheRetrieveModeHint(CacheRetrieveMode retrieveMode) { getQueryOptions().setCacheRetrieveMode( retrieveMode ); return true; diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java index b8f670df3143..a0c9e505b5e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java @@ -23,6 +23,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -39,7 +40,6 @@ import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; import org.hibernate.query.named.NamedQueryMemento; -import org.hibernate.query.sqm.SqmExpressible; import static org.hibernate.LockOptions.WAIT_FOREVER; import static org.hibernate.jpa.HibernateHints.HINT_CACHEABLE; @@ -185,18 +185,21 @@ public QueryImplementor setHibernateFlushMode(FlushMode flushMode) { return this; } + @Override + public QueryImplementor setForcedFlushMode(ForcedFlushMode forcedFlushMode) { + super.setForcedFlushMode( forcedFlushMode ); + return this; + } + @Override public FlushModeType getFlushMode() { - getSession().checkOpen(); - final FlushMode flushMode = getQueryOptions().getFlushMode() == null - ? getSession().getHibernateFlushMode() - : getQueryOptions().getFlushMode(); - return FlushModeTypeHelper.getFlushModeType( flushMode ); +// getSession().checkOpen(); + return FlushModeTypeHelper.getFlushModeType( getHibernateFlushMode() ); } @Override public QueryImplementor setFlushMode(FlushModeType flushModeType) { - getSession().checkOpen(); +// getSession().checkOpen(); setHibernateFlushMode( FlushModeTypeHelper.getFlushMode( flushModeType ) ); return this; } @@ -340,7 +343,7 @@ protected void collectHints(Map hints) { putIfNotNull( hints, HINT_COMMENT, getComment() ); putIfNotNull( hints, HINT_FETCH_SIZE, getQueryOptions().getFetchSize() ); - putIfNotNull( hints, HINT_FLUSH_MODE, getHibernateFlushMode() ); + putIfNotNull( hints, HINT_FLUSH_MODE, getQueryOptions().getFlushMode() ); if ( getCacheMode() != null ) { putIfNotNull( hints, HINT_CACHE_MODE, getCacheMode() ); @@ -382,13 +385,6 @@ public QueryImplementor setParameter(String name, Object value) { return this; } - private boolean isInstance(BindableType parameterType, Object value) { - final SqmExpressible sqmExpressible = parameterType.resolveExpressible( getSession().getFactory() ); - assert sqmExpressible != null; - - return sqmExpressible.getExpressibleJavaType().isInstance( value ); - } - @Override public

QueryImplementor setParameter(String name, P value, Class

javaTypeClass) { super.setParameter( name, value, javaTypeClass ); @@ -458,26 +454,6 @@ public

QueryImplementor setParameter(Parameter

parameter, P value) { return this; } - private

void setParameter(Parameter

parameter, P value, BindableType

type) { - if ( parameter instanceof QueryParameter ) { - setParameter( (QueryParameter

) parameter, value, type ); - } - else if ( value == null ) { - locateBinding( parameter ).setBindValue( null, type ); - } - else if ( value instanceof Collection ) { - //TODO: this looks wrong to me: how can value be both a P and a (Collection

)? - locateBinding( parameter ).setBindValues( (Collection

) value ); - } - else { - locateBinding( parameter ).setBindValue( value, type ); - } - } - - - - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Parameter list diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java index dd2f7bd36556..38456265cc74 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java @@ -33,6 +33,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -42,6 +43,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.spi.AppliedGraph; +import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.jpa.internal.util.LockModeTypeHelper; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.DomainType; @@ -287,21 +289,18 @@ else if ( Tuple.class.isAssignableFrom( resultClass ) ) { if ( jpaQueryComplianceEnabled ) { return; } - verifyResultType( resultClass, sqmSelection.getNodeType(), sessionFactory ); + verifyResultType( resultClass, sqmSelection.getNodeType() ); } } - protected static void verifyResultType( - Class resultClass, - SqmExpressible sqmExpressible, - SessionFactoryImplementor sessionFactory) { + protected static void verifyResultType(Class resultClass, SqmExpressible sqmExpressible) { assert sqmExpressible != null; final JavaType expressibleJavaType = sqmExpressible.getExpressibleJavaType(); assert expressibleJavaType != null; final Class javaTypeClass = expressibleJavaType.getJavaTypeClass(); if ( !resultClass.isAssignableFrom( javaTypeClass ) ) { if ( expressibleJavaType instanceof PrimitiveJavaType ) { - if ( ( (PrimitiveJavaType) expressibleJavaType ).getPrimitiveClass() == resultClass ) { + if ( ( (PrimitiveJavaType) expressibleJavaType ).getPrimitiveClass() == resultClass ) { return; } throwQueryTypeMismatchException( resultClass, sqmExpressible ); @@ -391,7 +390,7 @@ protected void beforeQuery() { assert sessionFlushMode == null; assert sessionCacheMode == null; - final FlushMode effectiveFlushMode = getHibernateFlushMode(); + final FlushMode effectiveFlushMode = getQueryOptions().getFlushMode(); if ( effectiveFlushMode != null ) { sessionFlushMode = getSession().getHibernateFlushMode(); getSession().setHibernateFlushMode( effectiveFlushMode ); @@ -530,12 +529,12 @@ protected void resetCallback() { @Override public FlushModeType getFlushMode() { - return getQueryOptions().getFlushMode().toJpaFlushMode(); + return FlushModeTypeHelper.getFlushModeType( getHibernateFlushMode() ); } @Override public SelectionQuery setFlushMode(FlushModeType flushMode) { - getQueryOptions().setFlushMode( FlushMode.fromJpaFlushMode( flushMode ) ); + setHibernateFlushMode( FlushModeTypeHelper.getFlushMode( flushMode ) ); return this; } @@ -744,6 +743,12 @@ public SelectionQuery setHibernateFlushMode(FlushMode flushMode) { return this; } + @Override + public SelectionQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode) { + super.setForcedFlushMode( forcedFlushMode ); + return this; + } + @Override public SelectionQuery setTimeout(int timeout) { super.setTimeout( timeout ); @@ -860,7 +865,7 @@ public SelectionQuery setParameter(int position, Date value, TemporalType tem } @Override - public SelectionQuery setParameterList(String name, Collection values) { + public SelectionQuery setParameterList(String name, @SuppressWarnings("rawtypes") Collection values) { super.setParameterList( name, values ); return this; } @@ -968,7 +973,7 @@ public

SelectionQuery setParameterList(QueryParameter

parameter, P[] v } @Override - public SelectionQuery setProperties(Map map) { + public SelectionQuery setProperties(@SuppressWarnings("rawtypes") Map map) { super.setProperties( map ); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/SqmQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/SqmQuery.java index c66485a7df07..f76b53fa6b4b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/SqmQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/SqmQuery.java @@ -13,6 +13,7 @@ import java.util.Map; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.query.BindableType; import org.hibernate.query.CommonQueryContract; import org.hibernate.query.ParameterMetadata; @@ -151,8 +152,11 @@ public interface SqmQuery extends CommonQueryContract { SqmQuery setProperties(Object bean); @Override - SqmQuery setProperties(Map bean); + SqmQuery setProperties(@SuppressWarnings("rawtypes") Map bean); @Override SqmQuery setHibernateFlushMode(FlushMode flushMode); + + @Override + SqmQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index 0f7734309184..f6e9619f6c39 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -22,6 +22,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -67,6 +68,7 @@ import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.ParameterMetadataImplementor; import org.hibernate.query.spi.QueryEngine; +import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryInterpretationCache; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindings; @@ -454,7 +456,7 @@ public NamedNativeQueryMemento toMemento(String name) { isCacheable(), getCacheRegion(), getCacheMode(), - getHibernateFlushMode(), + getQueryOptions().getFlushMode(), isReadOnly(), getTimeout(), getFetchSize(), @@ -579,7 +581,7 @@ protected void prepareForExecution() { private boolean shouldFlush() { if ( getSession().isTransactionInProgress() ) { - FlushMode effectiveFlushMode = getHibernateFlushMode(); + FlushMode effectiveFlushMode = getQueryOptions().getFlushMode(); if ( effectiveFlushMode == null ) { effectiveFlushMode = getSession().getHibernateFlushMode(); } @@ -1087,6 +1089,12 @@ public NativeQueryImplementor setHibernateFlushMode(FlushMode flushMode) { return this; } + @Override + public NativeQueryImplementor setForcedFlushMode(ForcedFlushMode forcedFlushMode) { + super.setForcedFlushMode(forcedFlushMode); + return this; + } + @Override public NativeQueryImplementor setFlushMode(FlushModeType flushModeType) { super.setFlushMode( flushModeType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeQueryImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeQueryImplementor.java index 59ced8e699bb..c16a99c142f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeQueryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/spi/NativeQueryImplementor.java @@ -14,6 +14,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.Incubating; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -149,6 +150,9 @@ NativeQueryImplementor addJoin( @Override NativeQueryImplementor setHibernateFlushMode(FlushMode flushMode); + @Override + NativeQueryImplementor setForcedFlushMode(ForcedFlushMode forcedFlushMode); + @Override NativeQueryImplementor setFlushMode(FlushModeType flushMode); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmSelectionQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmSelectionQuery.java index a4b450f5c5d2..cd2f13f0c646 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmSelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmSelectionQuery.java @@ -14,6 +14,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.query.BindableType; import org.hibernate.query.QueryParameter; import org.hibernate.query.SelectionQuery; @@ -82,7 +83,7 @@ public interface SqmSelectionQuery extends SqmQuery, SelectionQuery { SqmSelectionQuery setParameter(Parameter param, Date value, TemporalType temporalType); @Override - SqmSelectionQuery setParameterList(String name, Collection values); + SqmSelectionQuery setParameterList(String name, @SuppressWarnings("rawtypes") Collection values); @Override

SqmSelectionQuery setParameterList(String name, Collection values, Class

javaType); @@ -100,7 +101,7 @@ public interface SqmSelectionQuery extends SqmQuery, SelectionQuery {

SqmSelectionQuery setParameterList(String name, P[] values, BindableType

type); @Override - SqmSelectionQuery setParameterList(int position, Collection values); + SqmSelectionQuery setParameterList(int position, @SuppressWarnings("rawtypes") Collection values); @Override

SqmSelectionQuery setParameterList(int position, Collection values, Class

javaType); @@ -139,11 +140,14 @@ public interface SqmSelectionQuery extends SqmQuery, SelectionQuery { SqmSelectionQuery setProperties(Object bean); @Override - SqmSelectionQuery setProperties(Map bean); + SqmSelectionQuery setProperties(@SuppressWarnings("rawtypes") Map bean); @Override SqmSelectionQuery setHibernateFlushMode(FlushMode flushMode); + @Override + SqmSelectionQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode); + @Override SqmSelectionQuery setCacheMode(CacheMode cacheMode); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java index 9f0482d44616..9a7963113ae9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java @@ -21,6 +21,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -954,6 +955,12 @@ public SqmQueryImplementor setHibernateFlushMode(FlushMode flushMode) { return this; } + @Override + public SqmQueryImplementor setForcedFlushMode(ForcedFlushMode forcedFlushMode) { + super.setForcedFlushMode( forcedFlushMode ); + return this; + } + @Override public SqmQueryImplementor setFlushMode(FlushModeType flushMode) { applyJpaFlushMode( flushMode ); @@ -1133,7 +1140,7 @@ public NamedQueryMemento toMemento(String name) { isCacheable(), getCacheRegion(), getCacheMode(), - getHibernateFlushMode(), + getQueryOptions().getFlushMode(), isReadOnly(), getLockOptions(), getTimeout(), @@ -1152,7 +1159,7 @@ public NamedQueryMemento toMemento(String name) { isCacheable(), getCacheRegion(), getCacheMode(), - getHibernateFlushMode(), + getQueryOptions().getFlushMode(), isReadOnly(), getLockOptions(), getTimeout(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java index 2e10607a1ea9..7edb33787fc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmSelectionQueryImpl.java @@ -25,6 +25,7 @@ import org.hibernate.CacheMode; import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.ScrollMode; @@ -572,6 +573,12 @@ public SqmSelectionQuery setHibernateFlushMode(FlushMode flushMode) { return this; } + @Override + public SqmSelectionQuery setForcedFlushMode(ForcedFlushMode forcedFlushMode) { + super.setForcedFlushMode( forcedFlushMode ); + return this; + } + @Override public SqmSelectionQuery setTimeout(int timeout) { super.setTimeout( timeout ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java index c82ea89fc4cc..9e4e5f8c4a10 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryFlushModeTest.java @@ -25,7 +25,6 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; /** * @author Yoann Rodiere @@ -103,22 +102,22 @@ public void testNamedQueryWithFlushModePersistenceContext(EntityManagerFactorySc s.setHibernateFlushMode( FlushMode.MANUAL ); query = s.getNamedQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.COMMIT ); query = s.getNamedQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.AUTO ); query = s.getNamedQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.ALWAYS ); query = s.getNamedQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } ); @@ -185,22 +184,22 @@ public void testNamedNativeQueryWithFlushModePersistenceContext(EntityManagerFac s.setHibernateFlushMode( FlushMode.MANUAL ); query = s.getNamedNativeQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.COMMIT ); query = s.getNamedNativeQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.AUTO ); query = s.getNamedNativeQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); s.setHibernateFlushMode( FlushMode.ALWAYS ); query = s.getNamedNativeQuery( queryName ); - assertNull( query.getHibernateFlushMode() ); + assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryForcedFlushModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryForcedFlushModeTest.java new file mode 100644 index 000000000000..c1ec2069a268 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/query/NamedQueryForcedFlushModeTest.java @@ -0,0 +1,293 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.jpa.query; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import org.hibernate.FlushMode; +import org.hibernate.ForcedFlushMode; +import org.hibernate.Session; +import org.hibernate.annotations.NamedNativeQuery; +import org.hibernate.annotations.NamedQuery; +import org.hibernate.query.NativeQuery; +import org.hibernate.query.Query; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Yoann Rodiere + */ +@TestForIssue(jiraKey = "HHH-12795") +@Jpa(annotatedClasses = { + NamedQueryForcedFlushModeTest.TestEntity.class +}) +public class NamedQueryForcedFlushModeTest { + + @Test + public void testNamedQueryWithFlushModeManual(EntityManagerFactoryScope scope) { + String queryName = "NamedQueryFlushModeManual"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + Query query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); + // JPA flush mode is an approximation + assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); + } + ); + } + + @Test + public void testNamedQueryWithFlushModeCommit(EntityManagerFactoryScope scope) { + String queryName = "NamedQueryFlushModeCommit"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + Query query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); + } + ); + } + + @Test + public void testNamedQueryWithFlushModeAuto(EntityManagerFactoryScope scope) { + String queryName = "NamedQueryFlushModeAuto"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + Query query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); + } + ); + } + + @Test + public void testNamedQueryWithFlushModeAlways(EntityManagerFactoryScope scope) { + String queryName = "NamedQueryFlushModeAlways"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + Query query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); + // JPA flush mode is an approximation + assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); + } + ); + } + + @Test + public void testNamedQueryWithFlushModePersistenceContext(EntityManagerFactoryScope scope) { + String queryName = "NamedQueryFlushModePersistenceContext"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + Query query; + + // A null Hibernate flush mode means we will use whatever mode is set on the session + // JPA doesn't allow null flush modes, so we expect some approximation of the flush mode to be returned + + s.setHibernateFlushMode( FlushMode.MANUAL ); + query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); + assertEquals( ForcedFlushMode.NO_FORCING, query.getForcedFlushMode() ); + + s.setHibernateFlushMode( FlushMode.COMMIT ); + query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); + assertEquals( ForcedFlushMode.NO_FORCING, query.getForcedFlushMode() ); + + s.setHibernateFlushMode( FlushMode.AUTO ); + query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); + assertEquals( ForcedFlushMode.NO_FORCING, query.getForcedFlushMode() ); + + s.setHibernateFlushMode( FlushMode.ALWAYS ); + query = s.getNamedQuery( queryName ); + assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); + assertEquals( ForcedFlushMode.NO_FORCING, query.getForcedFlushMode() ); + } + ); + } + + @Test + public void testNamedNativeQueryWithFlushModeManual(EntityManagerFactoryScope scope) { + String queryName = "NamedNativeQueryFlushModeManual"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + NativeQuery query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); + assertEquals( ForcedFlushMode.FORCE_NO_FLUSH, query.getForcedFlushMode() ); + } + ); + } + + @Test + public void testNamedNativeQueryWithFlushModeCommit(EntityManagerFactoryScope scope) { + String queryName = "NamedNativeQueryFlushModeCommit"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + NativeQuery query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); + assertEquals( ForcedFlushMode.FORCE_NO_FLUSH, query.getForcedFlushMode() ); + } + ); + } + + @Test + public void testNamedNativeQueryWithFlushModeAuto(EntityManagerFactoryScope scope) { + String queryName = "NamedNativeQueryFlushModeAuto"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + NativeQuery query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); + assertEquals( ForcedFlushMode.NO_FORCING, query.getForcedFlushMode() ); + } + ); + } + + @Test + public void testNamedNativeQueryWithFlushModeAlways(EntityManagerFactoryScope scope) { + String queryName = "NamedNativeQueryFlushModeAlways"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + NativeQuery query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); + assertEquals( ForcedFlushMode.FORCE_FLUSH, query.getForcedFlushMode() ); + } + ); + } + + @Test + public void testNamedNativeQueryWithFlushModePersistenceContext(EntityManagerFactoryScope scope) { + String queryName = "NamedNativeQueryFlushModePersistenceContext"; + scope.inEntityManager( + entityManager -> { + Session s = entityManager.unwrap( Session.class ); + NativeQuery query; + + // A null Hibernate flush mode means we will use whatever mode is set on the session + // JPA doesn't allow null flush modes, so we expect some approximation of the flush mode to be returned + + s.setHibernateFlushMode( FlushMode.MANUAL ); + query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.MANUAL, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); + + s.setHibernateFlushMode( FlushMode.COMMIT ); + query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.COMMIT, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.COMMIT, query.getFlushMode() ); + + s.setHibernateFlushMode( FlushMode.AUTO ); + query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.AUTO, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); + + s.setHibernateFlushMode( FlushMode.ALWAYS ); + query = s.getNamedNativeQuery( queryName ); + assertEquals( FlushMode.ALWAYS, query.getHibernateFlushMode() ); + assertEquals( jakarta.persistence.FlushModeType.AUTO, query.getFlushMode() ); + } + ); + } + + @Entity(name = "TestEntity") + @NamedQuery( + name = "NamedQueryFlushModeManual", + query = "select e from TestEntity e where e.text = :text", + flush = ForcedFlushMode.FORCE_NO_FLUSH + ) + @NamedQuery( + name = "NamedQueryFlushModeCommit", + query = "select e from TestEntity e where e.text = :text", + flush = ForcedFlushMode.FORCE_NO_FLUSH + ) + @NamedQuery( + name = "NamedQueryFlushModeAuto", + query = "select e from TestEntity e where e.text = :text", + flush = ForcedFlushMode.NO_FORCING + ) + @NamedQuery( + name = "NamedQueryFlushModeAlways", + query = "select e from TestEntity e where e.text = :text", + flush = ForcedFlushMode.FORCE_FLUSH + ) + @NamedQuery( + name = "NamedQueryFlushModePersistenceContext", + query = "select e from TestEntity e where e.text = :text", + flush = ForcedFlushMode.NO_FORCING + ) + @NamedNativeQuery( + name = "NamedNativeQueryFlushModeManual", + query = "select * from TestEntity e where e.text = :text", + resultClass = TestEntity.class, + flush = ForcedFlushMode.FORCE_NO_FLUSH + ) + @NamedNativeQuery( + name = "NamedNativeQueryFlushModeCommit", + query = "select * from TestEntity e where e.text = :text", + resultClass = TestEntity.class, + flush = ForcedFlushMode.FORCE_NO_FLUSH + ) + @NamedNativeQuery( + name = "NamedNativeQueryFlushModeAuto", + query = "select * from TestEntity e where e.text = :text", + resultClass = TestEntity.class, + flush = ForcedFlushMode.NO_FORCING + ) + @NamedNativeQuery( + name = "NamedNativeQueryFlushModeAlways", + query = "select * from TestEntity e where e.text = :text", + resultClass = TestEntity.class, + flush = ForcedFlushMode.FORCE_FLUSH + ) + @NamedNativeQuery( + name = "NamedNativeQueryFlushModePersistenceContext", + query = "select * from TestEntity e where e.text = :text", + resultClass = TestEntity.class, + flush = ForcedFlushMode.NO_FORCING + ) + + public static class TestEntity { + @Id + @GeneratedValue + private Long id; + + private String text; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + } +}