Skip to content

Commit ad5855f

Browse files
committed
HHH-13377 Add test for issue
1 parent 8d30649 commit ad5855f

File tree

1 file changed

+348
-0
lines changed

1 file changed

+348
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.bytecode.enhancement.refresh;
6+
7+
import jakarta.persistence.Basic;
8+
import jakarta.persistence.CascadeType;
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.FetchType;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.ManyToOne;
13+
import jakarta.persistence.OneToMany;
14+
import jakarta.persistence.Table;
15+
import org.hibernate.annotations.Formula;
16+
import org.hibernate.dialect.MariaDBDialect;
17+
import org.hibernate.dialect.MySQLDialect;
18+
import org.hibernate.dialect.SQLServerDialect;
19+
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
20+
import org.hibernate.testing.orm.junit.DomainModel;
21+
import org.hibernate.testing.orm.junit.Jira;
22+
import org.hibernate.testing.orm.junit.SessionFactory;
23+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
24+
import org.hibernate.testing.orm.junit.SkipForDialect;
25+
import org.hibernate.testing.orm.junit.SkipForDialectGroup;
26+
import org.junit.jupiter.api.AfterEach;
27+
import org.junit.jupiter.api.BeforeEach;
28+
import org.junit.jupiter.api.Test;
29+
30+
import java.util.HashSet;
31+
import java.util.Set;
32+
33+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
34+
35+
36+
@Jira("HHH-13377")
37+
@DomainModel(
38+
annotatedClasses = {
39+
RefreshEntityWithLazyPropertyTest.Person.class,
40+
RefreshEntityWithLazyPropertyTest.Course.class,
41+
RefreshEntityWithLazyPropertyTest.Position.class}
42+
)
43+
@SessionFactory
44+
@BytecodeEnhanced
45+
@SkipForDialectGroup(
46+
{
47+
@SkipForDialect( dialectClass = MySQLDialect.class, reason = "does not support || as String concatenation"),
48+
@SkipForDialect( dialectClass = MariaDBDialect.class, reason = "does not support || as String concatenation"),
49+
@SkipForDialect( dialectClass = SQLServerDialect.class, reason = "does not support || as String concatenation"),
50+
}
51+
)
52+
public class RefreshEntityWithLazyPropertyTest {
53+
54+
private static final Long PERSON_ID = 1L;
55+
private static final Long ASSISTANT_PROFESSOR_POSITION_ID = 1L;
56+
private static final Long PROFESSOR_POSITION_ID = 2L;
57+
private static final String ASSISTANT_POSITION_DESCRIPTION = "Assistant Professor";
58+
private static final String POSITION_DESCRIPTION = "Professor";
59+
private static final String PROFESSOR_FIRST_NAME = "John";
60+
private static final String PROFESSOR_LAST_NAME = "Doe";
61+
62+
@BeforeEach
63+
public void setUp(SessionFactoryScope scope) {
64+
scope.inTransaction( session -> {
65+
Position professorPosition = new Position( PROFESSOR_POSITION_ID, POSITION_DESCRIPTION );
66+
session.persist( professorPosition );
67+
68+
Position assistantProfessor = new Position( ASSISTANT_PROFESSOR_POSITION_ID,
69+
ASSISTANT_POSITION_DESCRIPTION );
70+
session.persist( assistantProfessor );
71+
72+
Person person = new Person( PERSON_ID, PROFESSOR_FIRST_NAME, PROFESSOR_LAST_NAME, assistantProfessor,
73+
professorPosition );
74+
session.persist( person );
75+
} );
76+
}
77+
78+
@AfterEach
79+
public void tearDown(SessionFactoryScope scope) {
80+
scope.inTransaction( session -> {
81+
session.createMutationQuery( "delete from Course" ).executeUpdate();
82+
session.createMutationQuery( "delete from Person" ).executeUpdate();
83+
session.createMutationQuery( "delete from Position" ).executeUpdate();
84+
} );
85+
}
86+
87+
@Test
88+
public void testRefreshOfLazyField(SessionFactoryScope scope) {
89+
scope.inTransaction( session -> {
90+
Person p = session.find( Person.class, PERSON_ID );
91+
assertThat( p.getLastName() ).isEqualTo( PROFESSOR_LAST_NAME );
92+
93+
String updatedLastName = "Johnson";
94+
session.createMutationQuery( "update Person p " +
95+
"set p.lastName = :lastName " +
96+
"where p.id = :id"
97+
)
98+
.setParameter( "lastName", updatedLastName )
99+
.setParameter( "id", PERSON_ID )
100+
.executeUpdate();
101+
102+
session.refresh( p );
103+
assertThat( p.getLastName() ).isEqualTo( updatedLastName );
104+
} );
105+
}
106+
107+
@Test
108+
public void testRefreshOfLazyFormula(SessionFactoryScope scope) {
109+
scope.inTransaction( session -> {
110+
Person p = session.find( Person.class, PERSON_ID );
111+
assertThat( p.getFullName() ).isEqualTo( "John Doe" );
112+
113+
p.setLastName( "Johnson" );
114+
session.flush();
115+
session.refresh( p );
116+
assertThat( p.getFullName() ).isEqualTo( "John Johnson" );
117+
} );
118+
}
119+
120+
@Test
121+
public void testRefreshOfLazyOneToMany(SessionFactoryScope scope) {
122+
scope.inTransaction( session -> {
123+
Person p = session.find( Person.class, PERSON_ID );
124+
assertThat( p.getCourses().size() ).isEqualTo( 0 );
125+
126+
session.createMutationQuery( "insert into Course (id, title, person) values (:id, :title, :person) " )
127+
.setParameter( "id", 0 )
128+
.setParameter( "title", "Book Title" )
129+
.setParameter( "person", p )
130+
.executeUpdate();
131+
132+
session.refresh( p );
133+
assertThat( p.getCourses().size() ).isEqualTo( 1 );
134+
} );
135+
}
136+
137+
@Test
138+
public void testRefreshOfLazyManyToOne(SessionFactoryScope scope) {
139+
scope.inTransaction( session -> {
140+
Person p = session.find( Person.class, PERSON_ID );
141+
assertThat( p.getPosition().id ).isEqualTo( ASSISTANT_PROFESSOR_POSITION_ID );
142+
143+
Position professorPosition = session.find( Position.class, PROFESSOR_POSITION_ID );
144+
145+
session.createMutationQuery(
146+
"update Person p " +
147+
"set p.position = :position " +
148+
"where p.id = :personId "
149+
)
150+
.setParameter( "position", professorPosition )
151+
.setParameter( "personId", p.getId() )
152+
.executeUpdate();
153+
154+
session.refresh( p );
155+
assertThat( p.getPosition().id ).isEqualTo( PROFESSOR_POSITION_ID );
156+
157+
} );
158+
}
159+
160+
@Test
161+
public void testRefreshOfLazyManyToOneCascadeRefresh(SessionFactoryScope scope) {
162+
scope.inTransaction( session -> {
163+
Person p = session.find( Person.class, PERSON_ID );
164+
Position position = p.getPosition();
165+
assertThat( position.getId() ).isEqualTo( ASSISTANT_PROFESSOR_POSITION_ID );
166+
assertThat( position.getDescription() ).isEqualTo( ASSISTANT_POSITION_DESCRIPTION );
167+
168+
String newAssistantProfessorDescription = "Assistant Professor 2";
169+
session.createMutationQuery(
170+
"update Position " +
171+
"set description = :description " +
172+
"where id = :id "
173+
)
174+
.setParameter( "description", newAssistantProfessorDescription )
175+
.setParameter( "id", ASSISTANT_PROFESSOR_POSITION_ID )
176+
.executeUpdate();
177+
178+
session.refresh( p );
179+
// the association has been refreshed because it's annotated with `cascade = CascadeType.REFRESH`
180+
assertThat( p.getPosition().getDescription() ).isEqualTo( newAssistantProfessorDescription );
181+
} );
182+
}
183+
184+
@Test
185+
public void testRefreshOfLazyManyToOneNoCascadeRefresh(SessionFactoryScope scope) {
186+
scope.inTransaction( session -> {
187+
Person p = session.find( Person.class, PERSON_ID );
188+
Position position = p.getPreviousPosition();
189+
assertThat( position.getId() ).isEqualTo( PROFESSOR_POSITION_ID );
190+
assertThat( position.getDescription() ).isEqualTo( POSITION_DESCRIPTION );
191+
192+
String newAssistantProfessorDescription = "Assistant Professor 2";
193+
session.createMutationQuery(
194+
"update Position " +
195+
"set description = :description " +
196+
"where id = :id "
197+
)
198+
.setParameter( "description", newAssistantProfessorDescription )
199+
.setParameter( "id", PROFESSOR_POSITION_ID )
200+
.executeUpdate();
201+
202+
session.refresh( p );
203+
// the association has not been refreshed because it's not annotated with `cascade = CascadeType.REFRESH`
204+
assertThat( p.getPreviousPosition().getDescription() ).isEqualTo( POSITION_DESCRIPTION );
205+
} );
206+
}
207+
208+
@Entity(name = "Person")
209+
public static class Person {
210+
211+
@Id
212+
private Long id;
213+
214+
private String firstName;
215+
216+
@Basic(fetch = FetchType.LAZY)
217+
private String lastName;
218+
219+
@Basic(fetch = FetchType.LAZY)
220+
@Formula("firstName || ' ' || lastName")
221+
private String fullName;
222+
223+
@OneToMany(mappedBy = "person", fetch = FetchType.LAZY, cascade = CascadeType.REFRESH, orphanRemoval = true)
224+
private Set<Course> courses = new HashSet<>();
225+
226+
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
227+
private Position position;
228+
229+
@ManyToOne(fetch = FetchType.LAZY)
230+
private Position previousPosition;
231+
232+
protected Person() {
233+
}
234+
235+
public Person(Long id, String firstName, String lastName, Position position, Position previousPosition) {
236+
this.id = id;
237+
this.firstName = firstName;
238+
this.lastName = lastName;
239+
this.position = position;
240+
this.previousPosition = previousPosition;
241+
}
242+
243+
public Long getId() {
244+
return id;
245+
}
246+
247+
public String getFirstName() {
248+
return firstName;
249+
}
250+
251+
public void setFirstName(String firstName) {
252+
this.firstName = firstName;
253+
}
254+
255+
public String getLastName() {
256+
return lastName;
257+
}
258+
259+
public void setLastName(String lastName) {
260+
this.lastName = lastName;
261+
}
262+
263+
public String getFullName() {
264+
return fullName;
265+
}
266+
267+
public Set<Course> getCourses() {
268+
return courses;
269+
}
270+
271+
public Position getPosition() {
272+
return position;
273+
}
274+
275+
public Position getPreviousPosition() {
276+
return previousPosition;
277+
}
278+
}
279+
280+
@Entity(name = "Course")
281+
public static class Course {
282+
283+
@Id
284+
private Long id;
285+
286+
private String title;
287+
288+
@ManyToOne(fetch = FetchType.LAZY)
289+
private Person person;
290+
291+
protected Course() {
292+
}
293+
294+
public Course(Long id, String title, Person person) {
295+
this.id = id;
296+
this.title = title;
297+
this.person = person;
298+
}
299+
300+
public Long getId() {
301+
return id;
302+
}
303+
304+
public String getTitle() {
305+
return title;
306+
}
307+
308+
public Person getPerson() {
309+
return person;
310+
}
311+
}
312+
313+
@Entity(name = "Position")
314+
@Table(name = "POSITION_TABLE")
315+
public static class Position {
316+
317+
@Id
318+
private Long id;
319+
320+
@Basic(fetch = FetchType.LAZY)
321+
private String description;
322+
323+
public Position() {
324+
}
325+
326+
public Position(Long id, String description) {
327+
this.id = id;
328+
this.description = description;
329+
}
330+
331+
public Long getId() {
332+
return id;
333+
}
334+
335+
public void setId(Long id) {
336+
this.id = id;
337+
}
338+
339+
public String getDescription() {
340+
return description;
341+
}
342+
343+
public void setDescription(String description) {
344+
this.description = description;
345+
}
346+
}
347+
348+
}

0 commit comments

Comments
 (0)