Skip to content

Commit e60a076

Browse files
committed
HHH-19364 move to a fully-detached model
1 parent 7a7ed30 commit e60a076

File tree

9 files changed

+158
-173
lines changed

9 files changed

+158
-173
lines changed

hibernate-core/src/main/java/org/hibernate/query/programmatic/MutationSpecification.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@
44
*/
55
package org.hibernate.query.programmatic;
66

7-
import jakarta.persistence.EntityManagerFactory;
8-
import jakarta.persistence.criteria.Root;
97
import jakarta.persistence.criteria.CriteriaUpdate;
108
import jakarta.persistence.criteria.CriteriaDelete;
119
import org.hibernate.Incubating;
1210
import org.hibernate.SharedSessionContract;
13-
import org.hibernate.engine.spi.SessionFactoryImplementor;
1411
import org.hibernate.query.IllegalMutationQueryException;
1512
import org.hibernate.query.MutationQuery;
1613
import org.hibernate.query.SelectionQuery;
@@ -27,7 +24,7 @@
2724
* kinds.
2825
* <p>
2926
* Once all {@linkplain #addRestriction restrictions} are specified, call
30-
* {@linkplain QuerySpecification#createQuery(SharedSessionContract)} to obtain an {@linkplain SelectionQuery an
27+
* {@link #createQuery createQuery()} to obtain an {@linkplain SelectionQuery
3128
* executable mutation query object}.
3229
*
3330
* @param <T> The entity type which is the target of the mutation.
@@ -38,12 +35,6 @@
3835
*/
3936
@Incubating
4037
public interface MutationSpecification<T> extends QuerySpecification<T> {
41-
/**
42-
* The entity being mutated.
43-
*/
44-
default Root<T> getMutationTarget() {
45-
return getRoot();
46-
}
4738

4839
/**
4940
* Covariant override.
@@ -71,8 +62,8 @@ default Root<T> getMutationTarget() {
7162
* @throws IllegalMutationQueryException Only {@code update} and {@code delete} are supported;
7263
* this method will throw an exception if the given HQL query is not an {@code update} or {@code delete}.
7364
*/
74-
static <T> MutationSpecification<T> create(EntityManagerFactory factory, Class<T> entityClass, String hql) {
75-
return new MutationSpecificationImpl<>( hql, entityClass, (SessionFactoryImplementor) factory );
65+
static <T> MutationSpecification<T> create(Class<T> mutationTarget, String hql) {
66+
return new MutationSpecificationImpl<>( hql, mutationTarget );
7667
}
7768

7869
/**

hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,27 @@
44
*/
55
package org.hibernate.query.programmatic;
66

7-
import jakarta.persistence.criteria.CommonAbstractCriteria;
8-
import jakarta.persistence.criteria.Root;
97
import org.hibernate.Incubating;
8+
import org.hibernate.SessionFactory;
109
import org.hibernate.SharedSessionContract;
10+
import org.hibernate.engine.spi.SessionFactoryImplementor;
1111
import org.hibernate.query.CommonQueryContract;
1212
import org.hibernate.query.restriction.Restriction;
1313

1414
/**
1515
* Commonality for all query specifications which allow iterative,
1616
* programmatic building of a query.
1717
*
18-
* @apiNote Query specifications only support a {@linkplain #getRoot() single root}.
18+
* @apiNote Query specifications only support a single root entity.
19+
*
20+
* @param <T> The root entity type.
1921
*
2022
* @author Steve Ebersole
2123
*
2224
* @since 7.0
2325
*/
2426
@Incubating
2527
public interface QuerySpecification<T> {
26-
/**
27-
* Get the root of the query.
28-
* E.g. given the HQL {@code "from Book"}, we have a single {@code Root<Book>}.
29-
*/
30-
Root<T> getRoot();
31-
32-
/**
33-
* Access to the criteria query which QuerySpecification is
34-
* managing and manipulating internally.
35-
* While it is allowable to directly mutate this tree, users
36-
* should instead prefer to manipulate the tree through the
37-
* methods exposed on the specification itself.
38-
*/
39-
CommonAbstractCriteria getCriteria();
4028

4129
/**
4230
* Adds a restriction to the query specification.
@@ -51,4 +39,16 @@ public interface QuerySpecification<T> {
5139
* Finalize the building and create executable query instance.
5240
*/
5341
CommonQueryContract createQuery(SharedSessionContract session);
42+
43+
/**
44+
* Validate the query.
45+
*/
46+
default void validate(SessionFactory factory) {
47+
// Extremely temporary implementation.
48+
// We don't actually want to open a session here,
49+
// nor create an instance of CommonQueryContract.
50+
try ( var session = ((SessionFactoryImplementor) factory).openTemporarySession() ) {
51+
createQuery( session );
52+
}
53+
}
5454
}

hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@
44
*/
55
package org.hibernate.query.programmatic;
66

7-
import jakarta.persistence.EntityManagerFactory;
87
import jakarta.persistence.criteria.CriteriaQuery;
98
import org.hibernate.Incubating;
109
import org.hibernate.SharedSessionContract;
11-
import org.hibernate.engine.spi.SessionFactoryImplementor;
1210
import org.hibernate.query.IllegalSelectQueryException;
1311
import org.hibernate.query.Order;
14-
import org.hibernate.query.QueryProducer;
1512
import org.hibernate.query.SelectionQuery;
1613
import org.hibernate.query.programmatic.internal.SelectionSpecificationImpl;
1714
import org.hibernate.query.restriction.Restriction;
@@ -31,11 +28,10 @@
3128
* </ul>
3229
* <p>
3330
* Once all {@linkplain #addOrdering sorting} and {@linkplain #addRestriction restrictions}
34-
* are specified, call {@linkplain QuerySpecification#createQuery(SharedSessionContract)} to obtain an {@linkplain SelectionQuery
35-
* executable selection query object}.
31+
* are specified, call {@link #createQuery createQuery()} to obtain an
32+
* {@linkplain SelectionQuery executable selection query object}.
3633
* <pre>
37-
* SelectionSpecification.create(factory, Book.class,
38-
* "from Book where discontinued = false")
34+
* SelectionSpecification.create(Book.class, "from Book where discontinued = false")
3935
* .addRestriction(Restriction.contains(Book_.title, "hibernate", false))
4036
* .setOrdering(Order.desc(Book_.title))
4137
* .createQuery(session) // obtain a SelectionQuery
@@ -49,8 +45,6 @@
4945
*
5046
* @param <T> The entity type returned by the query
5147
*
52-
* @see QueryProducer#createSelectionSpecification(String, Class)
53-
*
5448
* @author Steve Ebersole
5549
*
5650
* @since 7.0
@@ -89,12 +83,6 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
8983
*/
9084
SelectionSpecification<T> setOrdering(List<Order<T>> orders);
9185

92-
/**
93-
* Covariant override.
94-
*/
95-
@Override
96-
CriteriaQuery<T> getCriteria();
97-
9886
/**
9987
* Covariant override.
10088
*/
@@ -112,20 +100,16 @@ public interface SelectionSpecification<T> extends QuerySpecification<T> {
112100
* iteratively build a {@linkplain SelectionQuery} for the given entity type,
113101
* allowing the addition of {@linkplain SelectionSpecification#addOrdering sorting}
114102
* and {@linkplain SelectionSpecification#addRestriction restrictions}.
115-
* This is effectively the same as calling {@linkplain QueryProducer#createSelectionSpecification(String, Class)}
103+
* This is effectively the same as calling {@linkplain #create(Class, String)}
116104
* with {@code "from {rootEntityType}"} as the HQL.
117105
*
118106
* @param rootEntityType The entity type which is the root of the query.
119107
*
120108
* @param <T> The entity type which is the root of the query.
121109
* {@code resultType} and {@code <T>} are both expected to refer to a singular query root.
122110
*/
123-
static <T> SelectionSpecification<T> create(EntityManagerFactory factory, Class<T> rootEntityType) {
124-
var builder = factory.getCriteriaBuilder();
125-
var query = builder.createQuery( rootEntityType );
126-
var root = query.from( rootEntityType );
127-
query.select( root );
128-
return new SelectionSpecificationImpl<>( query );
111+
static <T> SelectionSpecification<T> create(Class<T> rootEntityType) {
112+
return new SelectionSpecificationImpl<>( rootEntityType );
129113
}
130114

131115
/**
@@ -143,8 +127,8 @@ static <T> SelectionSpecification<T> create(EntityManagerFactory factory, Class<
143127
* @throws IllegalSelectQueryException The given HQL is expected to be a {@code select} query. This method will
144128
* throw an exception if not.
145129
*/
146-
static <T> SelectionSpecification<T> create(EntityManagerFactory factory, Class<T> resultType, String hql) {
147-
return new SelectionSpecificationImpl<>( hql, resultType, (SessionFactoryImplementor) factory );
130+
static <T> SelectionSpecification<T> create(Class<T> resultType, String hql) {
131+
return new SelectionSpecificationImpl<>( hql, resultType );
148132
}
149133

150134
/**

hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
*/
55
package org.hibernate.query.programmatic.internal;
66

7-
import jakarta.persistence.criteria.CommonAbstractCriteria;
87
import jakarta.persistence.criteria.CriteriaDelete;
98
import jakarta.persistence.criteria.CriteriaUpdate;
10-
import jakarta.persistence.criteria.Root;
9+
import org.hibernate.AssertionFailure;
1110
import org.hibernate.SharedSessionContract;
12-
import org.hibernate.engine.spi.SessionFactoryImplementor;
1311
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1412
import org.hibernate.query.programmatic.MutationSpecification;
1513
import org.hibernate.query.IllegalMutationQueryException;
@@ -26,7 +24,10 @@
2624
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
2725
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
2826

27+
import java.util.ArrayList;
28+
import java.util.List;
2929
import java.util.Locale;
30+
import java.util.function.BiConsumer;
3031

3132
import static org.hibernate.query.sqm.tree.SqmCopyContext.noParamCopyContext;
3233

@@ -37,54 +38,60 @@
3738
*/
3839
public class MutationSpecificationImpl<T> implements MutationSpecification<T> {
3940

40-
private final SqmDeleteOrUpdateStatement<T> sqmStatement;
41-
private final SqmRoot<T> mutationTargetRoot;
41+
private final List<BiConsumer<SqmDeleteOrUpdateStatement<T>, SqmRoot<T>>> specifications = new ArrayList<>();
42+
private final String hql;
43+
private final Class<T> mutationTarget;
44+
private final SqmDeleteOrUpdateStatement<T> deleteOrUpdateStatement;
4245

43-
public MutationSpecificationImpl(
44-
String hql,
45-
Class<T> mutationTarget,
46-
SessionFactoryImplementor factory) {
47-
this.sqmStatement = resolveSqmTree( hql, factory.getQueryEngine() );
48-
this.mutationTargetRoot = resolveSqmRoot( this.sqmStatement, mutationTarget );
46+
public MutationSpecificationImpl(String hql, Class<T> mutationTarget) {
47+
this.hql = hql;
48+
this.mutationTarget = mutationTarget;
49+
this.deleteOrUpdateStatement = null;
4950
}
5051

5152
public MutationSpecificationImpl(CriteriaUpdate<T> criteriaQuery) {
52-
this.sqmStatement = (SqmUpdateStatement<T>) criteriaQuery;
53-
this.mutationTargetRoot = resolveSqmRoot( sqmStatement,
54-
sqmStatement.getTarget().getManagedType().getJavaType() );
53+
this.deleteOrUpdateStatement = (SqmUpdateStatement<T>) criteriaQuery;
54+
this.mutationTarget = deleteOrUpdateStatement.getTarget().getManagedType().getJavaType();
55+
this.hql = null;
5556
}
5657

5758
public MutationSpecificationImpl(CriteriaDelete<T> criteriaQuery) {
58-
this.sqmStatement = (SqmDeleteStatement<T>) criteriaQuery;
59-
this.mutationTargetRoot = resolveSqmRoot( sqmStatement,
60-
sqmStatement.getTarget().getManagedType().getJavaType() );
61-
}
62-
63-
@Override
64-
public Root<T> getRoot() {
65-
return mutationTargetRoot;
66-
}
67-
68-
@Override
69-
public CommonAbstractCriteria getCriteria() {
70-
return sqmStatement;
59+
this.deleteOrUpdateStatement = (SqmDeleteStatement<T>) criteriaQuery;
60+
this.mutationTarget = deleteOrUpdateStatement.getTarget().getManagedType().getJavaType();
61+
this.hql = null;
7162
}
7263

7364
@Override
7465
public MutationSpecification<T> addRestriction(Restriction<T> restriction) {
75-
final SqmPredicate sqmPredicate = (SqmPredicate) restriction.toPredicate(
76-
mutationTargetRoot,
77-
sqmStatement.nodeBuilder()
78-
);
79-
sqmStatement.applyPredicate( sqmPredicate );
80-
66+
specifications.add( (sqmStatement, mutationTargetRoot) -> {
67+
final SqmPredicate sqmPredicate = (SqmPredicate) restriction.toPredicate(
68+
mutationTargetRoot,
69+
sqmStatement.nodeBuilder()
70+
);
71+
sqmStatement.applyPredicate( sqmPredicate );
72+
} );
8173
return this;
8274
}
8375

8476
@Override
8577
public MutationQuery createQuery(SharedSessionContract session) {
86-
return new QuerySqmImpl<>( sqmStatement, true, null,
87-
(SharedSessionContractImplementor) session );
78+
final var sessionImpl = (SharedSessionContractImplementor) session;
79+
final SqmDeleteOrUpdateStatement<T> sqmStatement;
80+
final SqmRoot<T> mutationTargetRoot;
81+
if ( hql != null ) {
82+
sqmStatement = resolveSqmTree( hql, sessionImpl.getFactory().getQueryEngine() );
83+
mutationTargetRoot = resolveSqmRoot( sqmStatement, mutationTarget );
84+
}
85+
else if ( deleteOrUpdateStatement != null ) {
86+
sqmStatement = deleteOrUpdateStatement;
87+
mutationTargetRoot = resolveSqmRoot( sqmStatement,
88+
sqmStatement.getTarget().getManagedType().getJavaType() );
89+
}
90+
else {
91+
throw new AssertionFailure( "No HQL or criteria" );
92+
}
93+
specifications.forEach( consumer -> consumer.accept( sqmStatement, mutationTargetRoot ) );
94+
return new QuerySqmImpl<>( sqmStatement, true, null, sessionImpl );
8895
}
8996

9097
/**

0 commit comments

Comments
 (0)