HHH-14124 Test that the FETCH entitygraph semantic overrides EAGER associations to LAZY for all results
This commit is contained in:
parent
b15835788b
commit
00989d28d8
|
@ -441,8 +441,10 @@ public abstract class Loader {
|
||||||
loadedKeys,
|
loadedKeys,
|
||||||
returnProxies
|
returnProxies
|
||||||
);
|
);
|
||||||
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
if ( nullSeparatedHydratedObjects != null ) {
|
||||||
nullSeparatedHydratedObjects.add( null );
|
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
||||||
|
nullSeparatedHydratedObjects.add( null );
|
||||||
|
}
|
||||||
if ( !keyToRead.equals( loadedKeys[0] ) ) {
|
if ( !keyToRead.equals( loadedKeys[0] ) ) {
|
||||||
throw new AssertionFailure(
|
throw new AssertionFailure(
|
||||||
String.format(
|
String.format(
|
||||||
|
@ -1051,8 +1053,10 @@ public abstract class Loader {
|
||||||
forcedResultTransformer
|
forcedResultTransformer
|
||||||
);
|
);
|
||||||
results.add( result );
|
results.add( result );
|
||||||
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
if ( nullSeparatedHydratedObjects != null ) {
|
||||||
nullSeparatedHydratedObjects.add( null );
|
// Signal that a new row starts. Used in initializeEntitiesAndCollections
|
||||||
|
nullSeparatedHydratedObjects.add( null );
|
||||||
|
}
|
||||||
if ( createSubselects ) {
|
if ( createSubselects ) {
|
||||||
subselectResultKeys.add( keys );
|
subselectResultKeys.add( keys );
|
||||||
keys = new EntityKey[entitySpan]; //can't reuse in this case
|
keys = new EntityKey[entitySpan]; //can't reuse in this case
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.jpa.test.graphs;
|
package org.hibernate.jpa.test.graphs;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
|
@ -17,6 +18,7 @@ import javax.persistence.Id;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
|
@ -62,110 +64,119 @@ public class LoadAndFetchGraphTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
doInJPA(
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
this::entityManagerFactory, entityManager -> {
|
// Create the model twice, with different IDs,
|
||||||
AEntity a1 = new AEntity();
|
// because we also need to test what happens when multiple results are loaded by a query.
|
||||||
a1.setId( 1 );
|
for ( int offset : new int[]{ 0, 10000 } ) {
|
||||||
a1.setLabel( "A1" );
|
AEntity a1 = new AEntity();
|
||||||
|
a1.setId( offset + 1 );
|
||||||
|
a1.setLabel( "A1" );
|
||||||
|
|
||||||
AEntity a2 = new AEntity();
|
AEntity a2 = new AEntity();
|
||||||
a2.setId( 2 );
|
a2.setId( offset + 2 );
|
||||||
a2.setLabel( "A2" );
|
a2.setLabel( "A2" );
|
||||||
|
|
||||||
entityManager.persist( a1 );
|
entityManager.persist( a1 );
|
||||||
entityManager.persist( a2 );
|
entityManager.persist( a2 );
|
||||||
|
|
||||||
BEntity b1 = new BEntity();
|
BEntity b1 = new BEntity();
|
||||||
b1.setId( 1 );
|
b1.setId( offset + 1 );
|
||||||
b1.setLabel( "B1" );
|
b1.setLabel( "B1" );
|
||||||
|
|
||||||
BEntity b2 = new BEntity();
|
BEntity b2 = new BEntity();
|
||||||
b2.setId( 2 );
|
b2.setId( offset + 2 );
|
||||||
b2.setLabel( "B2" );
|
b2.setLabel( "B2" );
|
||||||
|
|
||||||
entityManager.persist( b1 );
|
entityManager.persist( b1 );
|
||||||
entityManager.persist( b2 );
|
entityManager.persist( b2 );
|
||||||
|
|
||||||
EEntity e1 = new EEntity();
|
EEntity e1 = new EEntity();
|
||||||
e1.setId( 1 );
|
e1.setId( offset + 1 );
|
||||||
e1.setLabel( "E1" );
|
e1.setLabel( "E1" );
|
||||||
|
|
||||||
EEntity e2 = new EEntity();
|
EEntity e2 = new EEntity();
|
||||||
e2.setId( 2 );
|
e2.setId( offset + 2 );
|
||||||
e2.setLabel( "E2" );
|
e2.setLabel( "E2" );
|
||||||
|
|
||||||
EEntity e3 = new EEntity();
|
EEntity e3 = new EEntity();
|
||||||
e3.setId( 3 );
|
e3.setId( offset + 3 );
|
||||||
e3.setLabel( "E3" );
|
e3.setLabel( "E3" );
|
||||||
|
|
||||||
EEntity e4 = new EEntity();
|
EEntity e4 = new EEntity();
|
||||||
e4.setId( 4 );
|
e4.setId( offset + 4 );
|
||||||
e4.setLabel( "E4" );
|
e4.setLabel( "E4" );
|
||||||
|
|
||||||
entityManager.persist( e1 );
|
entityManager.persist( e1 );
|
||||||
entityManager.persist( e2 );
|
entityManager.persist( e2 );
|
||||||
entityManager.persist( e3 );
|
entityManager.persist( e3 );
|
||||||
entityManager.persist( e4 );
|
entityManager.persist( e4 );
|
||||||
|
|
||||||
DEntity d1 = new DEntity();
|
DEntity d1 = new DEntity();
|
||||||
d1.setId( 1 );
|
d1.setId( offset + 1 );
|
||||||
d1.setLabel( "D1" );
|
d1.setLabel( "D1" );
|
||||||
d1.setE( e1 );
|
d1.setE( e1 );
|
||||||
|
|
||||||
DEntity d2 = new DEntity();
|
DEntity d2 = new DEntity();
|
||||||
d2.setId( 2 );
|
d2.setId( offset + 2 );
|
||||||
d2.setLabel( "D2" );
|
d2.setLabel( "D2" );
|
||||||
d2.setE( e2 );
|
d2.setE( e2 );
|
||||||
|
|
||||||
CEntity c1 = new CEntity();
|
CEntity c1 = new CEntity();
|
||||||
c1.setId( 1 );
|
c1.setId( offset + 1 );
|
||||||
c1.setLabel( "C1" );
|
c1.setLabel( "C1" );
|
||||||
c1.setA( a1 );
|
c1.setA( a1 );
|
||||||
c1.setB( b1 );
|
c1.setB( b1 );
|
||||||
c1.addD( d1 );
|
c1.addD( d1 );
|
||||||
c1.addD( d2 );
|
c1.addD( d2 );
|
||||||
|
|
||||||
entityManager.persist( c1 );
|
entityManager.persist( c1 );
|
||||||
|
|
||||||
DEntity d3 = new DEntity();
|
DEntity d3 = new DEntity();
|
||||||
d3.setId( 3 );
|
d3.setId( offset + 3 );
|
||||||
d3.setLabel( "D3" );
|
d3.setLabel( "D3" );
|
||||||
d3.setE( e3 );
|
d3.setE( e3 );
|
||||||
|
|
||||||
DEntity d4 = new DEntity();
|
DEntity d4 = new DEntity();
|
||||||
d4.setId( 4 );
|
d4.setId( offset + 4 );
|
||||||
d4.setLabel( "D4" );
|
d4.setLabel( "D4" );
|
||||||
d4.setE( e4 );
|
d4.setE( e4 );
|
||||||
|
|
||||||
CEntity c2 = new CEntity();
|
CEntity c2 = new CEntity();
|
||||||
c2.setId( 2 );
|
c2.setId( offset + 2 );
|
||||||
c2.setLabel( "C2" );
|
c2.setLabel( "C2" );
|
||||||
c2.setA( a2 );
|
c2.setA( a2 );
|
||||||
c2.setB( b2 );
|
c2.setB( b2 );
|
||||||
c2.addD( d3 );
|
c2.addD( d3 );
|
||||||
c2.addD( d4 );
|
c2.addD( d4 );
|
||||||
|
|
||||||
entityManager.persist( c2 );
|
entityManager.persist( c2 );
|
||||||
|
|
||||||
CEntity c3 = new CEntity();
|
CEntity c3 = new CEntity();
|
||||||
c3.setId( 3 );
|
c3.setId( offset + 3 );
|
||||||
c3.setLabel( "C3" );
|
c3.setLabel( "C3" );
|
||||||
|
|
||||||
entityManager.persist( c3 );
|
entityManager.persist( c3 );
|
||||||
|
|
||||||
c1.setC( c2 );
|
CEntity c4 = new CEntity();
|
||||||
c2.setC( c3 );
|
c4.setId( offset + 4 );
|
||||||
|
c4.setLabel( "C4" );
|
||||||
|
|
||||||
int id = 5;
|
entityManager.persist( c4 );
|
||||||
for ( int i = 0; i < 10; i++ ) {
|
|
||||||
DEntity dn = new DEntity();
|
|
||||||
dn.setId( id++ );
|
|
||||||
dn.setLabel( "label" );
|
|
||||||
dn.setE( e3 );
|
|
||||||
entityManager.persist( dn );
|
|
||||||
}
|
|
||||||
|
|
||||||
} );
|
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
|
@Test
|
||||||
|
@ -284,10 +295,91 @@ public class LoadAndFetchGraphTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
assertTrue( Hibernate.isInitialized( cEntity.getC().getA() ) );
|
assertTrue( Hibernate.isInitialized( cEntity.getC().getA() ) );
|
||||||
assertFalse( Hibernate.isInitialized( cEntity.getC().getC() ) );
|
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() );
|
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")
|
@Entity(name = "AEntity")
|
||||||
@Table(name = "A")
|
@Table(name = "A")
|
||||||
public static class AEntity {
|
public static class AEntity {
|
||||||
|
|
Loading…
Reference in New Issue