Skip to content

Commit fc645d7

Browse files
committed
HHH-18871 allow collections to be mapped correctly while determining navigation path
1 parent f36b06c commit fc645d7

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ private List<String> columnNames(
260260

261261
private NavigablePath determineNavigablePath(LegacyFetchBuilder fetchBuilder) {
262262
final var ownerResult = alias2Return.get( fetchBuilder.getOwnerAlias() );
263-
final NavigablePath path;
263+
NavigablePath path;
264264
if ( ownerResult instanceof NativeQuery.RootReturn rootReturn ) {
265265
path = rootReturn.getNavigablePath();
266266
}
@@ -270,6 +270,9 @@ else if ( ownerResult instanceof DynamicFetchBuilderLegacy dynamicFetchBuilderLe
270270
else {
271271
throw new AssertionFailure( "Unexpected fetch builder" );
272272
}
273+
if ( alias2CollectionPersister.containsKey( fetchBuilder.getOwnerAlias() ) ) {
274+
path = path.append( "{element}" );
275+
}
273276
return path.append( fetchBuilder.getFetchable().getFetchableName() );
274277
}
275278

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.query;
6+
7+
import jakarta.persistence.*;
8+
import org.hibernate.cfg.AvailableSettings;
9+
import org.hibernate.testing.orm.junit.*;
10+
import org.junit.jupiter.api.Test;
11+
12+
import java.util.HashSet;
13+
import java.util.Set;
14+
15+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
16+
17+
/**
18+
* This reproduces an issue in Hibernate 6 parsing native queries.
19+
*/
20+
@DomainModel(
21+
annotatedClasses = {
22+
NativeQueryNestedTree.Tree.class,
23+
NativeQueryNestedTree.Forest.class
24+
}
25+
)
26+
@ServiceRegistry(
27+
settings = {
28+
@Setting(name = AvailableSettings.SHOW_SQL, value = "true"),
29+
@Setting(name = AvailableSettings.HBM2DDL_AUTO, value = "create")
30+
}
31+
)
32+
@SessionFactory
33+
@JiraKey(value = "HHH-18871")
34+
public class NativeQueryNestedTree {
35+
36+
@Test
37+
public void test(SessionFactoryScope scope) {
38+
// We want to make sure 'Could not locate TableGroup' no longer is thrown
39+
assertDoesNotThrow( () -> scope.inTransaction( session ->
40+
session.createNativeQuery( """
41+
SELECT {t.*}, {t2.*}, {t3.*}
42+
FROM TREE t
43+
INNER JOIN tree t2 ON t2.parent_id = t.id
44+
INNER JOIN tree t3 ON t3.parent_id = t2.id
45+
""" )
46+
.addEntity( "t", Tree.class )
47+
.addJoin( "t2", "t.children" )
48+
.addJoin( "t3", "t2.children" )
49+
.list()
50+
) );
51+
52+
assertDoesNotThrow( () -> scope.inTransaction( session ->
53+
session.createNativeQuery("""
54+
SELECT {t.*}, {t2.*}, {t3.*}, {t4.*}
55+
FROM tree t
56+
INNER JOIN tree t2 ON t2.parent_id = t.id
57+
INNER JOIN tree t3 ON t3.parent_id = t2.id
58+
INNER JOIN tree t4 ON t4.parent_id = t3.id
59+
""")
60+
.addEntity("t", Tree.class)
61+
.addJoin("t2", "t.children")
62+
.addJoin("t3", "t2.children")
63+
.addJoin("t4", "t3.children")
64+
.list()
65+
) );
66+
67+
assertDoesNotThrow( () -> scope.inTransaction( session ->
68+
session.createNativeQuery("""
69+
SELECT {f.*}, {t.*}, {t2.*}
70+
FROM forest f
71+
INNER JOIN tree t ON t.parent_id IS NULL
72+
INNER JOIN tree t2 ON t2.parent_id = t.id
73+
""")
74+
.addEntity("f", Forest.class)
75+
.addJoin("t", "f.trees")
76+
.addJoin("t2", "t.children")
77+
.list()
78+
) );
79+
}
80+
81+
@Entity(name = "Tree")
82+
@Table(name = "tree")
83+
public static class Tree {
84+
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
85+
@JoinColumn(name = "parent_id")
86+
private Tree parent;
87+
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
88+
private Set<Tree> children = new HashSet<>();
89+
@Id
90+
@GeneratedValue
91+
private long id;
92+
}
93+
94+
@Entity(name = "Forest")
95+
@Table(name = "forest")
96+
public static class Forest {
97+
@Id
98+
@GeneratedValue
99+
private Long id;
100+
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
101+
@JoinColumn(name = "forest_id")
102+
private Set<Tree> trees = new HashSet<>();
103+
}
104+
}

0 commit comments

Comments
 (0)