Skip to content

Commit 7ab7998

Browse files
committed
HHH-18855: Review comments
1 parent 8347c3b commit 7ab7998

File tree

2 files changed

+130
-74
lines changed

2 files changed

+130
-74
lines changed

hibernate-core/src/main/java/org/hibernate/engine/spi/SubselectFetch.java

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,42 +89,28 @@ public String toString() {
8989
public static RegistrationHandler createRegistrationHandler(
9090
BatchFetchQueue batchFetchQueue,
9191
SelectStatement sqlAst,
92-
TableGroup tableGroup,
9392
JdbcParametersList jdbcParameters,
9493
JdbcParameterBindings jdbcParameterBindings) {
94+
final List<TableGroup> roots = sqlAst.getQuerySpec().getFromClause().getRoots();
95+
if ( roots.isEmpty() ) {
96+
// we allow this now
97+
return NO_OP_REG_HANDLER;
98+
}
9599

96100
return new StandardRegistrationHandler(
97101
batchFetchQueue,
98102
sqlAst,
99-
tableGroup,
100103
jdbcParameters,
101104
jdbcParameterBindings
102105
);
103106
}
104107

105-
public static RegistrationHandler createRegistrationHandler(
106-
BatchFetchQueue batchFetchQueue,
107-
SelectStatement sqlAst,
108-
JdbcParametersList jdbcParameters,
109-
JdbcParameterBindings jdbcParameterBindings) {
110-
final List<TableGroup> roots = sqlAst.getQuerySpec().getFromClause().getRoots();
111-
if ( roots.isEmpty() ) {
112-
// we allow this now
113-
return NO_OP_REG_HANDLER;
114-
}
115-
116-
return createRegistrationHandler( batchFetchQueue, sqlAst, roots.get( 0 ), jdbcParameters, jdbcParameterBindings );
117-
}
118-
119108
public interface RegistrationHandler {
120109
void addKey(EntityHolder holder);
121110
}
122111

123-
private static final RegistrationHandler NO_OP_REG_HANDLER = new RegistrationHandler() {
124-
@Override
125-
public void addKey(EntityHolder holder) {
126-
}
127-
} ;
112+
private static final RegistrationHandler NO_OP_REG_HANDLER = holder -> {
113+
};
128114

129115
public static class StandardRegistrationHandler implements RegistrationHandler {
130116
private final BatchFetchQueue batchFetchQueue;
@@ -136,7 +122,6 @@ public static class StandardRegistrationHandler implements RegistrationHandler {
136122
private StandardRegistrationHandler(
137123
BatchFetchQueue batchFetchQueue,
138124
SelectStatement loadingSqlAst,
139-
TableGroup ownerTableGroup,
140125
JdbcParametersList loadingJdbcParameters,
141126
JdbcParameterBindings loadingJdbcParameterBindings) {
142127
this.batchFetchQueue = batchFetchQueue;

hibernate-core/src/test/java/org/hibernate/orm/test/fetch/GenerateSubselectsOnJoinedAssociationTest.java

Lines changed: 123 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@
1212
import jakarta.persistence.ManyToMany;
1313
import jakarta.persistence.ManyToOne;
1414
import jakarta.persistence.OneToMany;
15-
1615
import org.hibernate.Hibernate;
17-
import org.hibernate.annotations.Fetch;
1816
import org.hibernate.annotations.FetchMode;
17+
import org.hibernate.annotations.FetchProfile;
18+
import org.hibernate.annotations.FetchProfileOverride;
1919
import org.hibernate.engine.spi.BatchFetchQueue;
2020
import org.hibernate.engine.spi.EntityKey;
2121
import org.hibernate.engine.spi.SessionImplementor;
2222
import org.hibernate.persister.entity.EntityPersister;
23-
24-
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
25-
import org.hibernate.testing.orm.junit.Jpa;
26-
import org.junit.jupiter.api.BeforeAll;
23+
import org.hibernate.testing.orm.junit.DomainModel;
24+
import org.hibernate.testing.orm.junit.SessionFactory;
25+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
26+
import org.junit.jupiter.api.BeforeEach;
2727
import org.junit.jupiter.api.Test;
2828

2929
import java.util.HashSet;
@@ -33,15 +33,31 @@
3333
import static org.hamcrest.Matchers.is;
3434
import static org.hamcrest.Matchers.notNullValue;
3535

36-
@Jpa(annotatedClasses = {
36+
@SessionFactory
37+
@DomainModel(annotatedClasses = {
3738
GenerateSubselectsOnJoinedAssociationTest.LazySelectRoot.class,
3839
GenerateSubselectsOnJoinedAssociationTest.LazySelectNode.class
3940
})
4041
public class GenerateSubselectsOnJoinedAssociationTest {
4142

42-
@BeforeAll
43-
static void setup(final EntityManagerFactoryScope scope) {
43+
private EntityKey key1;
44+
private EntityKey key2;
45+
private EntityKey key3;
46+
47+
@BeforeEach
48+
void setup(final SessionFactoryScope scope) {
49+
final EntityPersister persister = scope.getSessionFactory().getMappingMetamodel()
50+
.getEntityDescriptor( LazySelectNode.class );
51+
52+
key1 = new EntityKey( 10, persister );
53+
key2 = new EntityKey( 20, persister );
54+
key3 = new EntityKey( 30, persister );
55+
4456
scope.inTransaction( em -> {
57+
if ( em.find( LazySelectRoot.class, 1 ) != null ) {
58+
return;
59+
}
60+
4561
final LazySelectNode rootNode = new LazySelectNode();
4662
rootNode.id = 10;
4763

@@ -68,64 +84,114 @@ static void setup(final EntityManagerFactoryScope scope) {
6884
}
6985

7086
@Test
71-
void testSubselectFetchingFromFind(final EntityManagerFactoryScope scope) {
72-
final LazySelectRoot root = scope.fromTransaction( em -> {
73-
final SessionImplementor session = em.unwrap( SessionImplementor.class );
74-
final EntityPersister persister = session.getEntityPersister( null, new LazySelectNode() );
75-
final EntityKey key1 = session.generateEntityKey( 10, persister );
76-
final EntityKey key2 = session.generateEntityKey( 20, persister );
77-
final EntityKey key3 = session.generateEntityKey( 30, persister );
78-
79-
final LazySelectRoot in = em.find( LazySelectRoot.class, 1L );
80-
81-
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
82-
assertThat( batchFetchQueue.getSubselect( key1 ), is( notNullValue() ) );
83-
assertThat( batchFetchQueue.getSubselect( key2 ), is( notNullValue() ) );
84-
assertThat( batchFetchQueue.getSubselect( key3 ), is( notNullValue() ) );
85-
86-
return in;
87+
void testLazySubselectFetchingFromFind(final SessionFactoryScope scope) {
88+
scope.inTransaction( session -> {
89+
session.enableFetchProfile( "lazysubselect" );
90+
91+
final LazySelectRoot root = session.find( LazySelectRoot.class, 1 );
92+
93+
assertNotInitialized( root );
94+
Hibernate.initialize( root.nodes );
95+
96+
assertGeneratedSubselects( session );
97+
assertNodesInitialized( root );
98+
99+
final LazySelectNode anyNode = root.nodes.iterator().next();
100+
Hibernate.initialize( anyNode.children );
101+
102+
assertFullyInitialized( root );
87103
} );
104+
}
88105

89-
for ( final LazySelectNode node : root.nodes ) {
90-
assertThat( Hibernate.isInitialized( ( (LazySelectNode) Hibernate.unproxy( node ) ).children ),
91-
is( false )
92-
);
93-
}
106+
@Test
107+
void testEagerSubselectFetchingFromFind(final SessionFactoryScope scope) {
108+
scope.inTransaction( session -> {
109+
session.enableFetchProfile( "eagersubselect" );
110+
111+
final LazySelectRoot root = session.find( LazySelectRoot.class, 1 );
112+
113+
assertGeneratedSubselects( session );
114+
assertFullyInitialized( root );
115+
} );
116+
}
117+
118+
@Test
119+
void testLazySubselectFetchingFromQuery(final SessionFactoryScope scope) {
120+
scope.inTransaction( session -> {
121+
session.enableFetchProfile( "lazysubselect" );
122+
123+
final LazySelectRoot root = session.createQuery( "select r from root r where r.id = ?1",
124+
LazySelectRoot.class )
125+
.setParameter( 1, 1 ).getSingleResult();
126+
127+
assertNotInitialized( root );
128+
Hibernate.initialize( root.nodes );
129+
130+
assertGeneratedSubselects( session );
131+
assertNodesInitialized( root );
132+
133+
final LazySelectNode anyNode = root.nodes.iterator().next();
134+
Hibernate.initialize( anyNode.children );
135+
136+
assertFullyInitialized( root );
137+
} );
94138
}
95139

96140
@Test
97-
void testSubselectFetchingFromQuery(final EntityManagerFactoryScope scope) {
98-
final LazySelectRoot root = scope.fromTransaction( em -> {
99-
final SessionImplementor session = em.unwrap( SessionImplementor.class );
100-
final EntityPersister persister = session.getEntityPersister( null, new LazySelectNode() );
101-
final EntityKey key1 = session.generateEntityKey( 10, persister );
102-
final EntityKey key2 = session.generateEntityKey( 20, persister );
103-
final EntityKey key3 = session.generateEntityKey( 30, persister );
104-
105-
final LazySelectRoot in = em.createQuery( "select r from root r join fetch r.nodes where r.id = ?1",
106-
LazySelectRoot.class ).setParameter( 1, 1 ).getSingleResult();
107-
108-
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
109-
assertThat( batchFetchQueue.getSubselect( key1 ), is( notNullValue() ) );
110-
assertThat( batchFetchQueue.getSubselect( key2 ), is( notNullValue() ) );
111-
assertThat( batchFetchQueue.getSubselect( key3 ), is( notNullValue() ) );
112-
return in;
141+
void testEagerSubselectFetchingFromQuery(final SessionFactoryScope scope) {
142+
scope.inTransaction( session -> {
143+
session.enableFetchProfile( "eagersubselect" );
144+
145+
final LazySelectRoot root = session.createQuery( "select r from root r where r.id = ?1",
146+
LazySelectRoot.class ).setParameter( 1, 1 ).getSingleResult();
147+
148+
assertGeneratedSubselects( session );
149+
assertFullyInitialized( root );
113150
} );
151+
}
114152

115-
for ( final LazySelectNode node : root.nodes ) {
116-
assertThat( Hibernate.isInitialized( ( (LazySelectNode) Hibernate.unproxy( node ) ).children ),
117-
is( false )
118-
);
153+
private void assertGeneratedSubselects(final SessionImplementor session) {
154+
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
155+
assertThat( batchFetchQueue.getSubselect( key1 ), is( notNullValue() ) );
156+
assertThat( batchFetchQueue.getSubselect( key2 ), is( notNullValue() ) );
157+
assertThat( batchFetchQueue.getSubselect( key3 ), is( notNullValue() ) );
158+
}
159+
160+
private void assertNotInitialized(LazySelectRoot root) {
161+
assertThat( Hibernate.isInitialized( root.getNodes() ), is( false ) );
162+
}
163+
164+
private void assertNodesInitialized(LazySelectRoot root) {
165+
assertThat( Hibernate.isInitialized( root.getNodes() ), is( true ) );
166+
167+
for ( final LazySelectNode node : root.getNodes() ) {
168+
assertThat( Hibernate.isInitialized( node.getChildren() ), is( false ) );
169+
}
170+
}
171+
172+
private void assertFullyInitialized(LazySelectRoot root) {
173+
assertThat( Hibernate.isInitialized( root.getNodes() ), is( true ) );
174+
175+
for ( final LazySelectNode node : root.getNodes() ) {
176+
assertThat( Hibernate.isInitialized( node.getChildren() ), is( true ) );
119177
}
120178
}
121179

122180
@Entity(name = "root")
181+
@FetchProfile(name = "lazysubselect")
182+
@FetchProfile(name = "eagersubselect")
123183
public static class LazySelectRoot {
124184
@Id
125185
public Integer id;
126186

127-
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "root")
187+
@OneToMany(cascade = CascadeType.ALL, mappedBy = "root")
188+
@FetchProfileOverride(profile = "lazysubselect", fetch = FetchType.LAZY)
189+
@FetchProfileOverride(profile = "eagersubselect", fetch = FetchType.EAGER)
128190
public Set<LazySelectNode> nodes = new HashSet<>();
191+
192+
public Set<LazySelectNode> getNodes() {
193+
return nodes;
194+
}
129195
}
130196

131197
@Entity(name = "node")
@@ -139,7 +205,12 @@ public static class LazySelectNode {
139205

140206
@ManyToMany(cascade = CascadeType.ALL)
141207
@JoinTable(name = "RELATIONSHIPS")
142-
@Fetch(FetchMode.SUBSELECT)
208+
@FetchProfileOverride(profile = "lazysubselect", fetch = FetchType.LAZY, mode = FetchMode.SUBSELECT)
209+
@FetchProfileOverride(profile = "eagersubselect", fetch = FetchType.EAGER, mode = FetchMode.SUBSELECT)
143210
public final Set<LazySelectNode> children = new HashSet<>();
211+
212+
public Set<LazySelectNode> getChildren() {
213+
return children;
214+
}
144215
}
145216
}

0 commit comments

Comments
 (0)