From df1f13702dc972e5f4ee78ad56d44e1ac1c6e469 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 19 Feb 2025 17:16:08 +0100 Subject: [PATCH 1/2] [#2104] Create Mutiny.SharedSessionContract interface --- .../org/hibernate/reactive/mutiny/Mutiny.java | 1390 +++++++---------- .../mutiny/impl/MutinySessionImpl.java | 5 + .../impl/MutinyStatelessSessionImpl.java | 234 +-- .../session/ReactiveQueryProducer.java | 3 + .../reactive/session/ReactiveSession.java | 3 - .../session/ReactiveStatelessSession.java | 3 + .../impl/ReactiveStatelessSessionImpl.java | 7 + 7 files changed, 750 insertions(+), 895 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java index e6cdab9d5..2131f57a7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java @@ -518,399 +518,404 @@ default Query setLockMode(String alias, LockModeType lockModeType) { Query enableFetchProfile(String profileName); } + interface SharedSessionContract extends Closeable { + /** + * Create an instance of {@link SelectionQuery} for the given HQL/JPQL + * query string. + * + * @param queryString The HQL/JPQL query + * + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String, Class) + */ + SelectionQuery createSelectionQuery(String queryString, Class resultType); - /** - * A non-blocking counterpart to the Hibernate {@link org.hibernate.Session} - * interface, allowing a reactive style of interaction with the database. - *

- * The semantics of operations on this interface are identical to the - * semantics of the similarly-named operations of {@code Session}, except - * that the operations are performed asynchronously, returning a {@link Uni} - * without blocking the calling thread. - *

- * Entities associated with an {@code Session} do not support transparent - * lazy association fetching. Instead, {@link #fetch(Object)} should be used - * to explicitly request asynchronous fetching of an association, or the - * association should be fetched eagerly when the entity is first retrieved, - * for example, by: - * - *

    - *
  • {@link #enableFetchProfile(String) enabling a fetch profile}, - *
  • using an {@link EntityGraph}, or - *
  • writing a {@code join fetch} clause in a HQL query. - *
- * - * @see org.hibernate.Session - */ - interface Session extends Closeable { + /** + * Create an instance of {@link MutationQuery} for the given HQL/JPQL + * update or delete statement. + * + * @param queryString The HQL/JPQL query, update or delete statement + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String) + */ + MutationQuery createMutationQuery(String queryString); /** - * Asynchronously return the persistent instance of the given entity - * class with the given identifier, or {@code null} if there is no such - * persistent instance. If the instance is already associated with - * the session, return the associated instance. This method never - * returns an uninitialized instance. + * Create an instance of {@link MutationQuery} for the given update tree. * - *
-		 * {@code session.find(Book.class, id).map(book -> print(book.getTitle()));}
-		 * 
+ * @param updateQuery the update criteria query * - * @param entityClass The entity type - * @param id an identifier + * @return The {@link MutationQuery} instance for manipulation and execution * - * @return a persistent instance or null via a {@code Uni} + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) + */ + MutationQuery createMutationQuery(CriteriaUpdate updateQuery); + + /** + * Create an instance of {@link MutationQuery} for the given delete tree. * - * @see jakarta.persistence.EntityManager#find(Class, Object) + * @param deleteQuery the delete criteria query + * + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) */ - Uni find(Class entityClass, Object id); + MutationQuery createMutationQuery(CriteriaDelete deleteQuery); /** - * Asynchronously return the persistent instance of the given entity - * class with the given identifier, requesting the given {@link LockMode}. + * Create a {@link MutationQuery} from the given insert select criteria tree * - * @param entityClass The entity type - * @param id an identifier - * @param lockMode the requested {@link LockMode} + * @param insert the insert select criteria query * - * @return a persistent instance or null via a {@code Uni} + * @return The {@link MutationQuery} instance for manipulation and execution * - * @see #find(Class, Object) - * @see #lock(Object, LockMode) this discussion of lock modes + * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) */ - Uni find(Class entityClass, Object id, LockMode lockMode); + MutationQuery createMutationQuery(JpaCriteriaInsert insert); /** - * Asynchronously return the persistent instance of the given entity - * class with the given identifier, requesting the given {@link LockModeType}. + * Create an instance of {@link Query} for the given HQL/JPQL query + * string or HQL/JPQL update or delete statement. In the case of an + * update or delete, the returned {@link Query} must be executed using + * {@link Query#executeUpdate()} which returns an affected row count. * - * @param entityClass The entity type - * @param id an identifier - * @param lockModeType the requested {@link LockModeType} + * @param queryString The HQL/JPQL query, update or delete statement * - * @return a persistent instance or null via a {@code Uni} + * @return The {@link Query} instance for manipulation and execution * - * @see #find(Class, Object) - * @see #lock(Object, LockMode) this discussion of lock modes + * @deprecated See explanation in + * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)} + * + * @see jakarta.persistence.EntityManager#createQuery(String) */ - default Uni find(Class entityClass, Object id, LockModeType lockModeType) { - return find( entityClass, id, convertToLockMode( lockModeType ) ); - } + @Deprecated + Query createQuery(String queryString); /** - * Asynchronously return the persistent instance with the given - * identifier of an entity class, using the given {@link EntityGraph} - * as a fetch plan. + * Create an instance of {@link SelectionQuery} for the given HQL/JPQL + * query string and query result type. * - * @param entityGraph an {@link EntityGraph} specifying the entity - * and associations to be fetched - * @param id an identifier + * @param queryString The HQL/JPQL query + * @param resultType the Java type returned in each row of query results * - * @see #find(Class, Object) + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String, Class) */ - Uni find(EntityGraph entityGraph, Object id); + SelectionQuery createQuery(String queryString, Class resultType); /** - * Asynchronously return the persistent instances of the given entity - * class with the given identifiers, or null if there is no such - * persistent instance. + * Create an instance of {@link SelectionQuery} for the given criteria + * query. * - * @param entityClass The entity type - * @param ids the identifiers + * @param criteriaQuery The {@link CriteriaQuery} * - * @return a list of persistent instances and nulls via a {@code Uni} + * @return The {@link SelectionQuery} instance for manipulation and execution * - * @see org.hibernate.Session#findMultiple(Class, List, FindOption...) + * @see jakarta.persistence.EntityManager#createQuery(String) */ - Uni> find(Class entityClass, Object... ids); + SelectionQuery createQuery(CriteriaQuery criteriaQuery); /** - * Asynchronously return the persistent instance of the given entity - * class with the given natural identifier, or null if there is no - * such persistent instance. + * Create an instance of {@link MutationQuery} for the given criteria update. * - * @param entityClass The entity type - * @param naturalId the natural identifier + * @param criteriaUpdate The {@link CriteriaUpdate} * - * @return a persistent instance or null via a {@code Uni} + * @return The {@link MutationQuery} instance for manipulation and execution */ - @Incubating - Uni find(Class entityClass, Identifier naturalId); + MutationQuery createQuery(CriteriaUpdate criteriaUpdate); /** - * Return the persistent instance of the given entity class with the - * given identifier, assuming that the instance exists. This method - * never results in access to the underlying data store, and thus - * might return a proxied instance that must be initialized explicitly - * using {@link #fetch(Object)}. - *

- * You should not use this method to determine if an instance exists - * (use {@link #find} instead). Use this only to retrieve an instance - * which you safely assume exists, where non-existence would be an - * actual error. + * Create an instance of {@link MutationQuery} for the given criteria delete. * - * @param entityClass a persistent class - * @param id a valid identifier of an existing persistent instance of the class + * @param criteriaDelete The {@link CriteriaDelete} * - * @return the persistent instance or proxy + * @return The {@link MutationQuery} instance for manipulation and execution + */ + MutationQuery createQuery(CriteriaDelete criteriaDelete); + + /** + * Create an instance of {@link Query} for the named query. * - * @see jakarta.persistence.EntityManager#getReference(Class, Object) + * @param queryName The name of the query + * + * @return The {@link Query} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String) */ - T getReference(Class entityClass, Object id); + Query createNamedQuery(String queryName); /** - * Return the persistent instance with the same identity as the given - * instance, which might be detached, assuming that the instance is - * still persistent in the database. This method never results in - * access to the underlying data store, and thus might return a proxy - * that must be initialized explicitly using {@link #fetch(Object)}. + * Create an instance of {@link SelectionQuery} for the named query. * - * @param entity a detached persistent instance + * @param queryName The name of the query + * @param resultType the Java type returned in each row of query results * - * @return the persistent instance or proxy + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String, Class) */ - T getReference(T entity); + SelectionQuery createNamedQuery(String queryName, Class resultType); /** - * Asynchronously persist the given transient instance, first assigning - * a generated identifier. (Or using the current value of the identifier - * property if the entity has assigned identifiers.) + * Create an instance of {@link Query} for the given SQL query string, + * or SQL update, insert, or delete statement. In the case of an update, + * insert, or delete, the returned {@link Query} must be executed using + * {@link Query#executeUpdate()} which returns an affected row count. + * In the case of a query: + * + *

    + *
  • If the result set has a single column, the results will be returned + * as scalars.
  • + *
  • Otherwise, if the result set has multiple columns, the results will + * be returned as elements of arrays of type {@code Object[]}.
  • + *
+ * + * @param queryString The SQL select, update, insert, or delete statement + */ + Query createNativeQuery(String queryString); + + /** + * Create an instance of {@link Query} for the given SQL query string, + * or SQL update, insert, or delete statement. In the case of an update, + * insert, or delete, the returned {@link Query} must be executed using + * {@link Query#executeUpdate()} which returns an affected row count. + * In the case of a query: + * + *
    + *
  • If the result set has a single column, the results will be returned + * as scalars.
  • + *
  • Otherwise, if the result set has multiple columns, the results will + * be returned as elements of arrays of type {@code Object[]}.
  • + *
*

- * This operation cascades to associated instances if the association is - * mapped with {@link jakarta.persistence.CascadeType#PERSIST}. + * Any {@link AffectedEntities affected entities} are synchronized with + * the database before execution of the statement. * - *

-		 * {@code session.persist(newBook).map(v -> session.flush());}
-		 * 
+ * @param queryString The SQL select, update, insert, or delete statement + * @param affectedEntities The entities which are affected by the statement + */ + Query createNativeQuery(String queryString, AffectedEntities affectedEntities); + + /** + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@code resultType} to interpret the results. * - * @param object a transient instance of a persistent class + *
    + *
  • If the given result type is {@link Object}, or a built-in type + * such as {@link String} or {@link Integer}, the result set must + * have a single column, which will be returned as a scalar. + *
  • If the given result type is {@code Object[]}, then the result set + * must have multiple columns, which will be returned in arrays. + *
  • Otherwise, the given result type must be an entity class, in which + * case the result set column aliases must map to the fields of the + * entity, and the query will return instances of the entity. + *
* - * @see jakarta.persistence.EntityManager#persist(Object) + * @param queryString The SQL query + * @param resultType the Java type returned in each row of query results + * + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) */ - Uni persist(Object object); + SelectionQuery createNativeQuery(String queryString, Class resultType); /** - * Make a transient instance persistent and mark it for later insertion in the - * database. This operation cascades to associated instances if the association - * is mapped with {@link jakarta.persistence.CascadeType#PERSIST}. + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@code resultType} to interpret the results. + * + *
    + *
  • If the given result type is {@link Object}, or a built-in type + * such as {@link String} or {@link Integer}, the result set must + * have a single column, which will be returned as a scalar. + *
  • If the given result type is {@code Object[]}, then the result set + * must have multiple columns, which will be returned in arrays. + *
  • Otherwise, the given result type must be an entity class, in which + * case the result set column aliases must map to the fields of the + * entity, and the query will return instances of the entity. + *
*

- * For entities with a {@link jakarta.persistence.GeneratedValue generated id}, - * {@code persist()} ultimately results in generation of an identifier for the - * given instance. But this may happen asynchronously, when the session is - * {@linkplain #flush() flushed}, depending on the identifier generation strategy. + * Any {@link AffectedEntities affected entities} are synchronized with + * the database before execution of the query. * - * @param entityName the entity name - * @param object a transient instance to be made persistent - * @see #persist(Object) + * @param queryString The SQL query + * @param resultType the Java type returned in each row of query results + * @param affectedEntities The entities which are affected by the query + * + * @return The {@link Query} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) */ - Uni persist(String entityName, Object object); + SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities); /** - * Persist multiple transient entity instances at once. + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@link ResultSetMapping} to interpret the + * result set. * - * @see #persist(Object) + * @param queryString The SQL query + * @param resultSetMapping the result set mapping + * + * @return The {@link Query} instance for manipulation and execution + * + * @see #getResultSetMapping(Class, String) + * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) */ - Uni persistAll(Object... entities); + SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping); /** - * Asynchronously remove a persistent instance from the datastore. The - * argument may be an instance associated with the receiving session or - * a transient instance with an identifier associated with existing - * persistent state. + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@link ResultSetMapping} to interpret the + * result set. *

- * This operation cascades to associated instances if the association is - * mapped with {@link jakarta.persistence.CascadeType#REMOVE}. + * Any {@link AffectedEntities affected entities} are synchronized with the + * database before execution of the query. + * + * @param queryString The SQL query + * @param resultSetMapping the result set mapping + * @param affectedEntities The entities which are affected by the query + * + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see #getResultSetMapping(Class, String) + * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) + */ + SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities); + + /** + * Fetch a lazy property of the given entity, identified by a JPA + * {@link Attribute attribute metamodel}. Note that this feature is + * only supported in conjunction with the Hibernate bytecode enhancer. + * + *

+		 * {@code session.fetch(book, Book_.isbn).thenAccept(isbn -> print(isbn))}
+		 * 
+ */ + Uni fetch(E entity, Attribute field); + + /** + * Return the identifier value of the given entity, which may be detached. * - *
-		 * {@code session.delete(book).thenAccept(v -> session.flush());}
-		 * 
+ * @param entity a persistent instance associated with this session * - * @param entity the managed persistent instance to be removed + * @return the identifier * - * @throws IllegalArgumentException if the given instance is not managed - * @see jakarta.persistence.EntityManager#remove(Object) + * @since 3.0 */ - Uni remove(Object entity); + Object getIdentifier(Object entity); /** - * Remove multiple entity instances at once. - * - * @see #remove(Object) + * Obtain a native SQL result set mapping defined via the annotation + * {@link jakarta.persistence.SqlResultSetMapping}. */ - Uni removeAll(Object... entities); + ResultSetMapping getResultSetMapping(Class resultType, String mappingName); /** - * Copy the state of the given object onto the persistent instance with - * the same identifier. If there is no such persistent instance currently - * associated with the session, it will be loaded. Return the persistent - * instance. Or, if the given instance is transient, save a copy of it - * and return the copy as a newly persistent instance. The given instance - * does not become associated with the session. - *

- * This operation cascades to associated instances if the association is - * mapped with {@link jakarta.persistence.CascadeType#MERGE}. - * - * @param entity a detached instance with state to be copied - * - * @return an updated persistent instance - * - * @see jakarta.persistence.EntityManager#merge(Object) + * Obtain a named {@link EntityGraph} */ - Uni merge(T entity); + EntityGraph getEntityGraph(Class rootType, String graphName); /** - * Merge multiple entity instances at once. - * - * @see #merge(Object) + * Create a new mutable {@link EntityGraph} */ - Uni mergeAll(Object... entities); + EntityGraph createEntityGraph(Class rootType); /** - * Re-read the state of the given instance from the underlying database. - * It is inadvisable to use this to implement long-running sessions that - * span many business tasks. This method is, however, useful in certain - * special circumstances, for example: - * - *

    - *
  • where a database trigger alters the object state after insert or - * update, or - *
  • after executing direct native SQL in the same session. - *
- * - * @param entity a managed persistent instance - * - * @throws IllegalArgumentException if the given instance is not managed - * @see jakarta.persistence.EntityManager#refresh(Object) + * Create a new mutable copy of a named {@link EntityGraph} */ - Uni refresh(Object entity); + EntityGraph createEntityGraph(Class rootType, String graphName); /** - * Re-read the state of the given instance from the underlying database, - * requesting the given {@link LockMode}. + * Performs the given work within the scope of a database transaction, + * automatically flushing the session. The transaction will be rolled + * back if the work completes with an uncaught exception, or if + * {@link Transaction#markForRollback()} is called. + * + *
  • If there is already a transaction associated with this session, + * the work is executed in the context of the existing transaction, and + * no new transaction is initiated. + *
  • If there is no transaction associated with this session, a new + * transaction is started, and the work is executed in the context of + * the new transaction. + * * - * @param entity a managed persistent entity instance - * @param lockMode the requested lock mode + * @param work a function which accepts {@link Transaction} and returns + * the result of the work as a {@link Uni}. * - * @see #refresh(Object) + * @see SessionFactory#withTransaction(BiFunction) */ - Uni refresh(Object entity, LockMode lockMode); + Uni withTransaction(Function> work); /** - * Re-read the state of the given instance from the underlying database, - * requesting the given {@link LockModeType}. + * Obtain the transaction currently associated with this session, + * if any. * - * @param entity a managed persistent entity instance - * @param lockModeType the requested lock mode + * @return the {@link Transaction}, or null if no transaction + * was started using {@link #withTransaction(Function)}. * - * @see #refresh(Object) + * @see #withTransaction(Function) + * @see SessionFactory#withTransaction(BiFunction) */ - default Uni refresh(Object entity, LockModeType lockModeType) { - return refresh( entity, convertToLockMode( lockModeType ) ); - } + Transaction currentTransaction(); /** - * Refresh multiple entity instances at once. - * - * @see #refresh(Object) + * @return false if {@link #close()} has been called */ - Uni refreshAll(Object... entities); + boolean isOpen(); /** - * Obtain the specified lock level upon the given object. For example, - * this operation may be used to: - * - *
      - *
    • perform a version check with {@link LockMode#PESSIMISTIC_READ}, - *
    • upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}, - *
    • force a version increment with {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}, - *
    • schedule a version check just before the end of the transaction with - * {@link LockMode#OPTIMISTIC}, or - *
    • schedule a version increment just before the end of the transaction - * with {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}. - *
    - *

    - * This operation cascades to associated instances if the association is - * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. - * - * @param entity a managed persistent instance - * @param lockMode the lock level - * - * @throws IllegalArgumentException if the given instance is not managed + * Close the reactive session and release the underlying database + * connection. */ - Uni lock(Object entity, LockMode lockMode); + Uni close(); /** - * Obtain the specified lock level upon the given object. For example, - * this operation may be used to: + * The {@link SessionFactory} which created this session. + */ + SessionFactory getFactory(); + + /** + * Determine if the fetch profile with the given name is enabled for this + * session. * - *

      - *
    • perform a version check with {@link LockModeType#PESSIMISTIC_READ}, - *
    • upgrade to a pessimistic lock with {@link LockModeType#PESSIMISTIC_WRITE}, - *
    • force a version increment with {@link LockModeType#PESSIMISTIC_FORCE_INCREMENT}, - *
    • schedule a version check just before the end of the transaction with - * {@link LockModeType#OPTIMISTIC}, or - *
    • schedule a version increment just before the end of the transaction - * with {@link LockModeType#OPTIMISTIC_FORCE_INCREMENT}. - *
    - *

    - * This operation cascades to associated instances if the association is - * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. + * @param name The name of the profile to be checked. * - * @param entity a managed persistent instance - * @param lockModeType the lock level + * @return True if fetch profile is enabled; false if not. * - * @throws IllegalArgumentException if the given instance is not managed + * @throws org.hibernate.UnknownProfileException Indicates that the given name does not + * match any known profile names + * @see org.hibernate.engine.profile.FetchProfile for discussion of this feature */ - default Uni lock(Object entity, LockModeType lockModeType) { - return lock( entity, convertToLockMode( lockModeType ) ); - } + boolean isFetchProfileEnabled(String name); /** - * Force this session to flush asynchronously. Must be called at the - * end of a unit of work, before committing the transaction and closing - * the session. Flushing is the process of synchronizing the - * underlying persistent store with state held in memory. + * Enable the named filter for this session. * - *

    -		 * {@code session.flush().thenAccept(v -> print("done saving changes"));}
    -		 * 
    + * @param filterName The name of the filter to be enabled. * - * @see jakarta.persistence.EntityManager#flush() + * @return The Filter instance representing the enabled filter. */ - Uni flush(); + Filter enableFilter(String filterName); /** - * Asynchronously fetch an association that's configured for lazy loading. - *

    - *

    -		 * {@code session.fetch(author.getBook()).thenAccept(book -> print(book.getTitle()));}
    -		 * 
    - *

    - *

    - * It can also initialize proxys. For example: - *

    -		 * {@code session.fetch(session.getReference(Author.class, authorId))}
    -		 * 
    - *

    - * @param association a lazy-loaded association, or a proxy - * - * @return the fetched association, via a {@code Uni} + * Disable the named filter for this session. * - * @see Mutiny#fetch(Object) - * @see #getReference(Class, Object) - * @see org.hibernate.Hibernate#initialize(Object) + * @param filterName The name of the filter to be disabled. */ - Uni fetch(T association); + void disableFilter(String filterName); /** - * Fetch a lazy property of the given entity, identified by a JPA - * {@link Attribute attribute metamodel}. Note that this feature is - * only supported in conjunction with the Hibernate bytecode enhancer. + * Retrieve a currently enabled filter by name. * - *
    -		 * {@code session.fetch(book, Book_.isbn).thenAccept(isbn -> print(isbn))}
    -		 * 
    + * @param filterName The name of the filter to be retrieved. + * + * @return The Filter instance representing the enabled filter. */ - Uni fetch(E entity, Attribute field); + Filter getEnabledFilter(String filterName); /** * Asynchronously fetch an association that's configured for lazy loading, @@ -927,288 +932,410 @@ default Uni lock(Object entity, LockModeType lockModeType) { * @see org.hibernate.Hibernate#unproxy(Object) */ Uni unproxy(T association); + } + + /** + * A non-blocking counterpart to the Hibernate {@link org.hibernate.Session} + * interface, allowing a reactive style of interaction with the database. + *

    + * The semantics of operations on this interface are identical to the + * semantics of the similarly-named operations of {@code Session}, except + * that the operations are performed asynchronously, returning a {@link Uni} + * without blocking the calling thread. + *

    + * Entities associated with an {@code Session} do not support transparent + * lazy association fetching. Instead, {@link #fetch(Object)} should be used + * to explicitly request asynchronous fetching of an association, or the + * association should be fetched eagerly when the entity is first retrieved, + * for example, by: + * + *

      + *
    • {@link #enableFetchProfile(String) enabling a fetch profile}, + *
    • using an {@link EntityGraph}, or + *
    • writing a {@code join fetch} clause in a HQL query. + *
    + * + * @see org.hibernate.Session + */ + interface Session extends SharedSessionContract { /** - * Determine the current lock mode of the given entity. + * Asynchronously return the persistent instance of the given entity + * class with the given identifier, or {@code null} if there is no such + * persistent instance. If the instance is already associated with + * the session, return the associated instance. This method never + * returns an uninitialized instance. + * + *
    +		 * {@code session.find(Book.class, id).map(book -> print(book.getTitle()));}
    +		 * 
    + * + * @param entityClass The entity type + * @param id an identifier + * + * @return a persistent instance or null via a {@code Uni} + * + * @see jakarta.persistence.EntityManager#find(Class, Object) */ - LockMode getLockMode(Object entity); + Uni find(Class entityClass, Object id); /** - * Determine if the given instance belongs to this persistence context. + * Asynchronously return the persistent instance of the given entity + * class with the given identifier, requesting the given {@link LockMode}. + * + * @param entityClass The entity type + * @param id an identifier + * @param lockMode the requested {@link LockMode} + * + * @return a persistent instance or null via a {@code Uni} + * + * @see #find(Class, Object) + * @see #lock(Object, LockMode) this discussion of lock modes */ - boolean contains(Object entity); + Uni find(Class entityClass, Object id, LockMode lockMode); /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string. + * Asynchronously return the persistent instance of the given entity + * class with the given identifier, requesting the given {@link LockModeType}. * - * @param queryString The HQL/JPQL query + * @param entityClass The entity type + * @param id an identifier + * @param lockModeType the requested {@link LockModeType} * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @return a persistent instance or null via a {@code Uni} * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) + * @see #find(Class, Object) + * @see #lock(Object, LockMode) this discussion of lock modes */ - SelectionQuery createSelectionQuery(String queryString, Class resultType); + default Uni find(Class entityClass, Object id, LockModeType lockModeType) { + return find( entityClass, id, convertToLockMode( lockModeType ) ); + } /** - * Create an instance of {@link MutationQuery} for the given HQL/JPQL - * update or delete statement. - * - * @param queryString The HQL/JPQL query, update or delete statement + * Asynchronously return the persistent instance with the given + * identifier of an entity class, using the given {@link EntityGraph} + * as a fetch plan. * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entityGraph an {@link EntityGraph} specifying the entity + * and associations to be fetched + * @param id an identifier * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @see #find(Class, Object) */ - MutationQuery createMutationQuery(String queryString); + Uni find(EntityGraph entityGraph, Object id); /** - * Create an instance of {@link MutationQuery} for the given update tree. + * Asynchronously return the persistent instances of the given entity + * class with the given identifiers, or null if there is no such + * persistent instance. * - * @param updateQuery the update criteria query + * @param entityClass The entity type + * @param ids the identifiers * - * @return The {@link MutationQuery} instance for manipulation and execution + * @return a list of persistent instances and nulls via a {@code Uni} * - * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) + * @see org.hibernate.Session#findMultiple(Class, List, FindOption...) */ - MutationQuery createMutationQuery(CriteriaUpdate updateQuery); + Uni> find(Class entityClass, Object... ids); /** - * Create an instance of {@link MutationQuery} for the given delete tree. - * - * @param deleteQuery the delete criteria query + * Asynchronously return the persistent instance of the given entity + * class with the given natural identifier, or null if there is no + * such persistent instance. * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entityClass The entity type + * @param naturalId the natural identifier * - * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) + * @return a persistent instance or null via a {@code Uni} */ - MutationQuery createMutationQuery(CriteriaDelete deleteQuery); + @Incubating + Uni find(Class entityClass, Identifier naturalId); /** - * Create a {@link MutationQuery} from the given insert select criteria tree + * Return the persistent instance of the given entity class with the + * given identifier, assuming that the instance exists. This method + * never results in access to the underlying data store, and thus + * might return a proxied instance that must be initialized explicitly + * using {@link #fetch(Object)}. + *

    + * You should not use this method to determine if an instance exists + * (use {@link #find} instead). Use this only to retrieve an instance + * which you safely assume exists, where non-existence would be an + * actual error. * - * @param insert the insert select criteria query + * @param entityClass a persistent class + * @param id a valid identifier of an existing persistent instance of the class * - * @return The {@link MutationQuery} instance for manipulation and execution + * @return the persistent instance or proxy * - * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) + * @see jakarta.persistence.EntityManager#getReference(Class, Object) */ - MutationQuery createMutationQuery(JpaCriteriaInsert insert); + T getReference(Class entityClass, Object id); /** - * Create an instance of {@link Query} for the given HQL/JPQL query - * string or HQL/JPQL update or delete statement. In the case of an - * update or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * - * @param queryString The HQL/JPQL query, update or delete statement - * - * @return The {@link Query} instance for manipulation and execution + * Return the persistent instance with the same identity as the given + * instance, which might be detached, assuming that the instance is + * still persistent in the database. This method never results in + * access to the underlying data store, and thus might return a proxy + * that must be initialized explicitly using {@link #fetch(Object)}. * - * @deprecated See explanation in - * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)} + * @param entity a detached persistent instance * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @return the persistent instance or proxy */ - @Deprecated - Query createQuery(String queryString); + T getReference(T entity); /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string and query result type. + * Asynchronously persist the given transient instance, first assigning + * a generated identifier. (Or using the current value of the identifier + * property if the entity has assigned identifiers.) + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link jakarta.persistence.CascadeType#PERSIST}. * - * @param queryString The HQL/JPQL query - * @param resultType the Java type returned in each row of query results + *

    +		 * {@code session.persist(newBook).map(v -> session.flush());}
    +		 * 
    * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @param object a transient instance of a persistent class * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) + * @see jakarta.persistence.EntityManager#persist(Object) */ - SelectionQuery createQuery(String queryString, Class resultType); + Uni persist(Object object); /** - * Create an instance of {@link SelectionQuery} for the given criteria - * query. - * - * @param criteriaQuery The {@link CriteriaQuery} + * Make a transient instance persistent and mark it for later insertion in the + * database. This operation cascades to associated instances if the association + * is mapped with {@link jakarta.persistence.CascadeType#PERSIST}. + *

    + * For entities with a {@link jakarta.persistence.GeneratedValue generated id}, + * {@code persist()} ultimately results in generation of an identifier for the + * given instance. But this may happen asynchronously, when the session is + * {@linkplain #flush() flushed}, depending on the identifier generation strategy. * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @param entityName the entity name + * @param object a transient instance to be made persistent + * @see #persist(Object) + */ + Uni persist(String entityName, Object object); + + /** + * Persist multiple transient entity instances at once. * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @see #persist(Object) */ - SelectionQuery createQuery(CriteriaQuery criteriaQuery); + Uni persistAll(Object... entities); /** - * Create an instance of {@link MutationQuery} for the given criteria update. + * Asynchronously remove a persistent instance from the datastore. The + * argument may be an instance associated with the receiving session or + * a transient instance with an identifier associated with existing + * persistent state. + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link jakarta.persistence.CascadeType#REMOVE}. * - * @param criteriaUpdate The {@link CriteriaUpdate} + *

    +		 * {@code session.delete(book).thenAccept(v -> session.flush());}
    +		 * 
    * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entity the managed persistent instance to be removed + * + * @throws IllegalArgumentException if the given instance is not managed + * @see jakarta.persistence.EntityManager#remove(Object) */ - MutationQuery createQuery(CriteriaUpdate criteriaUpdate); + Uni remove(Object entity); /** - * Create an instance of {@link MutationQuery} for the given criteria delete. - * - * @param criteriaDelete The {@link CriteriaDelete} + * Remove multiple entity instances at once. * - * @return The {@link MutationQuery} instance for manipulation and execution + * @see #remove(Object) */ - MutationQuery createQuery(CriteriaDelete criteriaDelete); + Uni removeAll(Object... entities); /** - * Create an instance of {@link Query} for the named query. + * Copy the state of the given object onto the persistent instance with + * the same identifier. If there is no such persistent instance currently + * associated with the session, it will be loaded. Return the persistent + * instance. Or, if the given instance is transient, save a copy of it + * and return the copy as a newly persistent instance. The given instance + * does not become associated with the session. + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link jakarta.persistence.CascadeType#MERGE}. * - * @param queryName The name of the query + * @param entity a detached instance with state to be copied * - * @return The {@link Query} instance for manipulation and execution + * @return an updated persistent instance * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @see jakarta.persistence.EntityManager#merge(Object) */ - Query createNamedQuery(String queryName); + Uni merge(T entity); /** - * Create an instance of {@link SelectionQuery} for the named query. - * - * @param queryName The name of the query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link SelectionQuery} instance for manipulation and execution + * Merge multiple entity instances at once. * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) + * @see #merge(Object) */ - SelectionQuery createNamedQuery(String queryName, Class resultType); + Uni mergeAll(Object... entities); /** - * Create an instance of {@link Query} for the given SQL query string, - * or SQL update, insert, or delete statement. In the case of an update, - * insert, or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * In the case of a query: + * Re-read the state of the given instance from the underlying database. + * It is inadvisable to use this to implement long-running sessions that + * span many business tasks. This method is, however, useful in certain + * special circumstances, for example: * *

      - *
    • If the result set has a single column, the results will be returned - * as scalars.
    • - *
    • Otherwise, if the result set has multiple columns, the results will - * be returned as elements of arrays of type {@code Object[]}.
    • + *
    • where a database trigger alters the object state after insert or + * update, or + *
    • after executing direct native SQL in the same session. *
    * - * @param queryString The SQL select, update, insert, or delete statement + * @param entity a managed persistent instance + * + * @throws IllegalArgumentException if the given instance is not managed + * @see jakarta.persistence.EntityManager#refresh(Object) */ - Query createNativeQuery(String queryString); + Uni refresh(Object entity); /** - * Create an instance of {@link Query} for the given SQL query string, - * or SQL update, insert, or delete statement. In the case of an update, - * insert, or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * In the case of a query: + * Re-read the state of the given instance from the underlying database, + * requesting the given {@link LockMode}. * - *
      - *
    • If the result set has a single column, the results will be returned - * as scalars.
    • - *
    • Otherwise, if the result set has multiple columns, the results will - * be returned as elements of arrays of type {@code Object[]}.
    • - *
    - *

    - * Any {@link AffectedEntities affected entities} are synchronized with - * the database before execution of the statement. + * @param entity a managed persistent entity instance + * @param lockMode the requested lock mode + * + * @see #refresh(Object) + */ + Uni refresh(Object entity, LockMode lockMode); + + /** + * Re-read the state of the given instance from the underlying database, + * requesting the given {@link LockModeType}. * - * @param queryString The SQL select, update, insert, or delete statement - * @param affectedEntities The entities which are affected by the statement + * @param entity a managed persistent entity instance + * @param lockModeType the requested lock mode + * + * @see #refresh(Object) */ - Query createNativeQuery(String queryString, AffectedEntities affectedEntities); + default Uni refresh(Object entity, LockModeType lockModeType) { + return refresh( entity, convertToLockMode( lockModeType ) ); + } /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@code resultType} to interpret the results. + * Refresh multiple entity instances at once. + * + * @see #refresh(Object) + */ + Uni refreshAll(Object... entities); + + /** + * Obtain the specified lock level upon the given object. For example, + * this operation may be used to: * *

      - *
    • If the given result type is {@link Object}, or a built-in type - * such as {@link String} or {@link Integer}, the result set must - * have a single column, which will be returned as a scalar. - *
    • If the given result type is {@code Object[]}, then the result set - * must have multiple columns, which will be returned in arrays. - *
    • Otherwise, the given result type must be an entity class, in which - * case the result set column aliases must map to the fields of the - * entity, and the query will return instances of the entity. + *
    • perform a version check with {@link LockMode#PESSIMISTIC_READ}, + *
    • upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}, + *
    • force a version increment with {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}, + *
    • schedule a version check just before the end of the transaction with + * {@link LockMode#OPTIMISTIC}, or + *
    • schedule a version increment just before the end of the transaction + * with {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}. *
    + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. * - * @param queryString The SQL query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @param entity a managed persistent instance + * @param lockMode the lock level * - * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) + * @throws IllegalArgumentException if the given instance is not managed */ - SelectionQuery createNativeQuery(String queryString, Class resultType); + Uni lock(Object entity, LockMode lockMode); /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@code resultType} to interpret the results. + * Obtain the specified lock level upon the given object. For example, + * this operation may be used to: * *

      - *
    • If the given result type is {@link Object}, or a built-in type - * such as {@link String} or {@link Integer}, the result set must - * have a single column, which will be returned as a scalar. - *
    • If the given result type is {@code Object[]}, then the result set - * must have multiple columns, which will be returned in arrays. - *
    • Otherwise, the given result type must be an entity class, in which - * case the result set column aliases must map to the fields of the - * entity, and the query will return instances of the entity. + *
    • perform a version check with {@link LockModeType#PESSIMISTIC_READ}, + *
    • upgrade to a pessimistic lock with {@link LockModeType#PESSIMISTIC_WRITE}, + *
    • force a version increment with {@link LockModeType#PESSIMISTIC_FORCE_INCREMENT}, + *
    • schedule a version check just before the end of the transaction with + * {@link LockModeType#OPTIMISTIC}, or + *
    • schedule a version increment just before the end of the transaction + * with {@link LockModeType#OPTIMISTIC_FORCE_INCREMENT}. *
    *

    - * Any {@link AffectedEntities affected entities} are synchronized with - * the database before execution of the query. - * - * @param queryString The SQL query - * @param resultType the Java type returned in each row of query results - * @param affectedEntities The entities which are affected by the query + * This operation cascades to associated instances if the association is + * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. * - * @return The {@link Query} instance for manipulation and execution + * @param entity a managed persistent instance + * @param lockModeType the lock level * - * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) + * @throws IllegalArgumentException if the given instance is not managed */ - SelectionQuery createNativeQuery( - String queryString, Class resultType, - AffectedEntities affectedEntities); + default Uni lock(Object entity, LockModeType lockModeType) { + return lock( entity, convertToLockMode( lockModeType ) ); + } /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@link ResultSetMapping} to interpret the - * result set. - * - * @param queryString The SQL query - * @param resultSetMapping the result set mapping + * Force this session to flush asynchronously. Must be called at the + * end of a unit of work, before committing the transaction and closing + * the session. Flushing is the process of synchronizing the + * underlying persistent store with state held in memory. * - * @return The {@link Query} instance for manipulation and execution + *

    +		 * {@code session.flush().thenAccept(v -> print("done saving changes"));}
    +		 * 
    * - * @see #getResultSetMapping(Class, String) - * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) + * @see jakarta.persistence.EntityManager#flush() */ - SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping); + Uni flush(); /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@link ResultSetMapping} to interpret the - * result set. + * Asynchronously fetch an association that's configured for lazy loading. *

    - * Any {@link AffectedEntities affected entities} are synchronized with the - * database before execution of the query. + *

    +		 * {@code session.fetch(author.getBook()).thenAccept(book -> print(book.getTitle()));}
    +		 * 
    + *

    + *

    + * It can also initialize proxys. For example: + *

    +		 * {@code session.fetch(session.getReference(Author.class, authorId))}
    +		 * 
    + *

    + * @param association a lazy-loaded association, or a proxy * - * @param queryString The SQL query - * @param resultSetMapping the result set mapping - * @param affectedEntities The entities which are affected by the query + * @return the fetched association, via a {@code Uni} * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @see Mutiny#fetch(Object) + * @see #getReference(Class, Object) + * @see org.hibernate.Hibernate#initialize(Object) + */ + Uni fetch(T association); + + /** + * Fetch a lazy property of the given entity, identified by a JPA + * {@link Attribute attribute metamodel}. Note that this feature is + * only supported in conjunction with the Hibernate bytecode enhancer. * - * @see #getResultSetMapping(Class, String) - * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) + *
    +		 * {@code session.fetch(book, Book_.isbn).thenAccept(isbn -> print(isbn))}
    +		 * 
    + */ + Uni fetch(E entity, Attribute field); + + /** + * Determine the current lock mode of the given entity. + */ + LockMode getLockMode(Object entity); + + /** + * Determine if the given instance belongs to this persistence context. */ - SelectionQuery createNativeQuery( - String queryString, - ResultSetMapping resultSetMapping, - AffectedEntities affectedEntities); + boolean contains(Object entity); /** * Set the {@link FlushMode flush mode} for this session. @@ -1280,27 +1407,6 @@ default Session setFlushMode(FlushModeType flushModeType) { */ Session enableFetchProfile(String name); - /** - * Obtain a native SQL result set mapping defined via the annotation - * {@link jakarta.persistence.SqlResultSetMapping}. - */ - ResultSetMapping getResultSetMapping(Class resultType, String mappingName); - - /** - * Obtain a named {@link EntityGraph} - */ - EntityGraph getEntityGraph(Class rootType, String graphName); - - /** - * Create a new mutable {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType); - - /** - * Create a new mutable copy of a named {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType, String graphName); - /** * Disable a particular fetch profile on this session, or do nothing if * the requested fetch profile is not enabled. @@ -1313,20 +1419,6 @@ default Session setFlushMode(FlushModeType flushModeType) { */ Session disableFetchProfile(String name); - /** - * Determine if the fetch profile with the given name is enabled for this - * session. - * - * @param name The name of the profile to be checked. - * - * @return True if fetch profile is enabled; false if not. - * - * @throws org.hibernate.UnknownProfileException Indicates that the given name does not - * match any known profile names - * @see org.hibernate.engine.profile.FetchProfile for discussion of this feature - */ - boolean isFetchProfileEnabled(String name); - /** * Change the default for entities and proxies loaded into this session * from modifiable to read-only mode, or from modifiable to read-only mode. @@ -1408,31 +1500,6 @@ default Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { */ Integer getBatchSize(); - /** - * Enable the named filter for this session. - * - * @param filterName The name of the filter to be enabled. - * - * @return The Filter instance representing the enabled filter. - */ - Filter enableFilter(String filterName); - - /** - * Disable the named filter for this session. - * - * @param filterName The name of the filter to be disabled. - */ - void disableFilter(String filterName); - - /** - * Retrieve a currently enabled filter by name. - * - * @param filterName The name of the filter to be retrieved. - * - * @return The Filter instance representing the enabled filter. - */ - Filter getEnabledFilter(String filterName); - /** * Get the maximum batch size for batch fetching associations by * id in this session. @@ -1454,78 +1521,31 @@ default Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { *
  • Otherwise, batch fetching is disabled. * * - * @param batchSize the maximum batch size for batch fetching - * - * @since 2.1 - */ - Session setFetchBatchSize(int batchSize); - - /** - * Determine if subselect fetching is enabled in this session. - * - * @return {@code true} if subselect fetching is enabled - * - * @since 2.1 - */ - boolean isSubselectFetchingEnabled(); - - /** - * Enable or disable subselect fetching in this session. - * Override the default controlled by the configuration property - * {@code hibernate.use_subselect_fetch}. - * - * @param enabled {@code true} to enable subselect fetching - * - * @since 2.1 - */ - Session setSubselectFetchingEnabled(boolean enabled); - - /** - * Performs the given work within the scope of a database transaction, - * automatically flushing the session. The transaction will be rolled - * back if the work completes with an uncaught exception, or if - * {@link Transaction#markForRollback()} is called. - *

    - * The resulting {@link Transaction} object may also be obtained via - * {@link #currentTransaction()}. - *

    - * - *

  • If there is already a transaction associated with this session, - * the work is executed in the context of the existing transaction, and - * no new transaction is initiated. - *
  • If there is no transaction associated with this session, a new - * transaction is started, and the work is executed in the context of - * the new transaction. - * - * - * @param work a function which accepts {@link Transaction} and returns - * the result of the work as a {@link Uni}. + * @param batchSize the maximum batch size for batch fetching * - * @see SessionFactory#withTransaction(BiFunction) + * @since 2.1 */ - Uni withTransaction(Function> work); + Session setFetchBatchSize(int batchSize); /** - * Obtain the transaction currently associated with this session, - * if any. + * Determine if subselect fetching is enabled in this session. * - * @return the {@link Transaction}, or null if no transaction - * was started using {@link #withTransaction(Function)}. + * @return {@code true} if subselect fetching is enabled * - * @see #withTransaction(Function) - * @see SessionFactory#withTransaction(BiFunction) - */ - Transaction currentTransaction(); - - /** - * @return false if {@link #close()} has been called + * @since 2.1 */ - boolean isOpen(); + boolean isSubselectFetchingEnabled(); /** - * The {@link SessionFactory} which created this session. + * Enable or disable subselect fetching in this session. + * Override the default controlled by the configuration property + * {@code hibernate.use_subselect_fetch}. + * + * @param enabled {@code true} to enable subselect fetching + * + * @since 2.1 */ - SessionFactory getFactory(); + Session setSubselectFetchingEnabled(boolean enabled); } /** @@ -1558,7 +1578,7 @@ default Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { * * @see org.hibernate.StatelessSession */ - interface StatelessSession extends Closeable { + interface StatelessSession extends SharedSessionContract { /** * Retrieve a row. @@ -1623,153 +1643,6 @@ default Uni get(Class entityClass, Object id, LockModeType lockModeTyp */ Uni get(EntityGraph entityGraph, Object id); - /** - * Create an instance of {@link Query} for the given HQL/JPQL query - * string or HQL/JPQL update or delete statement. In the case of an - * update or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * - * @param queryString The HQL/JPQL query, update or delete statement - * - * @return The {@link Query} instance for manipulation and execution - * - * @deprecated See explanation in - * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)} - * - * @see Session#createQuery(String) - */ - @Deprecated - Query createQuery(String queryString); - - /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string and query result type. - * - * @param queryString The HQL/JPQL query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link Query} instance for manipulation and execution - * - * @see Session#createQuery(String, Class) - */ - SelectionQuery createQuery(String queryString, Class resultType); - - /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string. - * - * @param queryString The HQL/JPQL query - * - * @return The {@link SelectionQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) - */ - SelectionQuery createSelectionQuery(String queryString, Class resultType); - - /** - * Create an instance of {@link MutationQuery} for the given HQL/JPQL - * update or delete statement. - * - * @param queryString The HQL/JPQL query, update or delete statement - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - MutationQuery createMutationQuery(String queryString); - - /** - * Create an instance of {@link Query} for the named query. - * - * @param queryName The name of the query - * - * @return The {@link Query} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - Query createNamedQuery(String queryName); - - /** - * Create an instance of {@link SelectionQuery} for the named query. - * - * @param queryName The name of the query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link SelectionQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) - */ - SelectionQuery createNamedQuery(String queryName, Class resultType); - - /** - * Create an instance of {@link Query} for the given SQL query string, - * or SQL update, insert, or delete statement. In the case of an update, - * insert, or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * - * @param queryString The SQL select, update, insert, or delete statement - * - * @see Session#createNativeQuery(String) - */ - Query createNativeQuery(String queryString); - - /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@code resultType} to interpret the results. - * - * @param queryString The SQL query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link Query} instance for manipulation and execution - * - * @see Session#createNativeQuery(String, Class) - */ - SelectionQuery createNativeQuery(String queryString, Class resultType); - - /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@link ResultSetMapping} to interpret the - * result set. - * - * @param queryString The SQL query - * @param resultSetMapping the result set mapping - * - * @return The {@link Query} instance for manipulation and execution - * - * @see Session#createNativeQuery(String, ResultSetMapping) - */ - SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping); - - /** - * Create an instance of {@link SelectionQuery} for the given criteria - * query. - * - * @param criteriaQuery The {@link CriteriaQuery} - * - * @return The {@link SelectionQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - SelectionQuery createQuery(CriteriaQuery criteriaQuery); - - /** - * Create an instance of {@link MutationQuery} for the given criteria update. - * - * @param criteriaUpdate The {@link CriteriaUpdate} - * - * @return The {@link MutationQuery} instance for manipulation and execution - */ - MutationQuery createQuery(CriteriaUpdate criteriaUpdate); - - /** - * Create an instance of {@link MutationQuery} for the given criteria delete. - * - * @param criteriaDelete The {@link CriteriaDelete} - * - * @return The {@link MutationQuery} instance for manipulation and execution - */ - MutationQuery createQuery(CriteriaDelete criteriaDelete); - /** * Insert a row. * @@ -1984,87 +1857,6 @@ default Uni refresh(Object entity, LockModeType lockModeType) { * @see org.hibernate.Hibernate#initialize(Object) */ Uni fetch(T association); - - /** - * Return the identifier value of the given entity, which may be detached. - * - * @param entity a persistent instance associated with this session - * - * @return the identifier - * - * @since 3.0 - */ - Object getIdentifier(Object entity); - - /** - * Obtain a native SQL result set mapping defined via the annotation - * {@link jakarta.persistence.SqlResultSetMapping}. - */ - ResultSetMapping getResultSetMapping(Class resultType, String mappingName); - - /** - * Obtain a named {@link EntityGraph} - */ - EntityGraph getEntityGraph(Class rootType, String graphName); - - /** - * Create a new mutable {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType); - - /** - * Create a new mutable copy of a named {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType, String graphName); - - /** - * Performs the given work within the scope of a database transaction, - * automatically flushing the session. The transaction will be rolled - * back if the work completes with an uncaught exception, or if - * {@link Transaction#markForRollback()} is called. - * - *
  • If there is already a transaction associated with this session, - * the work is executed in the context of the existing transaction, and - * no new transaction is initiated. - *
  • If there is no transaction associated with this session, a new - * transaction is started, and the work is executed in the context of - * the new transaction. - * - * - * @param work a function which accepts {@link Transaction} and returns - * the result of the work as a {@link Uni}. - * - * @see SessionFactory#withTransaction(BiFunction) - */ - Uni withTransaction(Function> work); - - /** - * Obtain the transaction currently associated with this session, - * if any. - * - * @return the {@link Transaction}, or null if no transaction - * was started using {@link #withTransaction(Function)}. - * - * @see #withTransaction(Function) - * @see SessionFactory#withTransaction(BiFunction) - */ - Transaction currentTransaction(); - - /** - * @return false if {@link #close()} has been called - */ - boolean isOpen(); - - /** - * Close the reactive session and release the underlying database - * connection. - */ - Uni close(); - - /** - * The {@link SessionFactory} which created this session. - */ - SessionFactory getFactory(); } /** diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java index 929987b55..6978ba1c2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionImpl.java @@ -84,6 +84,11 @@ public Uni fetch(E entity, Attribute field) { return uni( () -> delegate.reactiveFetch( entity, field ) ); } + @Override + public Object getIdentifier(Object entity) { + return delegate.getIdentifier( entity ); + } + @Override public Uni unproxy(T association) { return uni( () -> delegate.reactiveFetch( association, true ) ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java index 473196712..f4c83629e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinyStatelessSessionImpl.java @@ -5,25 +5,28 @@ */ package org.hibernate.reactive.mutiny.impl; -import io.smallrye.mutiny.Uni; -import jakarta.persistence.EntityGraph; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.hibernate.Filter; import org.hibernate.LockMode; import org.hibernate.graph.spi.RootGraphImplementor; +import org.hibernate.query.criteria.JpaCriteriaInsert; +import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.ResultSetMapping; import org.hibernate.reactive.mutiny.Mutiny; -import org.hibernate.reactive.mutiny.Mutiny.Query; -import org.hibernate.reactive.mutiny.Mutiny.SelectionQuery; import org.hibernate.reactive.pool.ReactiveConnection; import org.hibernate.reactive.session.ReactiveStatelessSession; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; -import java.util.function.Supplier; +import io.smallrye.mutiny.Uni; +import jakarta.persistence.EntityGraph; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Attribute; /** @@ -45,7 +48,6 @@ public ReactiveConnection getReactiveConnection() { return delegate.getReactiveConnection(); } - Uni uni(Supplier> stageSupplier) { return factory.uni( stageSupplier ); } @@ -71,66 +73,6 @@ public Uni get(EntityGraph entityGraph, Object id) { return uni( () -> delegate.reactiveGet( entityClass, id, null, entityGraph ) ); } - @Override - public Query createQuery(String queryString) { - return new MutinyQueryImpl<>( delegate.createReactiveQuery( queryString ), factory ); - } - - @Override @Deprecated - public SelectionQuery createQuery(String queryString, Class resultType) { - return new MutinySelectionQueryImpl<>( delegate.createReactiveQuery( queryString, resultType ), factory ); - } - - @Override - public SelectionQuery createSelectionQuery(String queryString, Class resultType) { - return new MutinySelectionQueryImpl<>( delegate.createReactiveSelectionQuery( queryString, resultType), factory ); - } - - @Override - public Mutiny.MutationQuery createMutationQuery(String queryString) { - return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( queryString), factory ); - } - - @Override - public Query createNamedQuery(String queryName) { - return new MutinyQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ), factory ); - } - - @Override - public SelectionQuery createNamedQuery(String queryName, Class resultType) { - return new MutinySelectionQueryImpl<>( delegate.createReactiveNamedQuery( queryName, resultType ), factory ); - } - - @Override - public Query createNativeQuery(String queryString) { - return new MutinyQueryImpl<>( delegate.createReactiveNativeQuery( queryString ), factory ); - } - - @Override - public SelectionQuery createNativeQuery(String queryString, Class resultType) { - return new MutinySelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultType ), factory ); - } - - @Override - public SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping) { - return new MutinySelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultSetMapping ), factory ); - } - - @Override - public SelectionQuery createQuery(CriteriaQuery criteriaQuery) { - return new MutinySelectionQueryImpl<>( delegate.createReactiveQuery( criteriaQuery ), factory ); - } - - @Override - public Mutiny.MutationQuery createQuery(CriteriaUpdate criteriaUpdate) { - return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( criteriaUpdate ), factory ); - } - - @Override - public Mutiny.MutationQuery createQuery(CriteriaDelete criteriaDelete) { - return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( criteriaDelete ), factory ); - } - @Override public Uni insert(Object entity) { return uni( () -> delegate.reactiveInsert( entity ) ); @@ -226,36 +168,117 @@ public Uni refresh(Object entity, LockMode lockMode) { return uni( () -> delegate.reactiveRefresh( entity, lockMode ) ); } + @Override + public Mutiny.SelectionQuery createSelectionQuery(String queryString, Class resultType) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveSelectionQuery( queryString, resultType ), factory ); + } + + @Override + public Mutiny.MutationQuery createMutationQuery(String queryString) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveQuery( queryString ), factory ); + } + + @Override + public Mutiny.MutationQuery createMutationQuery(CriteriaUpdate updateQuery) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( updateQuery ), factory ); + } + + @Override + public Mutiny.MutationQuery createMutationQuery(CriteriaDelete deleteQuery) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( deleteQuery ), factory ); + } + + @Override + public Mutiny.MutationQuery createMutationQuery(JpaCriteriaInsert insert) { + return new MutinyMutationQueryImpl<>( delegate.createReactiveMutationQuery( insert ), factory ); + } + + @Override @Deprecated + public Mutiny.Query createQuery(String queryString) { + return new MutinyQueryImpl<>( delegate.createReactiveQuery( queryString ), factory ); + } + + @Override + public Mutiny.SelectionQuery createQuery(String queryString, Class resultType) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveQuery( queryString, resultType ), factory ); + } + + @Override + public Mutiny.SelectionQuery createQuery(CriteriaQuery criteriaQuery) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveQuery( criteriaQuery ), factory ); + } + + @Override + public Mutiny.MutationQuery createQuery(CriteriaUpdate criteriaUpdate) { + return new MutinyMutationQueryImpl<>( + delegate.createReactiveMutationQuery( criteriaUpdate ), + factory + ); + } + + @Override + public Mutiny.MutationQuery createQuery(CriteriaDelete criteriaDelete) { + return new MutinyMutationQueryImpl<>( + delegate.createReactiveMutationQuery( criteriaDelete ), + factory + ); + } + + @Override + public Mutiny.Query createNamedQuery(String queryName) { + return new MutinyQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ), factory ); + } + + @Override + public Mutiny.SelectionQuery createNamedQuery(String queryName, Class resultType) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveNamedQuery( queryName, resultType ), factory ); + } + + @Override + public Mutiny.Query createNativeQuery(String queryString) { + return new MutinyQueryImpl<>( delegate.createReactiveNativeQuery( queryString ), factory ); + } + + @Override + public Mutiny.Query createNativeQuery(String queryString, AffectedEntities affectedEntities) { + return new MutinyQueryImpl<>( delegate.createReactiveNativeQuery( queryString, affectedEntities ), factory ); + } + + @Override + public Mutiny.SelectionQuery createNativeQuery(String queryString, Class resultType) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultType ), factory ); + } + + @Override + public Mutiny.SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultType, affectedEntities ), factory ); + } + + @Override + public Mutiny.SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultSetMapping ), factory ); + } + + @Override + public Mutiny.SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities) { + return new MutinySelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultSetMapping, affectedEntities ), factory ); + } + @Override public Uni fetch(T association) { return uni( () -> delegate.reactiveFetch( association, false ) ); } + @Override + public Uni fetch(E entity, Attribute field) { + return uni( () -> delegate.reactiveFetch( entity, field ) ); + } + @Override public Object getIdentifier(Object entity) { return delegate.getIdentifier(entity); } -// @Override -// public ResultSetMapping getResultSetMapping(Class resultType, String mappingName) { -// return delegate.getResultSetMapping( resultType, mappingName ); -// } -// -// @Override -// public EntityGraph getEntityGraph(Class entity, String name) { -// return delegate.getEntityGraph( entity, name ); -// } -// -// @Override -// public EntityGraph createEntityGraph(Class entity) { -// return delegate.createEntityGraph( entity ); -// } -// -// @Override -// public EntityGraph createEntityGraph(Class entity, String name) { -// return delegate.createEntityGraph( entity, name ); -// } - @Override public Uni withTransaction(Function> work) { return currentTransaction == null ? new Transaction().execute( work ) : work.apply( currentTransaction ); @@ -336,6 +359,26 @@ public MutinySessionFactoryImpl getFactory() { return factory; } + @Override + public boolean isFetchProfileEnabled(String name) { + return false; + } + + @Override + public Filter enableFilter(String filterName) { + return delegate.getSharedContract().enableFilter( filterName ); + } + + @Override + public void disableFilter(String filterName) { + delegate.getSharedContract().disableFilter( filterName ); + } + + @Override + public Filter getEnabledFilter(String filterName) { + return delegate.getSharedContract().getEnabledFilter( filterName ); + } + @Override public ResultSetMapping getResultSetMapping(Class resultType, String mappingName) { return delegate.getResultSetMapping( resultType, mappingName ); @@ -355,4 +398,9 @@ public EntityGraph createEntityGraph(Class rootType) { public EntityGraph createEntityGraph(Class rootType, String graphName) { return delegate.createEntityGraph( rootType, graphName ); } + + @Override + public Uni unproxy(T association) { + return uni( () -> delegate.reactiveFetch( association, true ) ); + } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java index 25a7402ef..9c88d09b2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveQueryProducer.java @@ -24,6 +24,7 @@ import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Attribute; /** @@ -43,6 +44,8 @@ public interface ReactiveQueryProducer extends ReactiveConnectionSupplier { CompletionStage reactiveFetch(T association, boolean unproxy); + CompletionStage reactiveFetch(E entity, Attribute field); + CompletionStage reactiveInternalLoad(String entityName, Object id, boolean eager, boolean nullable); EntityGraph createEntityGraph(Class entity); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java index f53ed4fca..3d4012f86 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveSession.java @@ -27,7 +27,6 @@ import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor; import jakarta.persistence.EntityGraph; -import jakarta.persistence.metamodel.Attribute; /** * A contract with the Hibernate session backing the user-visible @@ -46,8 +45,6 @@ public interface ReactiveSession extends ReactiveQueryProducer, ReactiveSharedSe SessionImplementor getSharedContract(); - CompletionStage reactiveFetch(E entity, Attribute field); - CompletionStage reactivePersist(Object entity); CompletionStage reactivePersist(String entityName, Object object); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java index 33e34917b..42d2e4781 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/ReactiveStatelessSession.java @@ -10,6 +10,7 @@ import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor; import jakarta.persistence.EntityGraph; +import jakarta.persistence.metamodel.Attribute; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -28,6 +29,8 @@ @Incubating public interface ReactiveStatelessSession extends ReactiveQueryProducer, ReactiveSharedSessionContractImplementor { + CompletionStage reactiveFetch(E entity, Attribute field); + CompletionStage reactiveGet(Class entityClass, Object id); CompletionStage> reactiveGet(Class entityClass, Object... id); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java index 8e8e338a6..379e260d7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveStatelessSessionImpl.java @@ -90,6 +90,7 @@ import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Attribute; import static java.lang.Boolean.TRUE; import static java.lang.invoke.MethodHandles.lookup; @@ -689,6 +690,12 @@ else if ( !persister.hasSubclasses() ) { .whenComplete( (r, e) -> persistenceContext.afterLoad() ); } + @Override + public CompletionStage reactiveFetch(E entity, Attribute field) { + return getEntityPersister( null, entity ) + .reactiveInitializeLazyProperty( field, entity, this ); + } + @Override @SuppressWarnings("unchecked") public CompletionStage reactiveFetch(T association, boolean unproxy) { From 2e42d9012bcb01c108104e91f961c23721fd4026 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 19 Feb 2025 17:58:28 +0100 Subject: [PATCH 2/2] [#2104] Create Stage.SharedSessionContract interface --- .../org/hibernate/reactive/stage/Stage.java | 1372 +++++++---------- .../reactive/stage/impl/StageSessionImpl.java | 34 +- .../stage/impl/StageStatelessSessionImpl.java | 43 +- 3 files changed, 599 insertions(+), 850 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java index 1cf8f4fed..a352f751f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java @@ -361,13 +361,6 @@ default SelectionQuery setLockMode(String alias, LockModeType lockModeType) { return setLockMode( alias, convertToLockMode(lockModeType) ); } -// /** -// * Set the {@link LockOptions} to use for the whole query. -// * -// * @see org.hibernate.query.Query#setLockOptions(LockOptions) -// */ -// Query setLockOptions(LockOptions lockOptions); - /** * If the result type of this query is an entity class, add one or more * {@linkplain Order rules} for ordering the query results. @@ -515,733 +508,777 @@ default Query setLockMode(String alias, LockModeType lockModeType) { Query setComment(String comment); } - /** - * A non-blocking counterpart to the Hibernate {@link org.hibernate.Session} - * interface, allowing a reactive style of interaction with the database. - *

    - * The semantics of operations on this interface are identical to the - * semantics of the similarly-named operations of {@code Session}, except - * that the operations are performed asynchronously, returning a - * {@link CompletionStage} without blocking the calling thread. - *

    - * Entities associated with an {@code Session} do not support transparent - * lazy association fetching. Instead, {@link #fetch(Object)} should be used - * to explicitly request asynchronous fetching of an association, or the - * association should be fetched eagerly when the entity is first retrieved, - * for example, by: - * - *

      - *
    • {@link #enableFetchProfile(String) enabling a fetch profile}, - *
    • using an {@link EntityGraph}, or - *
    • writing a {@code join fetch} clause in a HQL query. - *
    - * - * @see org.hibernate.Session - */ - interface Session extends Closeable { - + interface SharedSessionContract extends Stage.Closeable { /** - * Asynchronously return the persistent instance of the given entity - * class with the given identifier, or {@code null} if there is no such - * persistent instance. If the instance is already associated with - * the session, return the associated instance. This method never - * returns an uninitialized instance. - * - *
    -		 * {@code session.find(Book.class, id).thenAccept(book -> print(book.getTitle()));}
    -		 * 
    + * Create an instance of {@link SelectionQuery} for the given HQL/JPQL + * query string. * - * @param entityClass The entity type - * @param id an identifier + * @param queryString The HQL/JPQL query * - * @return a persistent instance or null via a {@code CompletionStage} + * @return The {@link SelectionQuery} instance for manipulation and execution * - * @see jakarta.persistence.EntityManager#find(Class, Object) + * @see jakarta.persistence.EntityManager#createQuery(String, Class) */ - CompletionStage find(Class entityClass, Object id); + SelectionQuery createSelectionQuery(String queryString, Class resultType); /** - * Asynchronously return the persistent instance of the given entity - * class with the given identifier, requesting the given {@link LockMode}. + * Create an instance of {@link MutationQuery} for the given HQL/JPQL + * update or delete statement. * - * @param entityClass The entity type - * @param id an identifier - * @param lockMode the requested {@link LockMode} + * @param queryString The HQL/JPQL query, update or delete statement * - * @return a persistent instance or null via a {@code CompletionStage} + * @return The {@link MutationQuery} instance for manipulation and execution * - * @see #find(Class,Object) - * @see #lock(Object, LockMode) this discussion of lock modes + * @see jakarta.persistence.EntityManager#createQuery(String) */ - CompletionStage find(Class entityClass, Object id, LockMode lockMode); + MutationQuery createMutationQuery(String queryString); /** - * Asynchronously return the persistent instance of the given entity - * class with the given identifier, requesting the given {@link LockModeType}. + * Create an instance of {@link MutationQuery} for the given update tree. * - * @param entityClass The entity type - * @param id an identifier - * @param lockModeType the requested {@link LockModeType} + * @param updateQuery the update criteria query * - * @return a persistent instance or null via a {@code CompletionStage} + * @return The {@link MutationQuery} instance for manipulation and execution * - * @see #find(Class,Object) - * @see #lock(Object, LockMode) this discussion of lock modes + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) */ - default CompletionStage find(Class entityClass, Object id, LockModeType lockModeType) { - return find( entityClass, id, convertToLockMode(lockModeType) ); - } - -// /** -// * Asynchronously return the persistent instance of the given entity -// * class with the given identifier, requesting the given {@link LockOptions}. -// * -// * @param entityClass The entity type -// * @param id an identifier -// * @param lockOptions the requested {@link LockOptions} -// * -// * @return a persistent instance or null via a {@code CompletionStage} -// * -// * @see #find(Class,Object) -// * @see #lock(Object, LockMode) this discussion of lock modes -// */ -// CompletionStage find(Class entityClass, Object id, LockOptions lockOptions); + MutationQuery createMutationQuery(CriteriaUpdate updateQuery); - /** - * Asynchronously return the persistent instance with the given - * identifier of an entity class, using the given {@link EntityGraph} - * as a fetch plan. + /** + * Create an instance of {@link MutationQuery} for the given delete tree. * - * @param entityGraph an {@link EntityGraph} specifying the entity - * and associations to be fetched - * @param id an identifier + * @param deleteQuery the delete criteria query * - * @see #find(Class,Object) + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) */ - CompletionStage find(EntityGraph entityGraph, Object id); + MutationQuery createMutationQuery(CriteriaDelete deleteQuery); /** - * Asynchronously return the persistent instances of the given entity - * class with the given identifiers, or null if there is no such - * persistent instance. + * Create a {@link MutationQuery} from the given insert select criteria tree * - * @param entityClass The entity type - * @param ids the identifiers + * @param insert the insert select criteria query * - * @return a list of persistent instances and nulls via a {@code CompletionStage} + * @return The {@link MutationQuery} instance for manipulation and execution + * + * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) */ - CompletionStage> find(Class entityClass, Object... ids); + MutationQuery createMutationQuery(JpaCriteriaInsert insert); /** - * Asynchronously return the persistent instance of the given entity - * class with the given natural identifiers, or null if there is no - * such persistent instance. + * Create an instance of {@link Query} for the given HQL/JPQL query + * string or HQL/JPQL update or delete statement. In the case of an + * update or delete, the returned {@link Query} must be executed using + * {@link Query#executeUpdate()} which returns an affected row count. * - * @param entityClass The entity type - * @param naturalId the natural identifier + * @param queryString The HQL/JPQL query, update or delete statement * - * @return a persistent instance or null via a {@code CompletionStage} + * @return The {@link Query} instance for manipulation and execution + * + * @deprecated See explanation in + * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)} + * + * @see jakarta.persistence.EntityManager#createQuery(String) */ - @Incubating - CompletionStage find(Class entityClass, Identifier naturalId); + @Deprecated + Query createQuery(String queryString); /** - * Return the persistent instance of the given entity class with the - * given identifier, assuming that the instance exists. This method - * never results in access to the underlying data store, and thus - * might return a proxy that must be initialized explicitly using - * {@link #fetch(Object)}. - *

    - * You should not use this method to determine if an instance exists - * (use {@link #find} instead). Use this only to retrieve an instance - * which you safely assume exists, where non-existence would be an - * actual error. + * Create an instance of {@link SelectionQuery} for the given HQL/JPQL + * query string and query result type. * - * @param entityClass a persistent class - * @param id a valid identifier of an existing persistent instance of the class + * @param queryString The HQL/JPQL query + * @param resultType the Java type returned in each row of query results * - * @return the persistent instance or proxy + * @return The {@link Query} instance for manipulation and execution * - * @see jakarta.persistence.EntityManager#getReference(Class, Object) + * @see jakarta.persistence.EntityManager#createQuery(String, Class) */ - T getReference(Class entityClass, Object id); + SelectionQuery createQuery(String queryString, Class resultType); /** - * Return the persistent instance with the same identity as the given - * instance, which might be detached, assuming that the instance is - * still persistent in the database. This method never results in - * access to the underlying data store, and thus might return a proxy - * that must be initialized explicitly using {@link #fetch(Object)}. + * Create an instance of {@link MutationQuery} for the given criteria + * update. * - * @param entity a detached persistent instance + * @param criteriaUpdate The {@link CriteriaUpdate} * - * @return the persistent instance or proxy + * @return The {@link MutationQuery} instance for manipulation and execution */ - T getReference(T entity); + MutationQuery createQuery(CriteriaUpdate criteriaUpdate); /** - * Asynchronously persist the given transient instance, first assigning - * a generated identifier. (Or using the current value of the identifier - * property if the entity has assigned identifiers.) - *

    - * This operation cascades to associated instances if the association is - * mapped with {@link jakarta.persistence.CascadeType#PERSIST}. - * - *

    -		 * {@code session.persist(newBook).thenAccept(v -> session.flush());}
    -		 * 
    + * Create an instance of {@link MutationQuery} for the given criteria + * delete. * - * @param entity a transient instance of a persistent class + * @param criteriaDelete The {@link CriteriaDelete} * - * @see jakarta.persistence.EntityManager#persist(Object) + * @return The {@link MutationQuery} instance for manipulation and execution */ - CompletionStage persist(Object entity); + MutationQuery createQuery(CriteriaDelete criteriaDelete); /** - * Make a transient instance persistent and mark it for later insertion in the - * database. This operation cascades to associated instances if the association - * is mapped with {@link jakarta.persistence.CascadeType#PERSIST}. - *

    - * For entities with a {@link jakarta.persistence.GeneratedValue generated id}, - * {@code persist()} ultimately results in generation of an identifier for the - * given instance. But this may happen asynchronously, when the session is - * {@linkplain #flush() flushed}, depending on the identifier generation strategy. + * Create an instance of {@link Query} for the named query. * - * @param entityName the entity name - * @param object a transient instance to be made persistent - * @see #persist(Object) + * @param queryName The name of the query + * + * @return The {@link Query} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String) */ - CompletionStage persist(String entityName, Object object); + Query createNamedQuery(String queryName); /** - * Persist multiple transient entity instances at once. + * Create an instance of {@link SelectionQuery} for the named query. * - * @see #persist(Object) + * @param queryName The name of the query + * @param resultType the Java type returned in each row of query results + * + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String, Class) */ - CompletionStage persist(Object... entities); + SelectionQuery createNamedQuery(String queryName, Class resultType); /** - * Asynchronously remove a persistent instance from the datastore. The - * argument may be an instance associated with the receiving session or - * a transient instance with an identifier associated with existing - * persistent state. - *

    - * This operation cascades to associated instances if the association is - * mapped with {@link jakarta.persistence.CascadeType#REMOVE}. + * Create an instance of {@link Query} for the given SQL query string, + * using the given {@code resultType} to interpret the results. * - *

    -		 * {@code session.delete(book).thenAccept(v -> session.flush());}
    -		 * 
    + *
      + *
    • If the given result type is {@link Object}, or a built-in type + * such as {@link String} or {@link Integer}, the result set must + * have a single column, which will be returned as a scalar.
    • + *
    • If the given result type is {@code Object[]}, then the result set + * must have multiple columns, which will be returned as elements of + * arrays of type {@code Object[]}.
    • + *
    • Otherwise, the given result type must be an entity class, in which + * case the result set column aliases must map to the fields of the + * entity, and the query will return instances of the entity.
    • + *
    * - * @param entity the managed persistent instance to be removed + * @param queryString The SQL query + * @param resultType the Java type returned in each row of query results * - * @throws IllegalArgumentException if the given instance is not managed + * @return The {@link SelectionQuery} instance for manipulation and execution * - * @see jakarta.persistence.EntityManager#remove(Object) + * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) */ - CompletionStage remove(Object entity); + SelectionQuery createNativeQuery(String queryString, Class resultType); /** - * Remove multiple entity instances at once. + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@code resultType} to interpret the results. * - * @see #remove(Object) - */ - CompletionStage remove(Object... entities); - - /** - * Copy the state of the given object onto the persistent instance with - * the same identifier. If there is no such persistent instance currently - * associated with the session, it will be loaded. Return the persistent - * instance. Or, if the given instance is transient, save a copy of it - * and return the copy as a newly persistent instance. The given instance - * does not become associated with the session. - *

    - * This operation cascades to associated instances if the association is - * mapped with {@link jakarta.persistence.CascadeType#MERGE}. + *

      + *
    • If the given result type is {@link Object}, or a built-in type + * such as {@link String} or {@link Integer}, the result set must + * have a single column, which will be returned as a scalar.
    • + *
    • If the given result type is {@code Object[]}, then the result set + * must have multiple columns, which will be returned as elements of + * arrays of type {@code Object[]}.
    • + *
    • Otherwise, the given result type must be an entity class, in which + * case the result set column aliases must map to the fields of the + * entity, and the query will return instances of the entity.
    • + *
    * - * @param entity a detached instance with state to be copied + * Any {@link AffectedEntities affected entities} are synchronized with + * the database before execution of the query. * - * @return an updated persistent instance + * @param queryString The SQL query + * @param resultType the Java type returned in each row of query results + * @param affectedEntities The entities which are affected by the query * - * @see jakarta.persistence.EntityManager#merge(Object) + * @return The {@link Query} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) */ - CompletionStage merge(T entity); + SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities); /** - * Merge multiple entity instances at once. + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@link ResultSetMapping} to interpret the + * result set. * - * @see #merge(Object) + * @param queryString The SQL query + * @param resultSetMapping the result set mapping + * + * @return The {@link Query} instance for manipulation and execution + * + * @see #getResultSetMapping(Class, String) + * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) */ - CompletionStage merge(Object... entities); + SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping); /** - * Re-read the state of the given instance from the underlying database. - * It is inadvisable to use this to implement long-running sessions that - * span many business tasks. This method is, however, useful in certain - * special circumstances, for example: - * - *
      - *
    • where a database trigger alters the object state after insert or - * update, or - *
    • after executing direct native SQL in the same session. - *
    + * Create an instance of {@link SelectionQuery} for the given SQL query + * string, using the given {@link ResultSetMapping} to interpret the + * result set. + *

    + * Any {@link AffectedEntities affected entities} are synchronized with + * the database before execution of the query. * - * @param entity a managed persistent instance + * @param queryString The SQL query + * @param resultSetMapping the result set mapping + * @param affectedEntities The entities which are affected by the query * - * @throws IllegalArgumentException if the given instance is not managed + * @return The {@link Query} instance for manipulation and execution * - * @see jakarta.persistence.EntityManager#refresh(Object) + * @see #getResultSetMapping(Class, String) + * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) */ - CompletionStage refresh(Object entity); + SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities); /** - * Re-read the state of the given instance from the underlying database, - * requesting the given {@link LockMode}. + * Create an instance of {@link Query} for the given SQL query string, + * or SQL update, insert, or delete statement. In the case of an update, + * insert, or delete, the returned {@link Query} must be executed using + * {@link Query#executeUpdate()} which returns an affected row count. + * In the case of a query: * - * @param entity a managed persistent entity instance - * @param lockMode the requested lock mode + *

      + *
    • If the result set has a single column, the results will be returned + * as scalars.
    • + *
    • Otherwise, if the result set has multiple columns, the results will + * be returned as elements of arrays of type {@code Object[]}.
    • + *
    * - * @see #refresh(Object) + * @param queryString The SQL select, update, insert, or delete statement */ - CompletionStage refresh(Object entity, LockMode lockMode); + Query createNativeQuery(String queryString); /** - * Re-read the state of the given instance from the underlying database, - * requesting the given {@link LockModeType}. + * Create an instance of {@link Query} for the given SQL query string, + * or SQL update, insert, or delete statement. In the case of an update, + * insert, or delete, the returned {@link Query} must be executed using + * {@link Query#executeUpdate()} which returns an affected row count. + * In the case of a query: * - * @param entity a managed persistent entity instance - * @param lockModeType the requested lock mode + *
      + *
    • If the result set has a single column, the results will be returned + * as scalars.
    • + *
    • Otherwise, if the result set has multiple columns, the results will + * be returned as elements of arrays of type {@code Object[]}.
    • + *
    * - * @see #refresh(Object) + * Any {@link AffectedEntities affected entities} are synchronized with + * the database before execution of the statement. + * + * @param queryString The SQL select, update, insert, or delete statement + * @param affectedEntities The entities which are affected by the statement */ - default CompletionStage refresh(Object entity, LockModeType lockModeType) { - return refresh( entity, convertToLockMode(lockModeType) ); - } - -// /** -// * Re-read the state of the given instance from the underlying database, -// * requesting the given {@link LockOptions}. -// * -// * @param entity a managed persistent entity instance -// * @param lockOptions the requested {@link LockOptions} -// * -// * @see #refresh(Object) -// */ -// CompletionStage refresh(Object entity, LockOptions lockOptions); + Query createNativeQuery(String queryString, AffectedEntities affectedEntities); /** - * Refresh multiple entity instances at once. + * Create an instance of {@link SelectionQuery} for the given criteria + * query. * - * @see #refresh(Object) + * @param criteriaQuery The {@link CriteriaQuery} + * + * @return The {@link SelectionQuery} instance for manipulation and execution + * + * @see jakarta.persistence.EntityManager#createQuery(String) */ - CompletionStage refresh(Object... entities); + SelectionQuery createQuery(CriteriaQuery criteriaQuery); /** - * Obtain the specified lock level upon the given object. For example, - * this operation may be used to: + * Asynchronously fetch an association that's configured for lazy loading, + * and unwrap the underlying entity implementation from any proxy. * - *
      - *
    • perform a version check with {@link LockMode#PESSIMISTIC_READ}, - *
    • upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}, - *
    • force a version increment with {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}, - *
    • schedule a version check just before the end of the transaction with - * {@link LockMode#OPTIMISTIC}, or - *
    • schedule a version increment just before the end of the transaction - * with {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}. - *
    + *
    +		 * {@code session.unproxy(author.getBook()).thenAccept(book -> print(book.getTitle()));}
    +		 * 
    * - * This operation cascades to associated instances if the association is - * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. + * @param association a lazy-loaded association * - * @param entity a managed persistent instance - * @param lockMode the lock level + * @return the fetched association, via a {@code CompletionStage} * - * @throws IllegalArgumentException if the given instance is not managed + * @see org.hibernate.Hibernate#unproxy(Object) */ - CompletionStage lock(Object entity, LockMode lockMode); + CompletionStage unproxy(T association); /** - * Obtain the specified lock level upon the given object. For example, - * this operation may be used to: - * - *
      - *
    • perform a version check with {@link LockModeType#PESSIMISTIC_READ}, - *
    • upgrade to a pessimistic lock with {@link LockModeType#PESSIMISTIC_WRITE}, - *
    • force a version increment with {@link LockModeType#PESSIMISTIC_FORCE_INCREMENT}, - *
    • schedule a version check just before the end of the transaction with - * {@link LockModeType#OPTIMISTIC}, or - *
    • schedule a version increment just before the end of the transaction - * with {@link LockModeType#OPTIMISTIC_FORCE_INCREMENT}. - *
    + * Return the identifier value of the given entity, which may be detached. * - * This operation cascades to associated instances if the association is - * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. + * @param entity a persistent instance associated with this session * - * @param entity a managed persistent instance - * @param lockModeType the lock level + * @return the identifier * - * @throws IllegalArgumentException if the given instance is not managed + * @since 3.0 */ - default CompletionStage lock(Object entity, LockModeType lockModeType) { - return lock( entity, convertToLockMode(lockModeType) ); - } + Object getIdentifier(Object entity); -// /** -// * Obtain the specified lock level upon the given object, with the given -// * {@link LockOptions}. -// * -// * @param entity a managed persistent instance -// * @param lockOptions the requested {@link LockOptions} -// * -// * @throws IllegalArgumentException if the given instance is not managed -// */ -// CompletionStage lock(Object entity, LockOptions lockOptions); + /** + * Obtain a native SQL result set mapping defined via the annotation + * {@link jakarta.persistence.SqlResultSetMapping}. + */ + ResultSetMapping getResultSetMapping(Class resultType, String mappingName); /** - * Force this session to flush asynchronously. Must be called at the - * end of a unit of work, before committing the transaction and closing - * the session. Flushing is the process of synchronizing the - * underlying persistent store with state held in memory. - * - *
    -		 * {@code session.flush().thenAccept(v -> print("done saving changes"));}
    -		 * 
    - * - * @see jakarta.persistence.EntityManager#flush() + * Obtain a named {@link EntityGraph} */ - CompletionStage flush(); + EntityGraph getEntityGraph(Class rootType, String graphName); /** - * Asynchronously fetch an association that's configured for lazy loading. + * Create a new mutable {@link EntityGraph} + */ + EntityGraph createEntityGraph(Class rootType); + + /** + * Create a new mutable copy of a named {@link EntityGraph} + */ + EntityGraph createEntityGraph(Class rootType, String graphName); + + /** + * Performs the given work within the scope of a database transaction, + * automatically flushing the session. The transaction will be rolled + * back if the work completes with an uncaught exception, or if + * {@link Transaction#markForRollback()} is called. *

    - *

    -		 * {@code session.fetch(author.getBook()).thenAccept(book -> print(book.getTitle()))}
    -		 * 
    - *

    + * The resulting {@link Transaction} object may also be obtained via + * {@link #currentTransaction()}. *

    - * It can also initialize proxys. For example: + * + *

  • If there is already a transaction associated with this session, + * the work is executed in the context of the existing transaction, and + * no new transaction is initiated. + *
  • If there is no transaction associated with this session, a new + * transaction is started, and the work is executed in the context of + * the new transaction. + * + * + * @param work a function which accepts {@link Transaction} and returns + * the result of the work as a {@link CompletionStage}. + * + * @see SessionFactory#withTransaction(BiFunction) + */ + CompletionStage withTransaction(Function> work); + + /** + * Obtain the transaction currently associated with this session, + * if any. + * + * @return the {@link Transaction}, or null if no transaction + * was started using {@link #withTransaction(Function)}. + * + * @see #withTransaction(Function) + * @see SessionFactory#withTransaction(BiFunction) + */ + Transaction currentTransaction(); + + /** + * @return false if {@link #close()} has been called + */ + boolean isOpen(); + + /** + * The {@link SessionFactory} which created this session. + */ + SessionFactory getFactory(); + } + + /** + * A non-blocking counterpart to the Hibernate {@link org.hibernate.Session} + * interface, allowing a reactive style of interaction with the database. + *

    + * The semantics of operations on this interface are identical to the + * semantics of the similarly-named operations of {@code Session}, except + * that the operations are performed asynchronously, returning a + * {@link CompletionStage} without blocking the calling thread. + *

    + * Entities associated with an {@code Session} do not support transparent + * lazy association fetching. Instead, {@link #fetch(Object)} should be used + * to explicitly request asynchronous fetching of an association, or the + * association should be fetched eagerly when the entity is first retrieved, + * for example, by: + * + *

      + *
    • {@link #enableFetchProfile(String) enabling a fetch profile}, + *
    • using an {@link EntityGraph}, or + *
    • writing a {@code join fetch} clause in a HQL query. + *
    + * + * @see org.hibernate.Session + */ + interface Session extends SharedSessionContract { + + /** + * Asynchronously return the persistent instance of the given entity + * class with the given identifier, or {@code null} if there is no such + * persistent instance. If the instance is already associated with + * the session, return the associated instance. This method never + * returns an uninitialized instance. + * *
    -		 * {@code session.fetch(session.getReference(Author.class, authorId))}
    +		 * {@code session.find(Book.class, id).thenAccept(book -> print(book.getTitle()));}
     		 * 
    - *

    * - * @param association a lazy-loaded association, or a proxy + * @param entityClass The entity type + * @param id an identifier * - * @return the fetched association, via a {@code CompletionStage} + * @return a persistent instance or null via a {@code CompletionStage} * - * @see Stage#fetch(Object) - * @see #getReference(Class, Object) - * @see org.hibernate.Hibernate#initialize(Object) + * @see jakarta.persistence.EntityManager#find(Class, Object) */ - CompletionStage fetch(T association); + CompletionStage find(Class entityClass, Object id); /** - * Fetch a lazy property of the given entity, identified by a JPA - * {@link Attribute attribute metamodel}. Note that this feature is - * only supported in conjunction with the Hibernate bytecode enhancer. + * Asynchronously return the persistent instance of the given entity + * class with the given identifier, requesting the given {@link LockMode}. * - *
    -		 * {@code session.fetch(book, Book_.isbn).thenAccept(isbn -> print(isbn))}
    -		 * 
    + * @param entityClass The entity type + * @param id an identifier + * @param lockMode the requested {@link LockMode} + * + * @return a persistent instance or null via a {@code CompletionStage} + * + * @see #find(Class,Object) + * @see #lock(Object, LockMode) this discussion of lock modes */ - CompletionStage fetch(E entity, Attribute field); + CompletionStage find(Class entityClass, Object id, LockMode lockMode); /** - * Asynchronously fetch an association that's configured for lazy loading, - * and unwrap the underlying entity implementation from any proxy. + * Asynchronously return the persistent instance of the given entity + * class with the given identifier, requesting the given {@link LockModeType}. * - *
    -		 * {@code session.unproxy(author.getBook()).thenAccept(book -> print(book.getTitle()));}
    -		 * 
    + * @param entityClass The entity type + * @param id an identifier + * @param lockModeType the requested {@link LockModeType} * - * @param association a lazy-loaded association + * @return a persistent instance or null via a {@code CompletionStage} * - * @return the fetched association, via a {@code CompletionStage} + * @see #find(Class,Object) + * @see #lock(Object, LockMode) this discussion of lock modes + */ + default CompletionStage find(Class entityClass, Object id, LockModeType lockModeType) { + return find( entityClass, id, convertToLockMode(lockModeType) ); + } + + /** + * Asynchronously return the persistent instance with the given + * identifier of an entity class, using the given {@link EntityGraph} + * as a fetch plan. * - * @see org.hibernate.Hibernate#unproxy(Object) + * @param entityGraph an {@link EntityGraph} specifying the entity + * and associations to be fetched + * @param id an identifier + * + * @see #find(Class,Object) */ - CompletionStage unproxy(T association); + CompletionStage find(EntityGraph entityGraph, Object id); /** - * Determine the current lock mode of the given entity. + * Asynchronously return the persistent instances of the given entity + * class with the given identifiers, or null if there is no such + * persistent instance. + * + * @param entityClass The entity type + * @param ids the identifiers + * + * @return a list of persistent instances and nulls via a {@code CompletionStage} */ - LockMode getLockMode(Object entity); + CompletionStage> find(Class entityClass, Object... ids); /** - * Determine if the given instance belongs to this persistence context. + * Asynchronously return the persistent instance of the given entity + * class with the given natural identifiers, or null if there is no + * such persistent instance. + * + * @param entityClass The entity type + * @param naturalId the natural identifier + * + * @return a persistent instance or null via a {@code CompletionStage} */ - boolean contains(Object entity); + @Incubating + CompletionStage find(Class entityClass, Identifier naturalId); /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string. + * Return the persistent instance of the given entity class with the + * given identifier, assuming that the instance exists. This method + * never results in access to the underlying data store, and thus + * might return a proxy that must be initialized explicitly using + * {@link #fetch(Object)}. + *

    + * You should not use this method to determine if an instance exists + * (use {@link #find} instead). Use this only to retrieve an instance + * which you safely assume exists, where non-existence would be an + * actual error. * - * @param queryString The HQL/JPQL query + * @param entityClass a persistent class + * @param id a valid identifier of an existing persistent instance of the class * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @return the persistent instance or proxy * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) + * @see jakarta.persistence.EntityManager#getReference(Class, Object) */ - SelectionQuery createSelectionQuery(String queryString, Class resultType); + T getReference(Class entityClass, Object id); /** - * Create an instance of {@link MutationQuery} for the given HQL/JPQL - * update or delete statement. - * - * @param queryString The HQL/JPQL query, update or delete statement + * Return the persistent instance with the same identity as the given + * instance, which might be detached, assuming that the instance is + * still persistent in the database. This method never results in + * access to the underlying data store, and thus might return a proxy + * that must be initialized explicitly using {@link #fetch(Object)}. * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entity a detached persistent instance * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @return the persistent instance or proxy */ - MutationQuery createMutationQuery(String queryString); + T getReference(T entity); /** - * Create an instance of {@link MutationQuery} for the given update tree. + * Asynchronously persist the given transient instance, first assigning + * a generated identifier. (Or using the current value of the identifier + * property if the entity has assigned identifiers.) + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link jakarta.persistence.CascadeType#PERSIST}. * - * @param updateQuery the update criteria query + *

    +		 * {@code session.persist(newBook).thenAccept(v -> session.flush());}
    +		 * 
    * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entity a transient instance of a persistent class * - * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) + * @see jakarta.persistence.EntityManager#persist(Object) */ - MutationQuery createMutationQuery(CriteriaUpdate updateQuery); + CompletionStage persist(Object entity); /** - * Create an instance of {@link MutationQuery} for the given delete tree. - * - * @param deleteQuery the delete criteria query + * Make a transient instance persistent and mark it for later insertion in the + * database. This operation cascades to associated instances if the association + * is mapped with {@link jakarta.persistence.CascadeType#PERSIST}. + *

    + * For entities with a {@link jakarta.persistence.GeneratedValue generated id}, + * {@code persist()} ultimately results in generation of an identifier for the + * given instance. But this may happen asynchronously, when the session is + * {@linkplain #flush() flushed}, depending on the identifier generation strategy. * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entityName the entity name + * @param object a transient instance to be made persistent + * @see #persist(Object) + */ + CompletionStage persist(String entityName, Object object); + + /** + * Persist multiple transient entity instances at once. * - * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) + * @see #persist(Object) */ - MutationQuery createMutationQuery(CriteriaDelete deleteQuery); + CompletionStage persist(Object... entities); /** - * Create a {@link MutationQuery} from the given insert select criteria tree + * Asynchronously remove a persistent instance from the datastore. The + * argument may be an instance associated with the receiving session or + * a transient instance with an identifier associated with existing + * persistent state. + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link jakarta.persistence.CascadeType#REMOVE}. * - * @param insert the insert select criteria query + *

    +		 * {@code session.delete(book).thenAccept(v -> session.flush());}
    +		 * 
    * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entity the managed persistent instance to be removed * - * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) + * @throws IllegalArgumentException if the given instance is not managed + * + * @see jakarta.persistence.EntityManager#remove(Object) */ - MutationQuery createMutationQuery(JpaCriteriaInsert insert); + CompletionStage remove(Object entity); /** - * Create an instance of {@link Query} for the given HQL/JPQL query - * string or HQL/JPQL update or delete statement. In the case of an - * update or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. + * Remove multiple entity instances at once. * - * @param queryString The HQL/JPQL query, update or delete statement + * @see #remove(Object) + */ + CompletionStage remove(Object... entities); + + /** + * Copy the state of the given object onto the persistent instance with + * the same identifier. If there is no such persistent instance currently + * associated with the session, it will be loaded. Return the persistent + * instance. Or, if the given instance is transient, save a copy of it + * and return the copy as a newly persistent instance. The given instance + * does not become associated with the session. + *

    + * This operation cascades to associated instances if the association is + * mapped with {@link jakarta.persistence.CascadeType#MERGE}. * - * @return The {@link Query} instance for manipulation and execution + * @param entity a detached instance with state to be copied * - * @deprecated See explanation in - * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)} + * @return an updated persistent instance * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @see jakarta.persistence.EntityManager#merge(Object) */ - @Deprecated - Query createQuery(String queryString); + CompletionStage merge(T entity); /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string and query result type. - * - * @param queryString The HQL/JPQL query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link Query} instance for manipulation and execution + * Merge multiple entity instances at once. * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) + * @see #merge(Object) */ - SelectionQuery createQuery(String queryString, Class resultType); + CompletionStage merge(Object... entities); /** - * Create an instance of {@link MutationQuery} for the given criteria - * update. + * Re-read the state of the given instance from the underlying database. + * It is inadvisable to use this to implement long-running sessions that + * span many business tasks. This method is, however, useful in certain + * special circumstances, for example: * - * @param criteriaUpdate The {@link CriteriaUpdate} + *

      + *
    • where a database trigger alters the object state after insert or + * update, or + *
    • after executing direct native SQL in the same session. + *
    * - * @return The {@link MutationQuery} instance for manipulation and execution + * @param entity a managed persistent instance + * + * @throws IllegalArgumentException if the given instance is not managed + * + * @see jakarta.persistence.EntityManager#refresh(Object) */ - MutationQuery createQuery(CriteriaUpdate criteriaUpdate); + CompletionStage refresh(Object entity); /** - * Create an instance of {@link MutationQuery} for the given criteria - * delete. + * Re-read the state of the given instance from the underlying database, + * requesting the given {@link LockMode}. * - * @param criteriaDelete The {@link CriteriaDelete} + * @param entity a managed persistent entity instance + * @param lockMode the requested lock mode * - * @return The {@link MutationQuery} instance for manipulation and execution + * @see #refresh(Object) */ - MutationQuery createQuery(CriteriaDelete criteriaDelete); + CompletionStage refresh(Object entity, LockMode lockMode); /** - * Create an instance of {@link Query} for the named query. - * - * @param queryName The name of the query + * Re-read the state of the given instance from the underlying database, + * requesting the given {@link LockModeType}. * - * @return The {@link Query} instance for manipulation and execution + * @param entity a managed persistent entity instance + * @param lockModeType the requested lock mode * - * @see jakarta.persistence.EntityManager#createQuery(String) + * @see #refresh(Object) */ - Query createNamedQuery(String queryName); + default CompletionStage refresh(Object entity, LockModeType lockModeType) { + return refresh( entity, convertToLockMode(lockModeType) ); + } /** - * Create an instance of {@link SelectionQuery} for the named query. - * - * @param queryName The name of the query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link SelectionQuery} instance for manipulation and execution + * Refresh multiple entity instances at once. * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) + * @see #refresh(Object) */ - SelectionQuery createNamedQuery(String queryName, Class resultType); + CompletionStage refresh(Object... entities); /** - * Create an instance of {@link Query} for the given SQL query string, - * using the given {@code resultType} to interpret the results. + * Obtain the specified lock level upon the given object. For example, + * this operation may be used to: * *
      - *
    • If the given result type is {@link Object}, or a built-in type - * such as {@link String} or {@link Integer}, the result set must - * have a single column, which will be returned as a scalar.
    • - *
    • If the given result type is {@code Object[]}, then the result set - * must have multiple columns, which will be returned as elements of - * arrays of type {@code Object[]}.
    • - *
    • Otherwise, the given result type must be an entity class, in which - * case the result set column aliases must map to the fields of the - * entity, and the query will return instances of the entity.
    • + *
    • perform a version check with {@link LockMode#PESSIMISTIC_READ}, + *
    • upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}, + *
    • force a version increment with {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}, + *
    • schedule a version check just before the end of the transaction with + * {@link LockMode#OPTIMISTIC}, or + *
    • schedule a version increment just before the end of the transaction + * with {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}. *
    * - * @param queryString The SQL query - * @param resultType the Java type returned in each row of query results + * This operation cascades to associated instances if the association is + * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. * - * @return The {@link SelectionQuery} instance for manipulation and execution + * @param entity a managed persistent instance + * @param lockMode the lock level * - * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) + * @throws IllegalArgumentException if the given instance is not managed */ - SelectionQuery createNativeQuery(String queryString, Class resultType); + CompletionStage lock(Object entity, LockMode lockMode); /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@code resultType} to interpret the results. + * Obtain the specified lock level upon the given object. For example, + * this operation may be used to: * *
      - *
    • If the given result type is {@link Object}, or a built-in type - * such as {@link String} or {@link Integer}, the result set must - * have a single column, which will be returned as a scalar.
    • - *
    • If the given result type is {@code Object[]}, then the result set - * must have multiple columns, which will be returned as elements of - * arrays of type {@code Object[]}.
    • - *
    • Otherwise, the given result type must be an entity class, in which - * case the result set column aliases must map to the fields of the - * entity, and the query will return instances of the entity.
    • + *
    • perform a version check with {@link LockModeType#PESSIMISTIC_READ}, + *
    • upgrade to a pessimistic lock with {@link LockModeType#PESSIMISTIC_WRITE}, + *
    • force a version increment with {@link LockModeType#PESSIMISTIC_FORCE_INCREMENT}, + *
    • schedule a version check just before the end of the transaction with + * {@link LockModeType#OPTIMISTIC}, or + *
    • schedule a version increment just before the end of the transaction + * with {@link LockModeType#OPTIMISTIC_FORCE_INCREMENT}. *
    * - * Any {@link AffectedEntities affected entities} are synchronized with - * the database before execution of the query. - * - * @param queryString The SQL query - * @param resultType the Java type returned in each row of query results - * @param affectedEntities The entities which are affected by the query + * This operation cascades to associated instances if the association is + * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}. * - * @return The {@link Query} instance for manipulation and execution + * @param entity a managed persistent instance + * @param lockModeType the lock level * - * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class) + * @throws IllegalArgumentException if the given instance is not managed */ - SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities); + default CompletionStage lock(Object entity, LockModeType lockModeType) { + return lock( entity, convertToLockMode(lockModeType) ); + } /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@link ResultSetMapping} to interpret the - * result set. - * - * @param queryString The SQL query - * @param resultSetMapping the result set mapping + * Force this session to flush asynchronously. Must be called at the + * end of a unit of work, before committing the transaction and closing + * the session. Flushing is the process of synchronizing the + * underlying persistent store with state held in memory. * - * @return The {@link Query} instance for manipulation and execution + *
    +		 * {@code session.flush().thenAccept(v -> print("done saving changes"));}
    +		 * 
    * - * @see #getResultSetMapping(Class, String) - * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) + * @see jakarta.persistence.EntityManager#flush() */ - SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping); + CompletionStage flush(); /** - * Create an instance of {@link SelectionQuery} for the given SQL query - * string, using the given {@link ResultSetMapping} to interpret the - * result set. + * Asynchronously fetch an association that's configured for lazy loading. *

    - * Any {@link AffectedEntities affected entities} are synchronized with - * the database before execution of the query. + *

    +		 * {@code session.fetch(author.getBook()).thenAccept(book -> print(book.getTitle()))}
    +		 * 
    + *

    + *

    + * It can also initialize proxys. For example: + *

    +		 * {@code session.fetch(session.getReference(Author.class, authorId))}
    +		 * 
    + *

    * - * @param queryString The SQL query - * @param resultSetMapping the result set mapping - * @param affectedEntities The entities which are affected by the query + * @param association a lazy-loaded association, or a proxy * - * @return The {@link Query} instance for manipulation and execution + * @return the fetched association, via a {@code CompletionStage} * - * @see #getResultSetMapping(Class, String) - * @see jakarta.persistence.EntityManager#createNativeQuery(String, String) + * @see Stage#fetch(Object) + * @see #getReference(Class, Object) + * @see org.hibernate.Hibernate#initialize(Object) */ - SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities); + CompletionStage fetch(T association); /** - * Create an instance of {@link Query} for the given SQL query string, - * or SQL update, insert, or delete statement. In the case of an update, - * insert, or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * In the case of a query: - * - *
      - *
    • If the result set has a single column, the results will be returned - * as scalars.
    • - *
    • Otherwise, if the result set has multiple columns, the results will - * be returned as elements of arrays of type {@code Object[]}.
    • - *
    + * Fetch a lazy property of the given entity, identified by a JPA + * {@link Attribute attribute metamodel}. Note that this feature is + * only supported in conjunction with the Hibernate bytecode enhancer. * - * @param queryString The SQL select, update, insert, or delete statement + *
    +		 * {@code session.fetch(book, Book_.isbn).thenAccept(isbn -> print(isbn))}
    +		 * 
    */ - Query createNativeQuery(String queryString); + CompletionStage fetch(E entity, Attribute field); /** - * Create an instance of {@link Query} for the given SQL query string, - * or SQL update, insert, or delete statement. In the case of an update, - * insert, or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * In the case of a query: - * - *
      - *
    • If the result set has a single column, the results will be returned - * as scalars.
    • - *
    • Otherwise, if the result set has multiple columns, the results will - * be returned as elements of arrays of type {@code Object[]}.
    • - *
    - * - * Any {@link AffectedEntities affected entities} are synchronized with - * the database before execution of the statement. - * - * @param queryString The SQL select, update, insert, or delete statement - * @param affectedEntities The entities which are affected by the statement + * Determine the current lock mode of the given entity. */ - Query createNativeQuery(String queryString, AffectedEntities affectedEntities); + LockMode getLockMode(Object entity); /** - * Create an instance of {@link SelectionQuery} for the given criteria - * query. - * - * @param criteriaQuery The {@link CriteriaQuery} - * - * @return The {@link SelectionQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) + * Determine if the given instance belongs to this persistence context. */ - SelectionQuery createQuery(CriteriaQuery criteriaQuery); + boolean contains(Object entity); /** * Set the {@link FlushMode flush mode} for this session. @@ -1313,27 +1350,6 @@ default Session setFlushMode(FlushModeType flushModeType) { */ Session enableFetchProfile(String name); - /** - * Obtain a native SQL result set mapping defined via the annotation - * {@link jakarta.persistence.SqlResultSetMapping}. - */ - ResultSetMapping getResultSetMapping(Class resultType, String mappingName); - - /** - * Obtain a named {@link EntityGraph} - */ - EntityGraph getEntityGraph(Class rootType, String graphName); - - /** - * Create a new mutable {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType); - - /** - * Create a new mutable copy of a named {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType, String graphName); - /** * Disable a particular fetch profile on this session, or do nothing if * the requested fetch profile is not enabled. @@ -1501,63 +1517,16 @@ default Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { * * @param filterName The name of the filter to be disabled. */ - void disableFilter(String filterName); - - /** - * Retrieve a currently enabled filter by name. - * - * @param filterName The name of the filter to be retrieved. - * - * @return The Filter instance representing the enabled filter. - */ - Filter getEnabledFilter(String filterName); - - /** - * Performs the given work within the scope of a database transaction, - * automatically flushing the session. The transaction will be rolled - * back if the work completes with an uncaught exception, or if - * {@link Transaction#markForRollback()} is called. - *

    - * The resulting {@link Transaction} object may also be obtained via - * {@link #currentTransaction()}. - *

    - * - *

  • If there is already a transaction associated with this session, - * the work is executed in the context of the existing transaction, and - * no new transaction is initiated. - *
  • If there is no transaction associated with this session, a new - * transaction is started, and the work is executed in the context of - * the new transaction. - * - * - * @param work a function which accepts {@link Transaction} and returns - * the result of the work as a {@link CompletionStage}. - * - * @see SessionFactory#withTransaction(BiFunction) - */ - CompletionStage withTransaction(Function> work); - - /** - * Obtain the transaction currently associated with this session, - * if any. - * - * @return the {@link Transaction}, or null if no transaction - * was started using {@link #withTransaction(Function)}. - * - * @see #withTransaction(Function) - * @see SessionFactory#withTransaction(BiFunction) - */ - Transaction currentTransaction(); - - /** - * @return false if {@link #close()} has been called - */ - boolean isOpen(); + void disableFilter(String filterName); /** - * The {@link SessionFactory} which created this session. + * Retrieve a currently enabled filter by name. + * + * @param filterName The name of the filter to be retrieved. + * + * @return The Filter instance representing the enabled filter. */ - SessionFactory getFactory(); + Filter getEnabledFilter(String filterName); } /** @@ -1590,7 +1559,7 @@ default Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { * * @see org.hibernate.StatelessSession */ - interface StatelessSession extends Closeable { + interface StatelessSession extends SharedSessionContract { /** * Retrieve a row. @@ -1655,178 +1624,6 @@ default CompletionStage get(Class entityClass, Object id, LockModeType */ CompletionStage get(EntityGraph entityGraph, Object id); - /** - * Create an instance of {@link Query} for the given HQL/JPQL query - * string or HQL/JPQL update or delete statement. In the case of an - * update or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * - * @param queryString The HQL/JPQL query, update or delete statement - * - * @return The {@link Query} instance for manipulation and execution - * - * @deprecated See explanation in - * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)} - * - * @see org.hibernate.Session#createQuery(String) - */ - @Deprecated - Query createQuery(String queryString); - - /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string and query result type. - * - * @param queryString The HQL/JPQL query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link Query} instance for manipulation and execution - * - * @see org.hibernate.Session#createQuery(String, Class) - */ - SelectionQuery createQuery(String queryString, Class resultType); - - /** - * Create an instance of {@link SelectionQuery} for the given HQL/JPQL - * query string. - * - * @param queryString The HQL/JPQL query - * - * @return The {@link SelectionQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) - */ - SelectionQuery createSelectionQuery(String queryString, Class resultType); - - /** - * Create an instance of {@link MutationQuery} for the given HQL/JPQL - * update or delete statement. - * - * @param queryString The HQL/JPQL query, update or delete statement - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - MutationQuery createMutationQuery(String queryString); - - /** - * Create an instance of {@link MutationQuery} for the given update tree. - * - * @param updateQuery the update criteria query - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate) - */ - MutationQuery createMutationQuery(CriteriaUpdate updateQuery); - - /** - * Create an instance of {@link MutationQuery} for the given delete tree. - * - * @param deleteQuery the delete criteria query - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete) - */ - MutationQuery createMutationQuery(CriteriaDelete deleteQuery); - - /** - * Create a {@link MutationQuery} from the given insert select criteria tree - * - * @param insert the insert select criteria query - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert) - */ - MutationQuery createMutationQuery(JpaCriteriaInsert insert); - - /** - * Create an instance of {@link Query} for the given SQL query string, - * or SQL update, insert, or delete statement. In the case of an update, - * insert, or delete, the returned {@link Query} must be executed using - * {@link Query#executeUpdate()} which returns an affected row count. - * - * @param queryString The SQL select, update, insert, or delete statement - * - * @see org.hibernate.Session#createNativeQuery(String) - */ - Query createNativeQuery(String queryString); - - /** - * Create an instance of {@link Query} for the named query. - * - * @param queryName The name of the query - * - * @return The {@link Query} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - Query createNamedQuery(String queryName); - - /** - * Create an instance of {@link Query} for the named query. - * - * @param queryName The name of the query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link Query} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String, Class) - */ - SelectionQuery createNamedQuery(String queryName, Class resultType); - - /** - * Create an instance of {@link Query} for the given SQL query string, - * using the given {@code resultType} to interpret the results. - * - * @param queryString The SQL query - * @param resultType the Java type returned in each row of query results - * - * @return The {@link Query} instance for manipulation and execution - * - * @see org.hibernate.Session#createNativeQuery(String, Class) - */ - SelectionQuery createNativeQuery(String queryString, Class resultType); - - /** - * Create an instance of {@link SelectionQuery} for the given criteria - * query. - * - * @param criteriaQuery The {@link CriteriaQuery} - * - * @return The {@link SelectionQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - SelectionQuery createQuery(CriteriaQuery criteriaQuery); - - /** - * Create an instance of {@link MutationQuery} for the given criteria - * update. - * - * @param criteriaUpdate The {@link CriteriaUpdate} - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - MutationQuery createQuery(CriteriaUpdate criteriaUpdate); - - /** - * Create an instance of {@link MutationQuery} for the given criteria - * delete. - * - * @param criteriaDelete The {@link CriteriaDelete} - * - * @return The {@link MutationQuery} instance for manipulation and execution - * - * @see jakarta.persistence.EntityManager#createQuery(String) - */ - MutationQuery createQuery(CriteriaDelete criteriaDelete); - /** * Insert a row. * @@ -2035,87 +1832,6 @@ default CompletionStage refresh(Object entity, LockModeType lockModeType) * @see org.hibernate.Hibernate#initialize(Object) */ CompletionStage fetch(T association); - - /** - * Return the identifier value of the given entity, which may be detached. - * - * @param entity a persistent instance associated with this session - * - * @return the identifier - * - * @since 3.0 - */ - Object getIdentifier(Object entity); - - /** - * Obtain a native SQL result set mapping defined via the annotation - * {@link jakarta.persistence.SqlResultSetMapping}. - */ - ResultSetMapping getResultSetMapping(Class resultType, String mappingName); - - /** - * Obtain a named {@link EntityGraph} - */ - EntityGraph getEntityGraph(Class rootType, String graphName); - - /** - * Create a new mutable {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType); - - /** - * Create a new mutable copy of a named {@link EntityGraph} - */ - EntityGraph createEntityGraph(Class rootType, String graphName); - - /** - * Performs the given work within the scope of a database transaction, - * automatically flushing the session. The transaction will be rolled - * back if the work completes with an uncaught exception, or if - * {@link Transaction#markForRollback()} is called. - * - *
  • If there is already a transaction associated with this session, - * the work is executed in the context of the existing transaction, and - * no new transaction is initiated. - *
  • If there is no transaction associated with this session, a new - * transaction is started, and the work is executed in the context of - * the new transaction. - * - * - * @param work a function which accepts {@link Transaction} and returns - * the result of the work as a {@link CompletionStage}. - * - * @see SessionFactory#withTransaction(BiFunction) - */ - CompletionStage withTransaction(Function> work); - - /** - * Obtain the transaction currently associated with this session, - * if any. - * - * @return the {@link Transaction}, or null if no transaction - * was started using {@link #withTransaction(Function)}. - * - * @see #withTransaction(Function) - * @see SessionFactory#withTransaction(BiFunction) - */ - Transaction currentTransaction(); - - /** - * @return false if {@link #close()} has been called - */ - boolean isOpen(); - - /** - * Close the reactive session and release the underlying database - * connection. - */ - CompletionStage close(); - - /** - * The {@link SessionFactory} which created this session. - */ - SessionFactory getFactory(); } /** diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java index 78ce3c891..53062793c 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSessionImpl.java @@ -5,16 +5,11 @@ */ package org.hibernate.reactive.stage.impl; -import jakarta.persistence.CacheRetrieveMode; -import jakarta.persistence.CacheStoreMode; -import jakarta.persistence.EntityGraph; -import jakarta.persistence.FlushModeType; -import jakarta.persistence.LockModeType; -import jakarta.persistence.PersistenceException; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; -import jakarta.persistence.metamodel.Attribute; +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + import org.hibernate.CacheMode; import org.hibernate.Filter; import org.hibernate.FlushMode; @@ -39,10 +34,16 @@ import org.hibernate.reactive.stage.Stage.Query; import org.hibernate.reactive.stage.Stage.SelectionQuery; -import java.lang.invoke.MethodHandles; -import java.util.List; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.EntityGraph; +import jakarta.persistence.FlushModeType; +import jakarta.persistence.LockModeType; +import jakarta.persistence.PersistenceException; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Attribute; import static org.hibernate.reactive.util.impl.CompletionStages.applyToAll; import static org.hibernate.reactive.util.impl.CompletionStages.returnOrRethrow; @@ -68,6 +69,11 @@ public CompletionStage flush() { return delegate.reactiveFlush(); } + @Override + public Object getIdentifier(Object entity) { + return delegate.getIdentifier(entity); + } + @Override public CompletionStage fetch(T association) { return delegate.reactiveFetch( association, false ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java index 7724a5cd1..85735cd12 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageStatelessSessionImpl.java @@ -5,13 +5,15 @@ */ package org.hibernate.reactive.stage.impl; -import jakarta.persistence.EntityGraph; -import jakarta.persistence.criteria.CriteriaDelete; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.CriteriaUpdate; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.function.Function; + import org.hibernate.LockMode; import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.query.criteria.JpaCriteriaInsert; +import org.hibernate.reactive.common.AffectedEntities; import org.hibernate.reactive.common.ResultSetMapping; import org.hibernate.reactive.pool.ReactiveConnection; import org.hibernate.reactive.session.ReactiveStatelessSession; @@ -20,10 +22,10 @@ import org.hibernate.reactive.stage.Stage.Query; import org.hibernate.reactive.stage.Stage.SelectionQuery; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.function.Function; +import jakarta.persistence.EntityGraph; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; import static org.hibernate.reactive.util.impl.CompletionStages.returnOrRethrow; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; @@ -160,6 +162,11 @@ public CompletionStage fetch(T association) { return delegate.reactiveFetch( association, false ); } + @Override + public CompletionStage unproxy(T association) { + return delegate.reactiveFetch( association, true ); + } + @Override public Object getIdentifier(Object entity) { return delegate.getIdentifier(entity); @@ -309,6 +316,11 @@ public Query createNativeQuery(String queryString) { return new StageQueryImpl<>( delegate.createReactiveNativeQuery( queryString ) ); } + @Override + public Query createNativeQuery(String queryString, AffectedEntities affectedEntities) { + return new StageQueryImpl<>( delegate.createReactiveNativeQuery( queryString, affectedEntities ) ); + } + @Override public Query createNamedQuery(String queryName) { return new StageQueryImpl<>( delegate.createReactiveNamedQuery( queryName, null ) ); @@ -324,6 +336,21 @@ public SelectionQuery createNativeQuery(String queryString, Class resu return new StageSelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultType ) ); } + @Override + public SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities) { + return new StageSelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultType, affectedEntities ) ); + } + + @Override + public SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping) { + return new StageSelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultSetMapping ) ); + } + + @Override + public SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities) { + return new StageSelectionQueryImpl<>( delegate.createReactiveNativeQuery( queryString, resultSetMapping, affectedEntities) ); + } + @Override public SelectionQuery createQuery(CriteriaQuery criteriaQuery) { return new StageSelectionQueryImpl<>( delegate.createReactiveQuery( criteriaQuery ) );