Skip to content

Commit 8dc6b85

Browse files
robwgreenjrbeikov
authored andcommitted
HHH-18871 allow collections to be mapped correctly while determining navigation path
1 parent a6e9cb7 commit 8dc6b85

File tree

2 files changed

+115
-3
lines changed

2 files changed

+115
-3
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.hibernate.LockMode;
1717
import org.hibernate.engine.spi.SessionFactoryImplementor;
1818
import org.hibernate.loader.internal.AliasConstantsHelper;
19+
import org.hibernate.metamodel.mapping.CollectionPart;
1920
import org.hibernate.metamodel.mapping.EntityMappingType;
2021
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
2122
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
@@ -260,16 +261,19 @@ private List<String> columnNames(
260261

261262
private NavigablePath determineNavigablePath(LegacyFetchBuilder fetchBuilder) {
262263
final var ownerResult = alias2Return.get( fetchBuilder.getOwnerAlias() );
263-
final NavigablePath path;
264+
final NavigablePath basePath;
264265
if ( ownerResult instanceof NativeQuery.RootReturn rootReturn ) {
265-
path = rootReturn.getNavigablePath();
266+
basePath = rootReturn.getNavigablePath();
266267
}
267268
else if ( ownerResult instanceof DynamicFetchBuilderLegacy dynamicFetchBuilderLegacy ) {
268-
path = determineNavigablePath( dynamicFetchBuilderLegacy );
269+
basePath = determineNavigablePath( dynamicFetchBuilderLegacy );
269270
}
270271
else {
271272
throw new AssertionFailure( "Unexpected fetch builder" );
272273
}
274+
final NavigablePath path = alias2CollectionPersister.containsKey( fetchBuilder.getOwnerAlias() )
275+
? basePath.append( CollectionPart.Nature.ELEMENT.getName() )
276+
: basePath;
273277
return path.append( fetchBuilder.getFetchable().getFetchableName() );
274278
}
275279

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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.CascadeType;
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.FetchType;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.JoinColumn;
13+
import jakarta.persistence.ManyToOne;
14+
import jakarta.persistence.OneToMany;
15+
import jakarta.persistence.Table;
16+
import org.hibernate.testing.orm.junit.DomainModel;
17+
import org.hibernate.testing.orm.junit.Jira;
18+
import org.hibernate.testing.orm.junit.SessionFactory;
19+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
20+
import org.junit.jupiter.api.Test;
21+
22+
import java.util.HashSet;
23+
import java.util.Set;
24+
25+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
26+
27+
/**
28+
* This reproduces an issue in Hibernate 6 parsing native queries.
29+
*/
30+
@DomainModel(
31+
annotatedClasses = {
32+
NativeQueryNestedTreeTest.Tree.class,
33+
NativeQueryNestedTreeTest.Forest.class
34+
}
35+
)
36+
@SessionFactory
37+
@Jira("https://hibernate.atlassian.net/browse/HHH-18871")
38+
public class NativeQueryNestedTreeTest {
39+
40+
@Test
41+
public void test(SessionFactoryScope scope) {
42+
// We want to make sure 'Could not locate TableGroup' no longer is thrown
43+
assertDoesNotThrow( () -> scope.inTransaction( session ->
44+
session.createNativeQuery( """
45+
select {t.*}, {t2.*}, {t3.*}
46+
from tree t
47+
inner join tree t2 on t2.parent_id = t.id
48+
inner join tree t3 on t3.parent_id = t2.id
49+
""", Tree.class )
50+
.addEntity( "t", Tree.class )
51+
.addJoin( "t2", "t.children" )
52+
.addJoin( "t3", "t2.children" )
53+
.list()
54+
) );
55+
56+
assertDoesNotThrow( () -> scope.inTransaction( session ->
57+
session.createNativeQuery( """
58+
select {t.*}, {t2.*}, {t3.*}, {t4.*}
59+
from tree t
60+
inner join tree t2 on t2.parent_id = t.id
61+
inner join tree t3 on t3.parent_id = t2.id
62+
inner join tree t4 on t4.parent_id = t3.id
63+
""", Tree.class )
64+
.addEntity( "t", Tree.class )
65+
.addJoin( "t2", "t.children" )
66+
.addJoin( "t3", "t2.children" )
67+
.addJoin( "t4", "t3.children" )
68+
.list()
69+
) );
70+
71+
assertDoesNotThrow( () -> scope.inTransaction( session ->
72+
session.createNativeQuery( """
73+
select {f.*}, {t.*}, {t2.*}
74+
from forest f
75+
inner join tree t on t.parent_id is null
76+
inner join tree t2 on t2.parent_id = t.id
77+
""", Forest.class )
78+
.addEntity( "f", Forest.class )
79+
.addJoin( "t", "f.trees" )
80+
.addJoin( "t2", "t.children" )
81+
.list()
82+
) );
83+
}
84+
85+
@Entity(name = "Tree")
86+
@Table(name = "tree")
87+
public static class Tree {
88+
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
89+
@JoinColumn(name = "parent_id")
90+
private Tree parent;
91+
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
92+
private Set<Tree> children = new HashSet<>();
93+
@Id
94+
@GeneratedValue
95+
private long id;
96+
}
97+
98+
@Entity(name = "Forest")
99+
@Table(name = "forest")
100+
public static class Forest {
101+
@Id
102+
@GeneratedValue
103+
private Long id;
104+
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
105+
@JoinColumn(name = "forest_id")
106+
private Set<Tree> trees = new HashSet<>();
107+
}
108+
}

0 commit comments

Comments
 (0)