Skip to content

Commit e5c2197

Browse files
mira-silhavydreab8
authored andcommitted
HHH-19387 - Fix concrete descriptor when left join returns null in a cached query
1 parent cfb1d76 commit e5c2197

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,10 @@ public void resolveState(EntityInitializerData data) {
16341634
castNonNull( discriminatorAssembler ),
16351635
entityDescriptor
16361636
);
1637+
if (data.concreteDescriptor == null) {
1638+
// Return because the value is null
1639+
return;
1640+
}
16371641
}
16381642
}
16391643
resolveEntityState( data );
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.querycache;
6+
7+
import java.util.Arrays;
8+
import java.util.List;
9+
import java.util.Set;
10+
11+
import org.hibernate.annotations.JdbcTypeCode;
12+
import org.hibernate.type.SqlTypes;
13+
14+
import org.hibernate.testing.orm.junit.DomainModel;
15+
import org.hibernate.testing.orm.junit.Jira;
16+
import org.hibernate.testing.orm.junit.SessionFactory;
17+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
18+
import org.junit.jupiter.api.AfterAll;
19+
import org.junit.jupiter.api.BeforeAll;
20+
import org.junit.jupiter.api.Test;
21+
22+
import jakarta.persistence.Access;
23+
import jakarta.persistence.Column;
24+
import jakarta.persistence.DiscriminatorColumn;
25+
import jakarta.persistence.DiscriminatorValue;
26+
import jakarta.persistence.Entity;
27+
import jakarta.persistence.Enumerated;
28+
import jakarta.persistence.FetchType;
29+
import jakarta.persistence.GeneratedValue;
30+
import jakarta.persistence.Id;
31+
import jakarta.persistence.JoinColumn;
32+
import jakarta.persistence.JoinTable;
33+
import jakarta.persistence.ManyToMany;
34+
35+
import static jakarta.persistence.AccessType.FIELD;
36+
import static jakarta.persistence.EnumType.STRING;
37+
import static org.assertj.core.api.Assertions.assertThat;
38+
39+
/**
40+
* @author miroslav silhavy
41+
*/
42+
@DomainModel(annotatedClasses = {
43+
EntityWithCollectionReloadCacheInheritanceTest.HighSchoolStudent.class,
44+
EntityWithCollectionReloadCacheInheritanceTest.DefaultSubject.class,
45+
EntityWithCollectionReloadCacheInheritanceTest.EnglishSubject.class
46+
})
47+
@SessionFactory
48+
@Jira("https://hibernate.atlassian.net/browse/HHH-19387")
49+
public class EntityWithCollectionReloadCacheInheritanceTest {
50+
51+
@Test
52+
public void test(SessionFactoryScope scope) {
53+
scope.inTransaction( session -> {
54+
List<HighSchoolStudent> list = session.createQuery(
55+
"select s" +
56+
" from HighSchoolStudent s left join fetch s.subjects m" +
57+
" where s.name in :names", HighSchoolStudent.class
58+
)
59+
.setParameter( "names", Arrays.asList( "Brian" ) )
60+
.setCacheable( true )
61+
.list();
62+
63+
assertThat( list ).hasSize( 1 );
64+
65+
list = session.createQuery(
66+
"select s" +
67+
" from HighSchoolStudent s left join fetch s.subjects m" +
68+
" where s.name in :names", HighSchoolStudent.class
69+
)
70+
.setParameter( "names", Arrays.asList( "Andrew", "Brian" ) )
71+
.setCacheable( true )
72+
.list();
73+
74+
assertThat( list ).hasSize( 2 );
75+
} );
76+
}
77+
78+
@BeforeAll
79+
public void setUp(SessionFactoryScope scope) {
80+
scope.inTransaction( session -> {
81+
HighSchoolStudent s1 = new HighSchoolStudent();
82+
s1.setName( "Andrew" );
83+
session.persist( s1 );
84+
85+
HighSchoolStudent s2 = new HighSchoolStudent();
86+
s2.setName( "Brian" );
87+
session.persist( s2 );
88+
} );
89+
}
90+
91+
@AfterAll
92+
public void tearDown(SessionFactoryScope scope) {
93+
scope.getSessionFactory().getSchemaManager().truncateMappedObjects();
94+
}
95+
96+
@Entity(name = "HighSchoolStudent")
97+
@Access(FIELD)
98+
static class HighSchoolStudent {
99+
100+
@Id
101+
@GeneratedValue
102+
@Column(name = "id")
103+
private Long id;
104+
105+
@Column(name = "name")
106+
private String name;
107+
108+
@ManyToMany(targetEntity = DefaultSubject.class, fetch = FetchType.LAZY)
109+
@JoinTable(name = "STUDENT_SUBJECT",
110+
joinColumns = { @JoinColumn(name = "student_id") },
111+
inverseJoinColumns = { @JoinColumn(name = "subject_id") }
112+
)
113+
private Set<DefaultSubject> subjects;
114+
115+
public Long getId() {
116+
return id;
117+
}
118+
119+
public void setId(Long id) {
120+
this.id = id;
121+
}
122+
123+
public String getName() {
124+
return name;
125+
}
126+
127+
public void setName(String name) {
128+
this.name = name;
129+
}
130+
131+
public Set<DefaultSubject> getSubjects() {
132+
return subjects;
133+
}
134+
135+
public void setMajors(Set<DefaultSubject> subjects) {
136+
this.subjects = subjects;
137+
}
138+
139+
}
140+
141+
@Entity(name = "DefaultSubject")
142+
@DiscriminatorValue("DEFAULT")
143+
@DiscriminatorColumn(name = "TYPE", length = 20)
144+
@Access(FIELD)
145+
static class DefaultSubject {
146+
147+
enum SubjectType {
148+
DEFAULT,
149+
ENGLISH
150+
}
151+
152+
@Column(name = "TYPE", nullable = false, length = 20, insertable = false, updatable = false)
153+
@Enumerated(STRING)
154+
@JdbcTypeCode(SqlTypes.VARCHAR)
155+
private SubjectType type;
156+
157+
@Id
158+
@GeneratedValue
159+
@Column(name = "id")
160+
private Long id;
161+
162+
public Long getId() {
163+
return id;
164+
}
165+
166+
public void setId(Long id) {
167+
this.id = id;
168+
}
169+
170+
}
171+
172+
@Entity(name = "EnglishSubject")
173+
@DiscriminatorValue("ENGLISH")
174+
@Access(FIELD)
175+
static class EnglishSubject extends DefaultSubject {
176+
}
177+
178+
}

0 commit comments

Comments
 (0)