Skip to content

Commit 369c4ec

Browse files
committed
HHH-19550 Attribute join on correlated from node receives wrong root
1 parent 2b96643 commit 369c4ec

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelation.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@
1818
public interface SqmCorrelation<O, T> extends SqmFrom<O, T>, SqmPathWrapper<T, T> {
1919
SqmRoot<O> getCorrelatedRoot();
2020

21+
@Override
22+
default SqmRoot<?> findRoot() {
23+
return getCorrelatedRoot();
24+
}
2125
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.orm.test.jpa.criteria.subquery;
8+
9+
import jakarta.persistence.*;
10+
import org.hibernate.Session;
11+
import org.hibernate.query.criteria.*;
12+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
13+
import org.hibernate.testing.orm.junit.Jira;
14+
import org.hibernate.testing.orm.junit.Jpa;
15+
import org.junit.jupiter.api.Test;
16+
17+
import java.io.Serializable;
18+
19+
@Jpa( annotatedClasses = {
20+
AttributeJoinOnCorrelatedOrderedJoinTest.Primary.class,
21+
AttributeJoinOnCorrelatedOrderedJoinTest.Secondary.class,
22+
AttributeJoinOnCorrelatedOrderedJoinTest.Tertiary.class,
23+
} )
24+
@Jira( "https://hibernate.atlassian.net/browse/HHH-19550" )
25+
public class AttributeJoinOnCorrelatedOrderedJoinTest {
26+
27+
@Test
28+
public void test(EntityManagerFactoryScope scope) {
29+
scope.inTransaction( em -> {
30+
final HibernateCriteriaBuilder cb = em.unwrap( Session.class ).getCriteriaBuilder();
31+
final JpaCriteriaQuery<Tuple> query = cb.createTupleQuery();
32+
final JpaRoot<Primary> primary = query.from( Primary.class );
33+
// setup ordered joins
34+
final JpaEntityJoin<Primary> entityJoinedPrimary = primary.join( Primary.class );
35+
entityJoinedPrimary.on( primary.get( "id" ).equalTo( entityJoinedPrimary.get( "id" ) ) );
36+
// Need an attribute join to correlate
37+
final JpaJoin<?, Secondary> secondaryJoin = primary.join( "secondary" );
38+
39+
final JpaSubQuery<String> subquery = query.subquery( String.class );
40+
final JpaJoin<?, Secondary> correlatedSecondaryJoin = subquery.correlate( secondaryJoin );
41+
// The association join is being added to the result of getLhs().findRoot()
42+
// so if the correlated join returns a wrong node, this is messed up
43+
// and will produce an exception when copying the criteria tree
44+
final JpaJoin<?, Tertiary> tertiary = correlatedSecondaryJoin.join( "tertiary" );
45+
subquery.select( tertiary.get( "name" ) ).where( cb.equal(
46+
tertiary.get( "secondaryFk" ),
47+
correlatedSecondaryJoin.get( "id" )
48+
) );
49+
query.multiselect( primary.get( "id" ), secondaryJoin.get( "name" ), subquery );
50+
em.createQuery( query ).getResultList();
51+
} );
52+
}
53+
54+
@Entity( name = "PrimaryEntity" )
55+
public static class Primary implements Serializable {
56+
@Id
57+
private Integer id;
58+
59+
@ManyToOne(fetch = FetchType.LAZY)
60+
private Secondary secondary;
61+
62+
public Primary() {
63+
}
64+
}
65+
66+
@Entity( name = "SecondaryEntity" )
67+
public static class Secondary implements Serializable {
68+
@Id
69+
private Integer id;
70+
71+
private String name;
72+
@ManyToOne(fetch = FetchType.LAZY)
73+
private Tertiary tertiary;
74+
75+
public Secondary() {
76+
}
77+
78+
public Secondary(Integer id, String name) {
79+
this.id = id;
80+
this.name = name;
81+
}
82+
}
83+
84+
@Entity( name = "TertiaryEntity" )
85+
public static class Tertiary implements Serializable {
86+
@Id
87+
private Integer id;
88+
89+
private Integer secondaryFk;
90+
91+
private String name;
92+
93+
public Tertiary() {
94+
}
95+
96+
public Tertiary(Integer id, Integer secondaryFk, String name) {
97+
this.id = id;
98+
this.secondaryFk = secondaryFk;
99+
this.name = name;
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)