diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index 10e0fea510..7149dfb61d 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -1360,9 +1360,8 @@ public interface Session extends SharedSessionContract, EntityManager { boolean getScope(); /** - * Check if locking extends to owned collections and associated entities. - * - * @return true if locking will be extended to owned collections and associated entities + * Obtain the {@link PessimisticLockScope}, which determines if locking + * extends to owned collections and associated entities. */ default PessimisticLockScope getLockScope() { return getScope() ? PessimisticLockScope.EXTENDED : PessimisticLockScope.NORMAL; @@ -1383,6 +1382,10 @@ public interface Session extends SharedSessionContract, EntityManager { @Deprecated(since = "6.2") LockRequest setScope(boolean scope); + /** + * Set the {@link PessimisticLockScope}, which determines if locking + * extends to owned collections and associated entities. + */ default LockRequest setLockScope(PessimisticLockScope scope) { return setScope( scope == PessimisticLockScope.EXTENDED ); } @@ -1444,7 +1447,7 @@ public interface Session extends SharedSessionContract, EntityManager { Query createQuery(CriteriaQuery criteriaQuery); /** - * Create a {@link Query} for the given JPA {@link CriteriaDelete} + * Create a {@link Query} for the given JPA {@link CriteriaDelete}. * * @deprecated use {@link #createMutationQuery(CriteriaDelete)} */ @@ -1452,7 +1455,7 @@ public interface Session extends SharedSessionContract, EntityManager { Query createQuery(CriteriaDelete deleteQuery); /** - * Create a {@link Query} for the given JPA {@link CriteriaUpdate} + * Create a {@link Query} for the given JPA {@link CriteriaUpdate}. * * @deprecated use {@link #createMutationQuery(CriteriaUpdate)} */ 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 bde8d708e7..0dbfa45fe8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java +++ b/hibernate-core/src/main/java/org/hibernate/query/CommonQueryContract.java @@ -21,9 +21,9 @@ import jakarta.persistence.TemporalType; /** * Defines the aspects of query execution and parameter binding that apply to all - * forms of querying - HQL, {@linkplain jakarta.persistence.criteria.CriteriaBuilder - * criteria queries}, and {@link org.hibernate.procedure.ProcedureCall stored - * procedure calls}. + * forms of querying: HQL/JPQL queries, native SQL queries, + * {@linkplain jakarta.persistence.criteria.CriteriaBuilder criteria queries}, and + * {@linkplain org.hibernate.procedure.ProcedureCall stored procedure calls}. * * @author Steve Ebersole * @author Gavin King 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 1738477c92..ee8c7ff619 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/MutationQuery.java @@ -19,9 +19,34 @@ import jakarta.persistence.Parameter; import jakarta.persistence.TemporalType; /** - * Models a mutation (insert, update, or delete) query. It is a slimmed - * down version of {@link Query}, but providing only methods relevant to - * mutation queries. + * Within the context of an active {@linkplain org.hibernate.Session session}, + * an instance of this type represents an executable mutation query, that is, + * an {@code insert}, {@code update}, or {@code delete}. It is a slimmed-down + * version of {@link Query}, providing only methods relevant to mutation queries. + *

+ * A {@code MutationQuery} may be obtained from the {@link org.hibernate.Session} + * by calling: + *

    + *
  • {@link QueryProducer#createMutationQuery(String)}, passing the HQL as a + * string, + *
  • {@link QueryProducer#createNativeMutationQuery(String)}, passing native + * SQL as a string, + *
  • {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)} or + * {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete)}, + * passing a criteria update or delete object, or + *
  • {@link QueryProducer#createNamedMutationQuery(String)}, passing the + * name of a query defined using {@link jakarta.persistence.NamedQuery} or + * {@link jakarta.persistence.NamedNativeQuery}. + *
+ *

+ * A {@code MutationQuery} controls how the mutation query is executed, and + * allows arguments to be bound to its parameters. + *

    + *
  • Mutation queries must be executed using {@link #executeUpdate()}. + *
  • The various overloads of {@link #setParameter(String, Object)} and + * {@link #setParameter(int, Object)} allow arguments to be bound to named + * and ordinal parameters defined by the query. + *
* * @author Steve Ebersole */ 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 ed476902bc..6e2ac20e5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/NativeQuery.java @@ -49,9 +49,14 @@ import org.hibernate.type.BasicTypeReference; * *

* A {@code NativeQuery} may be obtained from the {@link org.hibernate.Session} - * by calling {@link QueryProducer#createNativeQuery(String, Class)}, - * {@link QueryProducer#createNativeQuery(String, String, Class)}, or - * {@link QueryProducer#createNativeMutationQuery(String)}. + * by calling: + *

    + *
  • {@link QueryProducer#createNativeQuery(String, Class)}, passing + * native SQL as a string, or + *
  • {@link QueryProducer#createNativeQuery(String, String, Class)} + * passing the native SQL string and the name of a result set mapping + * defined using {@link jakarta.persistence.SqlResultSetMapping}. + *
*

* A result set mapping may be specified by: *

    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 22f61ae6e2..41815e1da7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -58,28 +58,30 @@ import jakarta.persistence.TypedQuery; * A {@code Query} may be obtained from the {@link org.hibernate.Session} by * calling: *
      - *
    • {@link QueryProducer#createQuery(String, Class)}, - * {@link QueryProducer#createQuery(jakarta.persistence.criteria.CriteriaQuery)}, - * or {@link QueryProducer#createNamedQuery(String, Class)} for - * selection queries, or - *
    • {@link QueryProducer#createMutationQuery(String)}, - * {@link QueryProducer#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)}, - * or {@link QueryProducer#createNamedMutationQuery(String)} for - * mutation queries. + *
    • {@link QueryProducer#createQuery(String, Class)}, passing the HQL as a + * string, + *
    • {@link QueryProducer#createQuery(jakarta.persistence.criteria.CriteriaQuery)}, + * passing a {@linkplain jakarta.persistence.criteria.CriteriaQuery criteria + * object}, or + *
    • {@link QueryProducer#createNamedQuery(String, Class)} passing the name + * of a query defined using {@link jakarta.persistence.NamedQuery} or + * {@link jakarta.persistence.NamedNativeQuery}. *
    *

    * A {@code Query} controls how a query is executed, and allows arguments to be * bound to its parameters. *

      *
    • Selection queries are usually executed using {@link #getResultList()} or - * {@link #getSingleResult()}, and mutation queries must be executed using - * {@link #executeUpdate()}. + * {@link #getSingleResult()}. *
    • The methods {@link #setMaxResults(int)} and {@link #setFirstResult(int)} * control limits and pagination. *
    • The various overloads of {@link #setParameter(String, Object)} and * {@link #setParameter(int, Object)} allow arguments to be bound to named * and ordinal parameters defined by the query. *
    + *

    + * Note that this interface offers no real advantages over {@link SelectionQuery} + * except for compatibility with the JPA-defined {@link TypedQuery} interface. * * @author Gavin King * @author Steve Ebersole diff --git a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java index f2c66490ba..8528faa72f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/QueryProducer.java @@ -62,7 +62,7 @@ public interface QueryProducer { Query createQuery(String queryString, Class resultClass); /** - * Create a {@link Query} for the given JPA {@link CriteriaQuery} + * Create a {@link Query} for the given JPA {@link CriteriaQuery}. */ Query createQuery(CriteriaQuery criteriaQuery); @@ -222,7 +222,7 @@ public interface QueryProducer { MutationQuery createMutationQuery(@SuppressWarnings("rawtypes") JpaCriteriaInsertSelect insertSelect); /** - * Create a {@link NativeQuery} instance for the given native (SQL) statement + * Create a {@link NativeQuery} instance for the given native SQL statement. * * @param sqlString a native SQL statement string * @@ -298,9 +298,6 @@ public interface QueryProducer { */ MutationQuery createNamedMutationQuery(String name); - - - /** * Create a {@link Query} instance for the named query. * 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 7a4a67ac3f..54acac7e13 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java @@ -36,8 +36,35 @@ import jakarta.persistence.Parameter; import jakarta.persistence.TemporalType; /** - * Models a selection query returning results. It is a slimmed down version - * of {@link Query}, but providing only methods relevant to selection queries. + * Within the context of an active {@linkplain org.hibernate.Session session}, + * an instance of this type represents an executable selection query, that is, + * a {@code select}. It is a slimmed-down version of {@link Query}, providing + * only methods relevant to selection queries. + *

    + * A {@code SelectionQuery} may be obtained from the {@link org.hibernate.Session} + * by calling: + *

      + *
    • {@link QueryProducer#createSelectionQuery(String, Class)}, passing the + * HQL as a string, + *
    • {@link QueryProducer#createSelectionQuery(jakarta.persistence.criteria.CriteriaQuery)}, + * passing a {@linkplain jakarta.persistence.criteria.CriteriaQuery criteria + * query object}, or + *
    • {@link QueryProducer#createNamedSelectionQuery(String, Class)} passing + * the name of a query defined using {@link jakarta.persistence.NamedQuery} + * or {@link jakarta.persistence.NamedNativeQuery}. + *
    + *

    + * A {@code SelectionQuery} controls how a query is executed, and allows arguments + * to be bound to its parameters. + *

      + *
    • Selection queries are usually executed using {@link #getResultList()} or + * {@link #getSingleResult()}. + *
    • The methods {@link #setMaxResults(int)} and {@link #setFirstResult(int)} + * control limits and pagination. + *
    • The various overloads of {@link #setParameter(String, Object)} and + * {@link #setParameter(int, Object)} allow arguments to be bound to named + * and ordinal parameters defined by the query. + *
    * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/package-info.java b/hibernate-core/src/main/java/org/hibernate/query/package-info.java index 9b7dd0a706..3f5abfcadc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/query/package-info.java @@ -7,5 +7,20 @@ /** * Everything related to HQL/JPQL, native SQL, and criteria queries. + *

    + * The important interfaces {@link org.hibernate.query.SelectionQuery}, + * {@link org.hibernate.query.MutationQuery}, {@link org.hibernate.query.Query}, + * and {@link org.hibernate.query.NativeQuery} provide an API for executing + * queries. Instances of these interfaces may be obtained from a + * {@link org.hibernate.query.QueryProducer}, that is, from any + * {@link org.hibernate.Session} or {@link org.hibernate.StatelessSession}. + *

    + * Hibernate's extensions to the JPA criteria query API are defined in the + * subpackage {@link org.hibernate.query.criteria}, with + * {@link org.hibernate.query.criteria.HibernateCriteriaBuilder} as the + * entry point. + *

    + * Other subpackages contain SPIs and internal implementation details, + * including the HQL parser and translator. */ package org.hibernate.query; diff --git a/hibernate-core/src/test/java/org/hibernate/BugTest.java b/hibernate-core/src/test/java/org/hibernate/BugTest.java new file mode 100644 index 0000000000..889ecf7e3c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/BugTest.java @@ -0,0 +1,43 @@ +package org.hibernate; + +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import java.util.List; + +@SessionFactory +@DomainModel (annotatedClasses = {BugTest.MyInstance.class, BugTest.My.class}) +public class BugTest { + + @Test void test(SessionFactoryScope scope) { + scope.inTransaction( s -> s.persist( new My() ) ); + scope.inTransaction( + s -> s.createMutationQuery("update My m set m.smallintCol = cast(1 as Short)") + .executeUpdate() + ); + } + + @MappedSuperclass + static abstract class MyInstance { + @Column(name = "iface_ids", columnDefinition = "TEXT") + @Convert(converter = StringListToStringConverter.class) + List interfaceIds = List.of("a", "b", "c"); + } + + @Entity(name="My") + static class My extends MyInstance { + @Id @GeneratedValue + Long id; + + @Column(name = "smallint_col", nullable = false) + private short smallintCol; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/StringListToStringConverter.java b/hibernate-core/src/test/java/org/hibernate/StringListToStringConverter.java new file mode 100644 index 0000000000..dcbe4826ca --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/StringListToStringConverter.java @@ -0,0 +1,18 @@ +package org.hibernate; + +import jakarta.persistence.AttributeConverter; + +import java.util.Arrays; +import java.util.List; + +public class StringListToStringConverter implements AttributeConverter, String> { + @Override + public String convertToDatabaseColumn(List attribute) { + return attribute.toString(); + } + + @Override + public List convertToEntityAttribute(String dbData) { + return Arrays.asList( dbData.split(",") ); + } +}