HHH-14124 Test that the FETCH entitygraph semantic overrides EAGER associations to LAZY for all results
This commit is contained in:
parent
1d965227c4
commit
9323d426f1
|
@ -441,8 +441,10 @@ public abstract class Loader {
|
|||
loadedKeys,
|
||||
returnProxies
|
||||
);
|
||||
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
||||
nullSeparatedHydratedObjects.add( null );
|
||||
if ( nullSeparatedHydratedObjects != null ) {
|
||||
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
||||
nullSeparatedHydratedObjects.add( null );
|
||||
}
|
||||
if ( !keyToRead.equals( loadedKeys[0] ) ) {
|
||||
throw new AssertionFailure(
|
||||
String.format(
|
||||
|
@ -1051,8 +1053,10 @@ public abstract class Loader {
|
|||
forcedResultTransformer
|
||||
);
|
||||
results.add( result );
|
||||
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
||||
nullSeparatedHydratedObjects.add( null );
|
||||
if ( nullSeparatedHydratedObjects != null ) {
|
||||
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
||||
nullSeparatedHydratedObjects.add( null );
|
||||
}
|
||||
if ( createSubselects ) {
|
||||
subselectResultKeys.add( keys );
|
||||
keys = new EntityKey[entitySpan]; //can't reuse in this case
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.jpa.test.graphs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.CascadeType;
|
||||
|
@ -17,6 +18,7 @@ import javax.persistence.Id;
|
|||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
|
@ -62,110 +64,119 @@ public class LoadAndFetchGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
doInJPA(
|
||||
this::entityManagerFactory, entityManager -> {
|
||||
AEntity a1 = new AEntity();
|
||||
a1.setId( 1 );
|
||||
a1.setLabel( "A1" );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
// Create the model twice, with different IDs,
|
||||
// because we also need to test what happens when multiple results are loaded by a query.
|
||||
for ( int offset : new int[]{ 0, 10000 } ) {
|
||||
AEntity a1 = new AEntity();
|
||||
a1.setId( offset + 1 );
|
||||
a1.setLabel( "A1" );
|
||||
|
||||
AEntity a2 = new AEntity();
|
||||
a2.setId( 2 );
|
||||
a2.setLabel( "A2" );
|
||||
AEntity a2 = new AEntity();
|
||||
a2.setId( offset + 2 );
|
||||
a2.setLabel( "A2" );
|
||||
|
||||
entityManager.persist( a1 );
|
||||
entityManager.persist( a2 );
|
||||
entityManager.persist( a1 );
|
||||
entityManager.persist( a2 );
|
||||
|
||||
BEntity b1 = new BEntity();
|
||||
b1.setId( 1 );
|
||||
b1.setLabel( "B1" );
|
||||
BEntity b1 = new BEntity();
|
||||
b1.setId( offset + 1 );
|
||||
b1.setLabel( "B1" );
|
||||
|
||||
BEntity b2 = new BEntity();
|
||||
b2.setId( 2 );
|
||||
b2.setLabel( "B2" );
|
||||
BEntity b2 = new BEntity();
|
||||
b2.setId( offset + 2 );
|
||||
b2.setLabel( "B2" );
|
||||
|
||||
entityManager.persist( b1 );
|
||||
entityManager.persist( b2 );
|
||||
entityManager.persist( b1 );
|
||||
entityManager.persist( b2 );
|
||||
|
||||
EEntity e1 = new EEntity();
|
||||
e1.setId( 1 );
|
||||
e1.setLabel( "E1" );
|
||||
EEntity e1 = new EEntity();
|
||||
e1.setId( offset + 1 );
|
||||
e1.setLabel( "E1" );
|
||||
|
||||
EEntity e2 = new EEntity();
|
||||
e2.setId( 2 );
|
||||
e2.setLabel( "E2" );
|
||||
EEntity e2 = new EEntity();
|
||||
e2.setId( offset + 2 );
|
||||
e2.setLabel( "E2" );
|
||||
|
||||
EEntity e3 = new EEntity();
|
||||
e3.setId( 3 );
|
||||
e3.setLabel( "E3" );
|
||||
EEntity e3 = new EEntity();
|
||||
e3.setId( offset + 3 );
|
||||
e3.setLabel( "E3" );
|
||||
|
||||
EEntity e4 = new EEntity();
|
||||
e4.setId( 4 );
|
||||
e4.setLabel( "E4" );
|
||||
EEntity e4 = new EEntity();
|
||||
e4.setId( offset + 4 );
|
||||
e4.setLabel( "E4" );
|
||||
|
||||
entityManager.persist( e1 );
|
||||
entityManager.persist( e2 );
|
||||
entityManager.persist( e3 );
|
||||
entityManager.persist( e4 );
|
||||
entityManager.persist( e1 );
|
||||
entityManager.persist( e2 );
|
||||
entityManager.persist( e3 );
|
||||
entityManager.persist( e4 );
|
||||
|
||||
DEntity d1 = new DEntity();
|
||||
d1.setId( 1 );
|
||||
d1.setLabel( "D1" );
|
||||
d1.setE( e1 );
|
||||
DEntity d1 = new DEntity();
|
||||
d1.setId( offset + 1 );
|
||||
d1.setLabel( "D1" );
|
||||
d1.setE( e1 );
|
||||
|
||||
DEntity d2 = new DEntity();
|
||||
d2.setId( 2 );
|
||||
d2.setLabel( "D2" );
|
||||
d2.setE( e2 );
|
||||
DEntity d2 = new DEntity();
|
||||
d2.setId( offset + 2 );
|
||||
d2.setLabel( "D2" );
|
||||
d2.setE( e2 );
|
||||
|
||||
CEntity c1 = new CEntity();
|
||||
c1.setId( 1 );
|
||||
c1.setLabel( "C1" );
|
||||
c1.setA( a1 );
|
||||
c1.setB( b1 );
|
||||
c1.addD( d1 );
|
||||
c1.addD( d2 );
|
||||
CEntity c1 = new CEntity();
|
||||
c1.setId( offset + 1 );
|
||||
c1.setLabel( "C1" );
|
||||
c1.setA( a1 );
|
||||
c1.setB( b1 );
|
||||
c1.addD( d1 );
|
||||
c1.addD( d2 );
|
||||
|
||||
entityManager.persist( c1 );
|
||||
entityManager.persist( c1 );
|
||||
|
||||
DEntity d3 = new DEntity();
|
||||
d3.setId( 3 );
|
||||
d3.setLabel( "D3" );
|
||||
d3.setE( e3 );
|
||||
DEntity d3 = new DEntity();
|
||||
d3.setId( offset + 3 );
|
||||
d3.setLabel( "D3" );
|
||||
d3.setE( e3 );
|
||||
|
||||
DEntity d4 = new DEntity();
|
||||
d4.setId( 4 );
|
||||
d4.setLabel( "D4" );
|
||||
d4.setE( e4 );
|
||||
DEntity d4 = new DEntity();
|
||||
d4.setId( offset + 4 );
|
||||
d4.setLabel( "D4" );
|
||||
d4.setE( e4 );
|
||||
|
||||
CEntity c2 = new CEntity();
|
||||
c2.setId( 2 );
|
||||
c2.setLabel( "C2" );
|
||||
c2.setA( a2 );
|
||||
c2.setB( b2 );
|
||||
c2.addD( d3 );
|
||||
c2.addD( d4 );
|
||||
CEntity c2 = new CEntity();
|
||||
c2.setId( offset + 2 );
|
||||
c2.setLabel( "C2" );
|
||||
c2.setA( a2 );
|
||||
c2.setB( b2 );
|
||||
c2.addD( d3 );
|
||||
c2.addD( d4 );
|
||||
|
||||
entityManager.persist( c2 );
|
||||
entityManager.persist( c2 );
|
||||
|
||||
CEntity c3 = new CEntity();
|
||||
c3.setId( 3 );
|
||||
c3.setLabel( "C3" );
|
||||
CEntity c3 = new CEntity();
|
||||
c3.setId( offset + 3 );
|
||||
c3.setLabel( "C3" );
|
||||
|
||||
entityManager.persist( c3 );
|
||||
entityManager.persist( c3 );
|
||||
|
||||
c1.setC( c2 );
|
||||
c2.setC( c3 );
|
||||
CEntity c4 = new CEntity();
|
||||
c4.setId( offset + 4 );
|
||||
c4.setLabel( "C4" );
|
||||
|
||||
int id = 5;
|
||||
for ( int i = 0; i < 10; i++ ) {
|
||||
DEntity dn = new DEntity();
|
||||
dn.setId( id++ );
|
||||
dn.setLabel( "label" );
|
||||
dn.setE( e3 );
|
||||
entityManager.persist( dn );
|
||||
}
|
||||
entityManager.persist( c4 );
|
||||
|
||||
} );
|
||||
c1.setC( c2 );
|
||||
c2.setC( c3 );
|
||||
c1.setEagerC( c4 );
|
||||
|
||||
int id = 5;
|
||||
for ( int i = 0; i < 10; i++ ) {
|
||||
DEntity dn = new DEntity();
|
||||
dn.setId( offset + id++ );
|
||||
dn.setLabel( "label" );
|
||||
dn.setE( e3 );
|
||||
entityManager.persist( dn );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -284,10 +295,91 @@ public class LoadAndFetchGraphTest extends BaseEntityManagerFunctionalTestCase {
|
|||
assertTrue( Hibernate.isInitialized( cEntity.getC().getA() ) );
|
||||
assertFalse( Hibernate.isInitialized( cEntity.getC().getC() ) );
|
||||
|
||||
// With FETCH semantic, attributes that are not mentioned in the graph are LAZY,
|
||||
// even if they were EAGER in the mapping.
|
||||
assertFalse( Hibernate.isInitialized( cEntity.getEagerC() ) );
|
||||
|
||||
assertEquals( 1L, statistics.getPrepareStatementCount() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14124")
|
||||
public void testQueryByIdWithLoadGraphMultipleResults() {
|
||||
Statistics statistics = entityManagerFactory().unwrap( SessionFactory.class ).getStatistics();
|
||||
statistics.clear();
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
EntityGraph<CEntity> entityGraph = entityManager.createEntityGraph( CEntity.class );
|
||||
entityGraph.addAttributeNodes( "a", "b" );
|
||||
entityGraph.addSubgraph( "dList" ).addAttributeNodes( "e" );
|
||||
|
||||
TypedQuery<CEntity> query = entityManager.createQuery(
|
||||
"select c from CEntity as c where c.id in :cid ",
|
||||
CEntity.class
|
||||
);
|
||||
query.setHint( GraphSemantic.LOAD.getJpaHintName(), entityGraph );
|
||||
query.setParameter( "cid", Arrays.asList( 1, 10001 ) );
|
||||
|
||||
List<CEntity> cEntityList = query.getResultList();
|
||||
assertEquals( 2, cEntityList.size() );
|
||||
|
||||
for ( CEntity cEntity : cEntityList ) {
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getA() ) );
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getB() ) );
|
||||
assertFalse( Hibernate.isInitialized( cEntity.getC() ) );
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getdList() ) );
|
||||
cEntity.getdList().forEach( dEntity -> {
|
||||
assertTrue( Hibernate.isInitialized( dEntity.getE() ) );
|
||||
} );
|
||||
|
||||
// With LOAD semantic, attributes that are not mentioned in the graph are LAZY or EAGER,
|
||||
// depending on the mapping.
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getEagerC() ) );
|
||||
}
|
||||
|
||||
// 1 + 2 for the eager C
|
||||
assertEquals( 3L, statistics.getPrepareStatementCount() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14124")
|
||||
public void testQueryByIdWithFetchGraphMultipleResults() {
|
||||
Statistics statistics = entityManagerFactory().unwrap( SessionFactory.class ).getStatistics();
|
||||
statistics.clear();
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
EntityGraph<CEntity> entityGraph = entityManager.createEntityGraph( CEntity.class );
|
||||
entityGraph.addAttributeNodes( "a", "b" );
|
||||
entityGraph.addSubgraph( "dList" ).addAttributeNodes( "e" );
|
||||
|
||||
TypedQuery<CEntity> query = entityManager.createQuery(
|
||||
"select c from CEntity as c where c.id in :cid ",
|
||||
CEntity.class
|
||||
);
|
||||
query.setHint( GraphSemantic.FETCH.getJpaHintName(), entityGraph );
|
||||
query.setParameter( "cid", Arrays.asList( 1, 10001 ) );
|
||||
|
||||
List<CEntity> cEntityList = query.getResultList();
|
||||
assertEquals( 2, cEntityList.size() );
|
||||
|
||||
for ( CEntity cEntity : cEntityList ) {
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getA() ) );
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getB() ) );
|
||||
assertFalse( Hibernate.isInitialized( cEntity.getC() ) );
|
||||
assertTrue( Hibernate.isInitialized( cEntity.getdList() ) );
|
||||
cEntity.getdList().forEach( dEntity -> {
|
||||
assertTrue( Hibernate.isInitialized( dEntity.getE() ) );
|
||||
} );
|
||||
|
||||
// With FETCH semantic, attributes that are not mentioned in the graph are LAZY,
|
||||
// even if they were EAGER in the mapping.
|
||||
assertFalse( Hibernate.isInitialized( cEntity.getEagerC() ) );
|
||||
}
|
||||
|
||||
assertEquals( 1L, statistics.getPrepareStatementCount() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "AEntity")
|
||||
@Table(name = "A")
|
||||
public static class AEntity {
|
||||
|
|
Loading…
Reference in New Issue