diff --git a/hibernate-core/src/main/java/org/hibernate/query/programmatic/MutationSpecification.java b/hibernate-core/src/main/java/org/hibernate/query/programmatic/MutationSpecification.java index e7d436c73c19..f2bfb848fa58 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/programmatic/MutationSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/query/programmatic/MutationSpecification.java @@ -10,7 +10,8 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Root; import org.hibernate.Incubating; -import org.hibernate.SharedSessionContract; +import org.hibernate.Session; +import org.hibernate.StatelessSession; import org.hibernate.query.IllegalMutationQueryException; import org.hibernate.query.MutationQuery; import org.hibernate.query.SelectionQuery; @@ -43,7 +44,7 @@ public interface MutationSpecification extends QuerySpecification { * Covariant override. */ @Override - MutationSpecification restrict(Restriction restriction); + MutationSpecification restrict(Restriction restriction); /** * A function capable of modifying or augmenting a criteria query. @@ -65,15 +66,21 @@ interface Augmentation { MutationSpecification augment(Augmentation augmentation); /** - * Finalize the building and create the {@linkplain SelectionQuery} instance. + * Finalize the building and create the {@linkplain MutationQuery} instance. */ @Override - MutationQuery createQuery(SharedSessionContract session); + MutationQuery createQuery(Session session); + + /** + * Finalize the building and create the {@linkplain MutationQuery} instance. + */ + @Override + MutationQuery createQuery(StatelessSession session); /** * Returns a specification reference which can be used to programmatically, * iteratively build a {@linkplain MutationQuery} based on a base HQL statement, - * allowing the addition of {@linkplain MutationSpecification#restrict restrictions}. + * allowing the addition of {@linkplain #restrict restrictions}. * * @param hql The base HQL query (expected to be an {@code update} or {@code delete} query). * @param mutationTarget The entity which is the target of the mutation. @@ -91,7 +98,7 @@ static MutationSpecification create(Class mutationTarget, String hql) /** * Returns a specification reference which can be used to programmatically, * iteratively build a {@linkplain MutationQuery} based on the given criteria update, - * allowing the addition of {@linkplain MutationSpecification#restrict restrictions}. + * allowing the addition of {@linkplain #restrict restrictions}. * * @param criteriaUpdate The criteria update query * @@ -104,7 +111,7 @@ static MutationSpecification create(CriteriaUpdate criteriaUpdate) { /** * Returns a specification reference which can be used to programmatically, * iteratively build a {@linkplain MutationQuery} based on the given criteria delete, - * allowing the addition of {@linkplain MutationSpecification#restrict restrictions}. + * allowing the addition of {@linkplain #restrict restrictions}. * * @param criteriaDelete The criteria delete query * diff --git a/hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java b/hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java index eccbdc27dc08..f24c4e8544e0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java @@ -4,9 +4,12 @@ */ package org.hibernate.query.programmatic; +import jakarta.persistence.EntityManager; + import org.hibernate.Incubating; +import org.hibernate.Session; import org.hibernate.SessionFactory; -import org.hibernate.SharedSessionContract; +import org.hibernate.StatelessSession; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.CommonQueryContract; import org.hibernate.query.restriction.Restriction; @@ -33,12 +36,22 @@ public interface QuerySpecification { * * @return {@code this} for method chaining. */ - QuerySpecification restrict(Restriction restriction); + QuerySpecification restrict(Restriction restriction); + + /** + * Finalize the building and create executable query instance. + */ + CommonQueryContract createQuery(Session session); + + /** + * Finalize the building and create executable query instance. + */ + CommonQueryContract createQuery(StatelessSession session); /** * Finalize the building and create executable query instance. */ - CommonQueryContract createQuery(SharedSessionContract session); + CommonQueryContract createQuery(EntityManager entityManager); /** * Validate the query. @@ -47,7 +60,9 @@ default void validate(SessionFactory factory) { // Extremely temporary implementation. // We don't actually want to open a session here, // nor create an instance of CommonQueryContract. - try ( var session = ((SessionFactoryImplementor) factory).openTemporarySession() ) { + final SessionFactoryImplementor factoryImplementor = + (SessionFactoryImplementor) factory; + try ( var session = factoryImplementor.openTemporarySession() ) { createQuery( session ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java b/hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java index 7ed622d3dc58..88f08bc443db 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java @@ -4,11 +4,13 @@ */ package org.hibernate.query.programmatic; +import jakarta.persistence.EntityManager; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Root; import org.hibernate.Incubating; -import org.hibernate.SharedSessionContract; +import org.hibernate.Session; +import org.hibernate.StatelessSession; import org.hibernate.query.IllegalSelectQueryException; import org.hibernate.query.Order; import org.hibernate.query.SelectionQuery; @@ -63,7 +65,7 @@ public interface SelectionSpecification extends QuerySpecification { * * @return {@code this} for method chaining. */ - SelectionSpecification sort(Order order); + SelectionSpecification sort(Order order); /** * Sets the ordering for this selection specification. @@ -74,7 +76,7 @@ public interface SelectionSpecification extends QuerySpecification { * * @return {@code this} for method chaining. */ - SelectionSpecification resort(Order order); + SelectionSpecification resort(Order order); /** * Sets the sorting for this selection specification. @@ -85,13 +87,13 @@ public interface SelectionSpecification extends QuerySpecification { * * @return {@code this} for method chaining. */ - SelectionSpecification resort(List> orders); + SelectionSpecification resort(List> orders); /** * Covariant override. */ @Override - SelectionSpecification restrict(Restriction restriction); + SelectionSpecification restrict(Restriction restriction); /** * Add a fetch {@linkplain Path path} to the specification. @@ -133,7 +135,7 @@ interface Augmentation { * SelectionSpecification.create(Book.class) * .augment((builder, query, book) -> * // eliminate explicit references to 'builder' - * new CriteriaDefinition<>(query) {{ + * new CriteriaDefinition<>(query) {{ * where(like(entity.get(BasicEntity_.title), titlePattern), * greaterThan(book.get(Book_.pages), minPages)); * orderBy(asc(book.get(Book_.isbn))); @@ -153,13 +155,22 @@ interface Augmentation { * Covariant override. */ @Override - SelectionQuery createQuery(SharedSessionContract session); + SelectionQuery createQuery(Session session); + + /** + * Covariant override. + */ + @Override + SelectionQuery createQuery(StatelessSession session); + + @Override + SelectionQuery createQuery(EntityManager entityManager); /** * Returns a specification reference which can be used to programmatically, * iteratively build a {@linkplain SelectionQuery} for the given entity type, - * allowing the addition of {@linkplain SelectionSpecification#sort sorting} - * and {@linkplain SelectionSpecification#restrict restrictions}. + * allowing the addition of {@linkplain #sort sorting} + * and {@linkplain #restrict restrictions}. * This is effectively the same as calling {@linkplain #create(Class, String)} * with {@code "from {rootEntityType}"} as the HQL. * @@ -175,8 +186,8 @@ static SelectionSpecification create(Class rootEntityType) { /** * Returns a specification reference which can be used to programmatically, * iteratively build a {@linkplain SelectionQuery} based on a base HQL statement, - * allowing the addition of {@linkplain SelectionSpecification#sort sorting} - * and {@linkplain SelectionSpecification#restrict restrictions}. + * allowing the addition of {@linkplain #sort sorting} + * and {@linkplain #restrict restrictions}. * * @param hql The base HQL query. * @param resultType The result type which will ultimately be returned from the {@linkplain SelectionQuery} @@ -194,8 +205,8 @@ static SelectionSpecification create(Class resultType, String hql) { /** * Returns a specification reference which can be used to programmatically, * iteratively build a {@linkplain SelectionQuery} for the given criteria query, - * allowing the addition of {@linkplain SelectionSpecification#sort sorting} - * and {@linkplain SelectionSpecification#restrict restrictions}. + * allowing the addition of {@linkplain #sort sorting} + * and {@linkplain #restrict restrictions}. * * @param criteria The criteria query * diff --git a/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java b/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java index d2d55eabaaa3..407b6b578277 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java @@ -4,10 +4,13 @@ */ package org.hibernate.query.programmatic.internal; +import jakarta.persistence.EntityManager; import jakarta.persistence.criteria.CriteriaDelete; import jakarta.persistence.criteria.CriteriaUpdate; import org.hibernate.AssertionFailure; +import org.hibernate.Session; import org.hibernate.SharedSessionContract; +import org.hibernate.StatelessSession; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.query.programmatic.MutationSpecification; import org.hibernate.query.IllegalMutationQueryException; @@ -62,7 +65,7 @@ public MutationSpecificationImpl(CriteriaDelete criteriaQuery) { } @Override - public MutationSpecification restrict(Restriction restriction) { + public MutationSpecification restrict(Restriction restriction) { specifications.add( (sqmStatement, mutationTargetRoot) -> { final SqmPredicate sqmPredicate = (SqmPredicate) restriction.toPredicate( mutationTargetRoot, @@ -81,6 +84,15 @@ public MutationSpecification augment(Augmentation augmentation) { } @Override + public MutationQuery createQuery(Session session) { + return createQuery( (SharedSessionContract) session ); + } + + @Override + public MutationQuery createQuery(StatelessSession session) { + return createQuery( (SharedSessionContract) session ); + } + public MutationQuery createQuery(SharedSessionContract session) { final var sessionImpl = (SharedSessionContractImplementor) session; final SqmDeleteOrUpdateStatement sqmStatement; @@ -101,6 +113,11 @@ else if ( deleteOrUpdateStatement != null ) { return new QuerySqmImpl<>( sqmStatement, true, null, sessionImpl ); } + @Override + public MutationQuery createQuery(EntityManager entityManager) { + return createQuery( (SharedSessionContract) entityManager ); + } + /** * Used during construction to parse/interpret the incoming HQL * and produce the corresponding SQM tree. diff --git a/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/SelectionSpecificationImpl.java b/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/SelectionSpecificationImpl.java index 399aa0a4926f..aad4efc77ecb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/SelectionSpecificationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/SelectionSpecificationImpl.java @@ -4,9 +4,12 @@ */ package org.hibernate.query.programmatic.internal; +import jakarta.persistence.EntityManager; import jakarta.persistence.criteria.CriteriaQuery; import org.hibernate.QueryException; +import org.hibernate.Session; import org.hibernate.SharedSessionContract; +import org.hibernate.StatelessSession; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.query.IllegalSelectQueryException; import org.hibernate.query.Order; @@ -64,7 +67,7 @@ public SelectionSpecificationImpl(CriteriaQuery criteriaQuery) { } @Override - public SelectionSpecification restrict(Restriction restriction) { + public SelectionSpecification restrict(Restriction restriction) { specifications.add( (sqmStatement, root) -> { final SqmPredicate sqmPredicate = SqmUtil.restriction( sqmStatement, resultType, restriction ); sqmStatement.getQuerySpec().applyPredicate( sqmPredicate ); @@ -86,7 +89,7 @@ public SelectionSpecification fetch(Path fetchPath) { } @Override - public SelectionSpecification sort(Order order) { + public SelectionSpecification sort(Order order) { specifications.add( (sqmStatement, root) -> { addOrder( order, sqmStatement ); } ); @@ -94,7 +97,7 @@ public SelectionSpecification sort(Order order) { } @Override - public final SelectionSpecification resort(Order order) { + public final SelectionSpecification resort(Order order) { specifications.add( (sqmStatement, root) -> { sqmStatement.getQuerySpec().setOrderByClause( new SqmOrderByClause() ); addOrder( order, sqmStatement ); @@ -103,7 +106,7 @@ public final SelectionSpecification resort(Order order) { } @Override - public final SelectionSpecification resort(List> orders) { + public final SelectionSpecification resort(List> orders) { specifications.add( (sqmStatement, root) -> { sqmStatement.getQuerySpec().setOrderByClause( new SqmOrderByClause() ); orders.forEach( order -> addOrder( order, sqmStatement ) ); @@ -111,7 +114,7 @@ public final SelectionSpecification resort(List> orders) { return this; } - private static void addOrder(Order order, SqmSelectStatement sqmStatement) { + private static void addOrder(Order order, SqmSelectStatement sqmStatement) { final SqmSortSpecification sortSpecification = SqmUtil.sortSpecification( sqmStatement, order ); final var querySpec = sqmStatement.getQuerySpec(); if ( querySpec.getOrderByClause() == null ) { @@ -121,6 +124,15 @@ private static void addOrder(Order order, SqmSelectStatement sqmStatem } @Override + public SelectionQuery createQuery(Session session) { + return createQuery( (SharedSessionContract) session ); + } + + @Override + public SelectionQuery createQuery(StatelessSession session) { + return createQuery( (SharedSessionContract) session ); + } + public SelectionQuery createQuery(SharedSessionContract session) { final var sessionImpl = (SharedSessionContractImplementor) session; final SqmSelectStatement sqmStatement; @@ -145,6 +157,11 @@ else if ( criteriaQuery != null ) { return new SqmSelectionQueryImpl<>( sqmStatement, true, resultType, sessionImpl ); } + @Override + public SelectionQuery createQuery(EntityManager entityManager) { + return createQuery( (SharedSessionContract) entityManager ); + } + /** * Used during construction to parse/interpret the incoming HQL * and produce the corresponding SQM tree. diff --git a/hibernate-core/src/main/java/org/hibernate/query/restriction/NamedPathElement.java b/hibernate-core/src/main/java/org/hibernate/query/restriction/NamedPathElement.java index 2a82b49b3fb7..d73f0e0a8e2b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/restriction/NamedPathElement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/restriction/NamedPathElement.java @@ -6,7 +6,7 @@ import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.FetchParent; - +import jakarta.persistence.criteria.JoinType; /** * A non-root element of a {@link Path}, using a stringly-typed @@ -33,6 +33,6 @@ public jakarta.persistence.criteria.Path path(Root root) { @Override public FetchParent fetch(Root root) { - return parent.fetch( root ).fetch( attributeName ); + return parent.fetch( root ).fetch( attributeName, JoinType.LEFT ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/restriction/PathElement.java b/hibernate-core/src/main/java/org/hibernate/query/restriction/PathElement.java index 6c9ec3dd3816..2df31174b0ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/restriction/PathElement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/restriction/PathElement.java @@ -6,6 +6,7 @@ import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.FetchParent; +import jakarta.persistence.criteria.JoinType; import jakarta.persistence.metamodel.SingularAttribute; /** @@ -27,6 +28,6 @@ public jakarta.persistence.criteria.Path path(Root root) { @Override public FetchParent fetch(Root root) { - return parent.fetch( root ).fetch( attribute ); + return parent.fetch( root ).fetch( attribute, JoinType.LEFT ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java index c1f307958e52..69668013ddbb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java @@ -947,7 +947,7 @@ public static Class resolveExpressibleJavaTypeClass(final SqmExpression ex public static SqmPredicate restriction( SqmSelectStatement sqmStatement, Class resultType, - Restriction restriction) { + Restriction restriction) { //noinspection unchecked final JpaRoot root = (JpaRoot) sqmStatement.getRoot( 0, resultType ); return (SqmPredicate) restriction.toPredicate( root, sqmStatement.nodeBuilder() );