Skip to content

Commit 453cc01

Browse files
committed
add systematic tests for before native query flushing in JPA and plain Hibernate
1 parent 7d78b00 commit 453cc01

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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.jpa.autoflush;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.FlushModeType;
9+
import jakarta.persistence.Id;
10+
import org.hibernate.query.QueryFlushMode;
11+
import org.hibernate.testing.orm.junit.DomainModel;
12+
import org.hibernate.testing.orm.junit.SessionFactory;
13+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
14+
import org.junit.jupiter.api.Test;
15+
16+
import java.util.List;
17+
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
20+
@SessionFactory
21+
@DomainModel(annotatedClasses = HibernateAutoflushTest.Thing.class)
22+
public class HibernateAutoflushTest {
23+
24+
@Test void test1(SessionFactoryScope scope) {
25+
scope.getSessionFactory().getSchemaManager().truncate();
26+
scope.inTransaction( em -> {
27+
em.persist( new Thing( "Widget" ) );
28+
List<Thing> resultList =
29+
em.createNativeQuery( "select * from Thing", Thing.class )
30+
.getResultList();
31+
// Hibernate does NOT autoflush before a native query
32+
assertEquals( 0, resultList.size() );
33+
} );
34+
}
35+
36+
@Test void test2(SessionFactoryScope scope) {
37+
scope.getSessionFactory().getSchemaManager().truncate();
38+
scope.inTransaction( em -> {
39+
em.persist( new Thing("Widget") );
40+
List<String> resultList =
41+
em.createNativeQuery( "select typeOfThing from Thing", String.class )
42+
.getResultList();
43+
// Hibernate does NOT autoflush before a native query
44+
assertEquals(0, resultList.size());
45+
} );
46+
}
47+
48+
@Test void test3(SessionFactoryScope scope) {
49+
scope.getSessionFactory().getSchemaManager().truncate();
50+
scope.inSession( em -> {
51+
em.persist( new Thing("Widget") );
52+
List<Thing> resultList =
53+
em.createNativeQuery( "select * from Thing", Thing.class )
54+
.getResultList();
55+
// spec says we must NOT flush before native query outside tx
56+
assertEquals(0, resultList.size());
57+
} );
58+
}
59+
60+
@Test void test4(SessionFactoryScope scope) {
61+
scope.getSessionFactory().getSchemaManager().truncate();
62+
scope.inTransaction( em -> {
63+
em.setFlushMode( FlushModeType.COMMIT );
64+
em.persist( new Thing("Widget") );
65+
List<Thing> resultList =
66+
em.createNativeQuery( "select * from Thing", Thing.class )
67+
.getResultList();
68+
// spec says we must NOT flush before native query with FMT.COMMIT
69+
assertEquals(0, resultList.size());
70+
} );
71+
}
72+
73+
@Test void test5(SessionFactoryScope scope) {
74+
scope.getSessionFactory().getSchemaManager().truncate();
75+
scope.inTransaction( em -> {
76+
em.persist( new Thing("Widget") );
77+
List<Thing> resultList =
78+
em.createNativeQuery( "select * from Thing", Thing.class )
79+
.addSynchronizedQuerySpace( "Thing" )
80+
.getResultList();
81+
// we should not flush because user specified that the query touches the table
82+
assertEquals(1, resultList.size());
83+
} );
84+
}
85+
86+
@Test void test6(SessionFactoryScope scope) {
87+
scope.getSessionFactory().getSchemaManager().truncate();
88+
scope.inTransaction( em -> {
89+
em.persist( new Thing("Widget") );
90+
List<Thing> resultList =
91+
em.createNativeQuery( "select * from Thing", Thing.class )
92+
.addSynchronizedQuerySpace( "XXX" )
93+
.getResultList();
94+
// we should not flush because user specified that the query doesn't touch the table
95+
assertEquals(0, resultList.size());
96+
} );
97+
}
98+
99+
@Test void test7(SessionFactoryScope scope) {
100+
scope.getSessionFactory().getSchemaManager().truncate();
101+
scope.inTransaction( em -> {
102+
em.persist( new Thing( "Widget" ) );
103+
List<Thing> resultList =
104+
em.createNativeQuery( "select * from Thing", Thing.class )
105+
.setQueryFlushMode( QueryFlushMode.FLUSH )
106+
.getResultList();
107+
// we should flush because of the QueryFlushMode
108+
assertEquals( 1, resultList.size() );
109+
} );
110+
}
111+
112+
@Entity(name="Thing")
113+
public static class Thing {
114+
@Id
115+
long id;
116+
String typeOfThing;
117+
118+
public Thing(String typeOfThing) {
119+
this.typeOfThing = typeOfThing;
120+
}
121+
122+
public Thing() {
123+
}
124+
}
125+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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.jpa.autoflush;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.FlushModeType;
9+
import jakarta.persistence.Id;
10+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
11+
import org.hibernate.testing.orm.junit.Jpa;
12+
import org.junit.jupiter.api.Test;
13+
14+
import java.util.List;
15+
16+
import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_SPACES;
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
19+
@Jpa(annotatedClasses = JpaAutoflushTest.Thing.class)
20+
public class JpaAutoflushTest {
21+
22+
@Test void test1(EntityManagerFactoryScope scope) {
23+
scope.getEntityManagerFactory().getSchemaManager().truncate();
24+
scope.inTransaction( em -> {
25+
em.persist( new Thing( "Widget" ) );
26+
List<?> resultList =
27+
em.createNativeQuery( "select * from Thing", Thing.class )
28+
.getResultList();
29+
// spec says we must flush before native query in tx
30+
assertEquals( 1, resultList.size() );
31+
} );
32+
}
33+
34+
@Test void test2(EntityManagerFactoryScope scope) {
35+
scope.getEntityManagerFactory().getSchemaManager().truncate();
36+
scope.inTransaction( em -> {
37+
em.persist( new Thing("Widget") );
38+
List<?> resultList =
39+
em.createNativeQuery( "select typeOfThing from Thing", String.class )
40+
.getResultList();
41+
// spec says we must flush before native query in tx
42+
assertEquals(1, resultList.size());
43+
} );
44+
}
45+
46+
@Test void test3(EntityManagerFactoryScope scope) {
47+
scope.getEntityManagerFactory().getSchemaManager().truncate();
48+
scope.inEntityManager( em -> {
49+
em.persist( new Thing("Widget") );
50+
List<?> resultList =
51+
em.createNativeQuery( "select * from Thing", Thing.class )
52+
.getResultList();
53+
// spec says we must NOT flush before native query outside tx
54+
assertEquals(0, resultList.size());
55+
} );
56+
}
57+
58+
@Test void test4(EntityManagerFactoryScope scope) {
59+
scope.getEntityManagerFactory().getSchemaManager().truncate();
60+
scope.inTransaction( em -> {
61+
em.setFlushMode( FlushModeType.COMMIT );
62+
em.persist( new Thing("Widget") );
63+
List<?> resultList =
64+
em.createNativeQuery( "select * from Thing", Thing.class )
65+
.getResultList();
66+
// spec says we must NOT flush before native query with FMT.COMMIT
67+
assertEquals(0, resultList.size());
68+
} );
69+
}
70+
71+
@Test void test5(EntityManagerFactoryScope scope) {
72+
scope.getEntityManagerFactory().getSchemaManager().truncate();
73+
scope.inTransaction( em -> {
74+
em.persist( new Thing("Widget") );
75+
List<?> resultList =
76+
em.createNativeQuery( "select * from Thing", Thing.class )
77+
.setHint( HINT_NATIVE_SPACES, "Thing" )
78+
.getResultList();
79+
// we should not flush because user specified that the query touches the table
80+
assertEquals(1, resultList.size());
81+
} );
82+
}
83+
84+
@Test void test6(EntityManagerFactoryScope scope) {
85+
scope.getEntityManagerFactory().getSchemaManager().truncate();
86+
scope.inTransaction( em -> {
87+
em.persist( new Thing("Widget") );
88+
List<?> resultList =
89+
em.createNativeQuery( "select * from Thing", Thing.class )
90+
.setHint( HINT_NATIVE_SPACES, "XXX" )
91+
.getResultList();
92+
// we should not flush because user specified that the query doesn't touch the table
93+
assertEquals(0, resultList.size());
94+
} );
95+
}
96+
97+
@Entity(name="Thing")
98+
public static class Thing {
99+
@Id
100+
long id;
101+
String typeOfThing;
102+
103+
public Thing(String typeOfThing) {
104+
this.typeOfThing = typeOfThing;
105+
}
106+
107+
public Thing() {
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)