Skip to content

Commit 2ed4355

Browse files
committed
HHH-19096 Adjust SelectionQuery#setEntityGraph(..) to accept entity graphs of supertypes
1 parent ca1d66f commit 2ed4355

File tree

10 files changed

+143
-9
lines changed

10 files changed

+143
-9
lines changed

hibernate-core/src/main/java/org/hibernate/Session.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,8 @@ public interface Session extends SharedSessionContract, EntityManager {
13111311
* @apiNote This method returns {@code RootGraph<?>}, requiring an
13121312
* unchecked typecast before use. It's cleaner to obtain a graph using
13131313
* the static metamodel for the class which defines the graph, or by
1314-
* calling {@link SessionFactory#getNamedEntityGraphs(Class)} instead.
1314+
* calling either {@link SessionFactory#getNamedEntityGraphs(Class)}
1315+
* or {@link org.hibernate.query.SelectionQuery#getNamedEntityGraph(String)} instead.
13151316
*
13161317
* @see #find(EntityGraph, Object, FindOption...)
13171318
* @see org.hibernate.query.SelectionQuery#setEntityGraph(EntityGraph, org.hibernate.graph.GraphSemantic)

hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Set;
2020
import java.util.stream.Stream;
2121

22+
import jakarta.persistence.EntityGraph;
2223
import org.hibernate.HibernateException;
2324
import org.hibernate.LockMode;
2425
import org.hibernate.LockOptions;
@@ -839,6 +840,10 @@ public Query<R> applyGraph(@SuppressWarnings("rawtypes") RootGraph graph, GraphS
839840
throw new IllegalStateException( "EntityGraph hints are not supported for ProcedureCall/StoredProcedureQuery" );
840841
}
841842

843+
@Override
844+
public EntityGraph<? super R> getNamedEntityGraph(String graphName) {
845+
throw new IllegalStateException( "EntityGraph hints are not supported for ProcedureCall/StoredProcedureQuery" );
846+
}
842847

843848
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
844849
// outputs

hibernate-core/src/main/java/org/hibernate/query/Query.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ default Query<R> setPage(Page page) {
922922
Query<R> setHint(String hintName, Object value);
923923

924924
@Override
925-
Query<R> setEntityGraph(EntityGraph<R> graph, GraphSemantic semantic);
925+
Query<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic);
926926

927927
@Override
928928
Query<R> enableFetchProfile(String profileName);

hibernate-core/src/main/java/org/hibernate/query/SelectionQuery.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,20 @@ default Stream<R> stream() {
291291
*
292292
* @since 6.3
293293
*/
294-
SelectionQuery<R> setEntityGraph(EntityGraph<R> graph, GraphSemantic semantic);
294+
SelectionQuery<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic);
295+
296+
/**
297+
* Obtain an immutable reference to a predefined
298+
* {@linkplain jakarta.persistence.NamedEntityGraph named entity graph}
299+
* or return {@code null} if there is no predefined graph with the given
300+
* name.
301+
*
302+
* @param graphName The name of the predefined named entity graph
303+
*
304+
* @since 7.0
305+
*/
306+
@Incubating
307+
EntityGraph<? super R> getNamedEntityGraph(String graphName);
295308

296309
/**
297310
* Enable the {@link org.hibernate.annotations.FetchProfile fetch profile}

hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public QueryImplementor<R> setHint(String hintName, Object value) {
129129
}
130130

131131
@Override
132-
public QueryImplementor<R> setEntityGraph(EntityGraph<R> graph, GraphSemantic semantic) {
132+
public QueryImplementor<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic) {
133133
super.setEntityGraph( graph, semantic );
134134
return this;
135135
}

hibernate-core/src/main/java/org/hibernate/query/spi/AbstractSelectionQuery.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,23 @@ public SelectionQuery<R> setHint(String hintName, Object value) {
374374
}
375375

376376
@Override
377-
public SelectionQuery<R> setEntityGraph(EntityGraph<R> graph, GraphSemantic semantic) {
378-
applyGraph( (RootGraphImplementor<R>) graph, semantic );
377+
public SelectionQuery<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic) {
378+
applyGraph( (RootGraphImplementor<? super R>) graph, semantic );
379379
return this;
380380
}
381381

382+
@SuppressWarnings("unchecked")
383+
@Override
384+
public EntityGraph<? super R> getNamedEntityGraph(String graphName) {
385+
for ( EntityGraph<? super R> graph : getSession().getSessionFactory()
386+
.findEntityGraphsByType( (Class<R>) getResultType() ) ) {
387+
if ( graph.getName().equals( graphName ) ) {
388+
return graph;
389+
}
390+
}
391+
return null;
392+
}
393+
382394
@Override
383395
public SelectionQuery<R> enableFetchProfile(String profileName) {
384396
if ( getSession().getFactory().containsFetchProfileDefinition( profileName ) ) {

hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.function.Consumer;
1919
import java.util.function.Supplier;
2020

21+
import jakarta.persistence.EntityGraph;
2122
import org.checkerframework.checker.nullness.qual.Nullable;
2223
import org.hibernate.CacheMode;
2324
import org.hibernate.FlushMode;
@@ -596,6 +597,11 @@ public Query<R> applyGraph(@SuppressWarnings("rawtypes") RootGraph graph, GraphS
596597
throw new HibernateException( "A native SQL query cannot use EntityGraphs" );
597598
}
598599

600+
@Override
601+
public EntityGraph<? super R> getNamedEntityGraph(String graphName) {
602+
throw new HibernateException( "A native SQL query cannot use EntityGraphs" );
603+
}
604+
599605
@Override
600606
protected void applyEntityGraphHint(String hintName, Object value) {
601607
super.applyEntityGraphHint( hintName, value );

hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ public SqmQueryImplementor<R> setHint(String hintName, Object value) {
811811
}
812812

813813
@Override
814-
public Query<R> setEntityGraph(EntityGraph<R> graph, GraphSemantic semantic) {
814+
public Query<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic) {
815815
super.setEntityGraph( graph, semantic );
816816
return this;
817817
}

hibernate-core/src/main/java/org/hibernate/query/sqm/spi/DelegatingSqmSelectionQueryImplementor.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,16 @@ public Optional<R> uniqueResultOptional() {
157157
}
158158

159159
@Override
160-
public SqmSelectionQueryImplementor<R> setEntityGraph(EntityGraph<R> graph, GraphSemantic semantic) {
160+
public SqmSelectionQueryImplementor<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic) {
161161
getDelegate().setEntityGraph( graph, semantic );
162162
return this;
163163
}
164164

165+
@Override
166+
public EntityGraph<? super R> getNamedEntityGraph(String graphName) {
167+
return getDelegate().getNamedEntityGraph( graphName );
168+
}
169+
165170
@Override
166171
public SqmSelectionQueryImplementor<R> enableFetchProfile(String profileName) {
167172
getDelegate().enableFetchProfile( profileName );

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/fetchprofile/NewGraphTest.java

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
import org.hibernate.annotations.NaturalId;
99
import org.hibernate.graph.GraphSemantic;
1010
import org.hibernate.graph.RootGraph;
11+
import org.hibernate.query.SelectionQuery;
1112
import org.hibernate.testing.orm.junit.DomainModel;
1213
import org.hibernate.testing.orm.junit.SessionFactory;
1314
import org.hibernate.testing.orm.junit.SessionFactoryScope;
1415
import org.junit.jupiter.api.Test;
1516

17+
import java.util.HashSet;
18+
import java.util.List;
1619
import java.util.Set;
1720

1821
import static jakarta.persistence.FetchType.LAZY;
@@ -21,7 +24,8 @@
2124
import static org.junit.jupiter.api.Assertions.assertTrue;
2225

2326
@SessionFactory
24-
@DomainModel(annotatedClasses = {NewGraphTest.class, NewGraphTest.E.class, NewGraphTest.F.class, NewGraphTest.G.class, NewGraphTest.H.class})
27+
@DomainModel(annotatedClasses = {NewGraphTest.class, NewGraphTest.E.class, NewGraphTest.F.class, NewGraphTest.G.class, NewGraphTest.H.class,
28+
NewGraphTest.A.class, NewGraphTest.Aa.class, NewGraphTest.B.class})
2529
public class NewGraphTest {
2630

2731
@Test void testByIdEntityGraph(SessionFactoryScope scope) {
@@ -168,6 +172,62 @@ public class NewGraphTest {
168172
assertTrue( isInitialized( ee.f ) );
169173
}
170174

175+
@Test
176+
void subTypeEntityGraph(SessionFactoryScope scope) {
177+
scope.inTransaction( s -> {
178+
A a = new A();
179+
Aa aa = new Aa();
180+
B b1 = new B();
181+
B b2 = new B();
182+
B b3 = new B();
183+
b1.a = a;
184+
a.bs = new HashSet<>();
185+
a.bs.add( b1 );
186+
187+
b2.a = aa;
188+
aa.bs = new HashSet<>();
189+
aa.bs.add( b2 );
190+
191+
b3.a = aa;
192+
aa.bss = new HashSet<>();
193+
aa.bss.add( b3 );
194+
195+
s.persist( a );
196+
s.persist( aa );
197+
s.persist( b1 );
198+
s.persist( b2 );
199+
s.persist( b3 );
200+
} );
201+
202+
A a = scope.fromSession( s ->
203+
s.createSelectionQuery( "from A", A.class )
204+
.setMaxResults( 1 )
205+
.getSingleResult() );
206+
assertFalse( isInitialized( a.bs ) );
207+
208+
List<Aa> as = scope.fromSession( s -> {
209+
SelectionQuery<Aa> query = s.createSelectionQuery( "from Aa", Aa.class );
210+
return query
211+
.setEntityGraph( query.getNamedEntityGraph( "a-graph" ), GraphSemantic.FETCH )
212+
.getResultList();
213+
} );
214+
for ( Aa el : as ) {
215+
assertTrue( isInitialized( el.bs ) );
216+
assertFalse( isInitialized( el.bss ) );
217+
}
218+
219+
as = scope.fromSession( s -> {
220+
SelectionQuery<Aa> query = s.createSelectionQuery( "from Aa", Aa.class );
221+
return query
222+
.setEntityGraph( query.getNamedEntityGraph( "aa-graph" ), GraphSemantic.FETCH )
223+
.getResultList();
224+
} );
225+
for ( Aa el : as ) {
226+
assertTrue( isInitialized( el.bs ) );
227+
assertTrue( isInitialized( el.bss ) );
228+
}
229+
}
230+
171231
@Entity(name = "E")
172232
static class E {
173233
@Id @GeneratedValue
@@ -199,4 +259,36 @@ static class H {
199259
Long id;
200260
@ManyToOne G g;
201261
}
262+
263+
@NamedEntityGraph(name = "a-graph", attributeNodes = {@NamedAttributeNode("bs"),})
264+
@Entity(name = "A")
265+
static class A {
266+
@Id @GeneratedValue
267+
Long id;
268+
269+
@OneToMany(mappedBy = "a")
270+
Set<B> bs;
271+
}
272+
273+
@NamedEntityGraph(name = "aa-graph", attributeNodes = {@NamedAttributeNode("bs"), @NamedAttributeNode("bss"),})
274+
@Entity(name = "Aa")
275+
static class Aa extends A {
276+
@Id @GeneratedValue
277+
Long id;
278+
279+
@OneToMany(mappedBy = "aa")
280+
Set<B> bss;
281+
}
282+
283+
@Entity(name = "B")
284+
static class B {
285+
@Id @GeneratedValue
286+
Long id;
287+
288+
@ManyToOne(fetch = LAZY)
289+
A a;
290+
291+
@ManyToOne(fetch = LAZY)
292+
Aa aa;
293+
}
202294
}

0 commit comments

Comments
 (0)