Merge remote-tracking branch 'upstream/master' into wip/6.0_merge_47
This commit is contained in:
commit
4550c70d15
|
@ -16,9 +16,8 @@ buildscript {
|
||||||
classpath 'gradle.plugin.com.github.lburgazzoli:gradle-karaf-plugin:0.5.1'
|
classpath 'gradle.plugin.com.github.lburgazzoli:gradle-karaf-plugin:0.5.1'
|
||||||
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.7'
|
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.7'
|
||||||
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
|
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
|
||||||
classpath 'de.thetaphi:forbiddenapis:2.7'
|
classpath 'de.thetaphi:forbiddenapis:3.0.1'
|
||||||
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.1'
|
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.1'
|
||||||
classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:4.2.0'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +26,7 @@ plugins {
|
||||||
id 'org.hibernate.build.xjc' version '2.0.1' apply false
|
id 'org.hibernate.build.xjc' version '2.0.1' apply false
|
||||||
id 'org.hibernate.build.maven-repo-auth' version '3.0.2' apply false
|
id 'org.hibernate.build.maven-repo-auth' version '3.0.2' apply false
|
||||||
id 'org.jetbrains.gradle.plugin.idea-ext' version '0.5'
|
id 'org.jetbrains.gradle.plugin.idea-ext' version '0.5'
|
||||||
|
id 'biz.aQute.bnd' version '5.1.1' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
|
|
@ -20,3 +20,9 @@ dependencies {
|
||||||
compile 'org.hibernate.build.gradle:gradle-animalSniffer-plugin:1.0.1.Final'
|
compile 'org.hibernate.build.gradle:gradle-animalSniffer-plugin:1.0.1.Final'
|
||||||
compile 'org.hibernate.build.gradle:hibernate-matrix-testing:3.0.0.Final'
|
compile 'org.hibernate.build.gradle:hibernate-matrix-testing:3.0.0.Final'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType( GroovyCompile ) {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
sourceCompatibility = 8
|
||||||
|
targetCompatibility = 8
|
||||||
|
}
|
||||||
|
|
|
@ -217,6 +217,14 @@ include::{sourcedir}/GraphFetchingTest.java[tags=fetching-strategies-dynamic-fet
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
When executing a JPQL query, if an EAGER association is omitted, Hibernate will issue a secondary select for every association needed to be fetched eagerly,
|
||||||
|
which can lead to N+1 query issues.
|
||||||
|
|
||||||
|
For this reason, it's better to use LAZY associations, and only fetch them eagerly on a per-query basis.
|
||||||
|
====
|
||||||
|
|
||||||
An EntityGraph is the root of a "load plan" and must correspond to an EntityType.
|
An EntityGraph is the root of a "load plan" and must correspond to an EntityType.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ buildscript {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'de.thetaphi:forbiddenapis:2.7'
|
classpath 'de.thetaphi:forbiddenapis:3.0.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
else
|
else
|
||||||
eval `echo args$i`="\"$arg\""
|
eval `echo args$i`="\"$arg\""
|
||||||
fi
|
fi
|
||||||
i=$((i+1))
|
i=`expr $i + 1`
|
||||||
done
|
done
|
||||||
case $i in
|
case $i in
|
||||||
(0) set -- ;;
|
0) set -- ;;
|
||||||
(1) set -- "$args0" ;;
|
1) set -- "$args0" ;;
|
||||||
(2) set -- "$args0" "$args1" ;;
|
2) set -- "$args0" "$args1" ;;
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -175,14 +175,9 @@ save () {
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
echo " "
|
echo " "
|
||||||
}
|
}
|
||||||
APP_ARGS=$(save "$@")
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
|
||||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|
|
@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
|
|
@ -1362,7 +1362,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
||||||
|
|
||||||
private Object getParentsByChild(Object childEntity) {
|
private Object getParentsByChild(Object childEntity) {
|
||||||
if ( parentsByChild != null ) {
|
if ( parentsByChild != null ) {
|
||||||
parentsByChild.get( childEntity );
|
return parentsByChild.get( childEntity );
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ public final class TwoPhaseLoad {
|
||||||
* Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
|
* Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
|
||||||
* to resolve any associations yet, because there might be other entities waiting to be
|
* to resolve any associations yet, because there might be other entities waiting to be
|
||||||
* read from the JDBC result set we are currently processing
|
* read from the JDBC result set we are currently processing
|
||||||
|
*
|
||||||
* @param persister The persister for the hydrated entity
|
* @param persister The persister for the hydrated entity
|
||||||
* @param id The entity identifier
|
* @param id The entity identifier
|
||||||
* @param values The entity values
|
* @param values The entity values
|
||||||
|
|
|
@ -0,0 +1,516 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.jpa.test.graphs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EntityGraph;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.graph.GraphSemantic;
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
* @author Nathan Xu
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-14097")
|
||||||
|
public class LoadAndFetchGraphTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
AEntity.class,
|
||||||
|
BEntity.class,
|
||||||
|
CEntity.class,
|
||||||
|
DEntity.class,
|
||||||
|
EEntity.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addConfigOptions(Map options) {
|
||||||
|
options.put( Environment.GENERATE_STATISTICS, "true" );
|
||||||
|
super.addConfigOptions( options );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory, entityManager -> {
|
||||||
|
AEntity a1 = new AEntity();
|
||||||
|
a1.setId( 1 );
|
||||||
|
a1.setLabel( "A1" );
|
||||||
|
|
||||||
|
AEntity a2 = new AEntity();
|
||||||
|
a2.setId( 2 );
|
||||||
|
a2.setLabel( "A2" );
|
||||||
|
|
||||||
|
entityManager.persist( a1 );
|
||||||
|
entityManager.persist( a2 );
|
||||||
|
|
||||||
|
BEntity b1 = new BEntity();
|
||||||
|
b1.setId( 1 );
|
||||||
|
b1.setLabel( "B1" );
|
||||||
|
|
||||||
|
BEntity b2 = new BEntity();
|
||||||
|
b2.setId( 2 );
|
||||||
|
b2.setLabel( "B2" );
|
||||||
|
|
||||||
|
entityManager.persist( b1 );
|
||||||
|
entityManager.persist( b2 );
|
||||||
|
|
||||||
|
EEntity e1 = new EEntity();
|
||||||
|
e1.setId( 1 );
|
||||||
|
e1.setLabel( "E1" );
|
||||||
|
|
||||||
|
EEntity e2 = new EEntity();
|
||||||
|
e2.setId( 2 );
|
||||||
|
e2.setLabel( "E2" );
|
||||||
|
|
||||||
|
EEntity e3 = new EEntity();
|
||||||
|
e3.setId( 3 );
|
||||||
|
e3.setLabel( "E3" );
|
||||||
|
|
||||||
|
EEntity e4 = new EEntity();
|
||||||
|
e4.setId( 4 );
|
||||||
|
e4.setLabel( "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 d2 = new DEntity();
|
||||||
|
d2.setId( 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 );
|
||||||
|
|
||||||
|
entityManager.persist( c1 );
|
||||||
|
|
||||||
|
DEntity d3 = new DEntity();
|
||||||
|
d3.setId( 3 );
|
||||||
|
d3.setLabel( "D3" );
|
||||||
|
d3.setE( e3 );
|
||||||
|
|
||||||
|
DEntity d4 = new DEntity();
|
||||||
|
d4.setId( 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 );
|
||||||
|
|
||||||
|
entityManager.persist( c2 );
|
||||||
|
|
||||||
|
CEntity c3 = new CEntity();
|
||||||
|
c3.setId( 3 );
|
||||||
|
c3.setLabel( "C3" );
|
||||||
|
|
||||||
|
entityManager.persist( c3 );
|
||||||
|
|
||||||
|
c1.setC( c2 );
|
||||||
|
c2.setC( c3 );
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryById() {
|
||||||
|
Statistics statistics = entityManagerFactory().unwrap( SessionFactory.class ).getStatistics();
|
||||||
|
statistics.clear();
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory, entityManager -> {
|
||||||
|
TypedQuery<CEntity> query = entityManager.createQuery(
|
||||||
|
"select c from CEntity as c where c.id = :cid ",
|
||||||
|
CEntity.class
|
||||||
|
);
|
||||||
|
query.setParameter( "cid", 1 );
|
||||||
|
CEntity cEntity = query.getSingleResult();
|
||||||
|
|
||||||
|
assertFalse( Hibernate.isInitialized( cEntity.getA() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( cEntity.getB() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( cEntity.getC() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( cEntity.getdList() ) );
|
||||||
|
|
||||||
|
assertEquals( 1L, statistics.getPrepareStatementCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryByIdWithLoadGraph() {
|
||||||
|
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 = :cid ",
|
||||||
|
CEntity.class
|
||||||
|
);
|
||||||
|
query.setHint( GraphSemantic.LOAD.getJpaHintName(), entityGraph );
|
||||||
|
query.setParameter( "cid", 1 );
|
||||||
|
|
||||||
|
CEntity cEntity = query.getSingleResult();
|
||||||
|
|
||||||
|
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() ) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
assertEquals( 1L, statistics.getPrepareStatementCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryByIdWithFetchGraph() {
|
||||||
|
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 = :cid ",
|
||||||
|
CEntity.class
|
||||||
|
);
|
||||||
|
query.setHint( GraphSemantic.FETCH.getJpaHintName(), entityGraph );
|
||||||
|
query.setParameter( "cid", 1 );
|
||||||
|
|
||||||
|
CEntity cEntity = query.getSingleResult();
|
||||||
|
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() ) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
assertEquals( 1L, statistics.getPrepareStatementCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryByIdWithFetchGraph2() {
|
||||||
|
Statistics statistics = entityManagerFactory().unwrap( SessionFactory.class ).getStatistics();
|
||||||
|
statistics.clear();
|
||||||
|
doInJPA(
|
||||||
|
this::entityManagerFactory, entityManager -> {
|
||||||
|
EntityGraph<CEntity> entityGraph = entityManager.createEntityGraph( CEntity.class );
|
||||||
|
entityGraph.addSubgraph( "c" ).addAttributeNodes( "a" );
|
||||||
|
|
||||||
|
TypedQuery<CEntity> query = entityManager.createQuery(
|
||||||
|
"select c from CEntity as c where c.id = :cid ",
|
||||||
|
CEntity.class
|
||||||
|
);
|
||||||
|
query.setHint( GraphSemantic.FETCH.getJpaHintName(), entityGraph );
|
||||||
|
query.setParameter( "cid", 1 );
|
||||||
|
|
||||||
|
CEntity cEntity = query.getSingleResult();
|
||||||
|
assertTrue( Hibernate.isInitialized( cEntity.getC() ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( cEntity.getC().getA() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( cEntity.getC().getC() ) );
|
||||||
|
|
||||||
|
assertEquals( 1L, statistics.getPrepareStatementCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "AEntity")
|
||||||
|
@Table(name = "A")
|
||||||
|
public static class AEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
fetch = FetchType.LAZY,
|
||||||
|
mappedBy = "a",
|
||||||
|
cascade = CascadeType.ALL,
|
||||||
|
orphanRemoval = true
|
||||||
|
)
|
||||||
|
private List<CEntity> cList = new ArrayList<>();
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "BEntity")
|
||||||
|
@Table(name = "B")
|
||||||
|
public static class BEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
fetch = FetchType.LAZY,
|
||||||
|
mappedBy = "b",
|
||||||
|
cascade = CascadeType.ALL,
|
||||||
|
orphanRemoval = true
|
||||||
|
)
|
||||||
|
private List<CEntity> cList = new ArrayList<>();
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "CEntity")
|
||||||
|
@Table(name = "C")
|
||||||
|
public static class CEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "A_ID")
|
||||||
|
private AEntity a;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "B_ID")
|
||||||
|
private BEntity b;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private CEntity c;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
fetch = FetchType.LAZY,
|
||||||
|
mappedBy = "c",
|
||||||
|
cascade = CascadeType.ALL,
|
||||||
|
orphanRemoval = true
|
||||||
|
)
|
||||||
|
private List<DEntity> dList = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addD(DEntity d) {
|
||||||
|
dList.add( d );
|
||||||
|
d.setC( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AEntity getA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setA(AEntity a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BEntity getB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setB(BEntity b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CEntity getC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setC(CEntity c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DEntity> getdList() {
|
||||||
|
return dList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setdList(List<DEntity> dList) {
|
||||||
|
this.dList = dList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "DEntity")
|
||||||
|
@Table(name = "D")
|
||||||
|
public static class DEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "C_ID")
|
||||||
|
private CEntity c;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "E_ID")
|
||||||
|
private EEntity e;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CEntity getC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setC(CEntity c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EEntity getE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setE(EEntity e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "EEntity")
|
||||||
|
@Table(name = "E")
|
||||||
|
public static class EEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
fetch = FetchType.LAZY,
|
||||||
|
mappedBy = "e",
|
||||||
|
cascade = CascadeType.ALL,
|
||||||
|
orphanRemoval = true
|
||||||
|
)
|
||||||
|
private List<DEntity> dList = new ArrayList<>();
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLabel(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.batchfetch;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.LockModeType;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.*;
|
||||||
|
|
||||||
|
public class BatchFetchRefreshTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
|
||||||
|
public void testRefreshWithBatch() {
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
|
||||||
|
// Retrieve one of the parents into the session.
|
||||||
|
Parent parent = session.find(Parent.class, 1);
|
||||||
|
Assert.assertNotNull(parent);
|
||||||
|
|
||||||
|
// Retrieve children but keep their parents lazy!
|
||||||
|
// This allows batch fetching to do its thing when we refresh below.
|
||||||
|
session.createQuery( "FROM Child" ).getResultList();
|
||||||
|
|
||||||
|
session.refresh( parent, LockModeType.PESSIMISTIC_WRITE );
|
||||||
|
|
||||||
|
// Just something to force delazification of children on parent entity
|
||||||
|
// The parent is obviously attached to the session (we just refreshed it!)
|
||||||
|
parent.getChildren().size();
|
||||||
|
|
||||||
|
// Another interesting thing to note - em.getLockMode returns an incorrect value after the above refresh
|
||||||
|
Assert.assertEquals( LockModeType.PESSIMISTIC_WRITE, session.getLockMode( parent ) );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setupData() {
|
||||||
|
final int numParents = 5;
|
||||||
|
final int childrenPerParent = 2;
|
||||||
|
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
int k = 1;
|
||||||
|
for ( int i = 1; i <= numParents; i++ ) {
|
||||||
|
Parent parent = new Parent();
|
||||||
|
parent.parentId = i;
|
||||||
|
parent.name = "Parent_" + i;
|
||||||
|
|
||||||
|
session.persist( parent );
|
||||||
|
|
||||||
|
// Create some children for each parent...
|
||||||
|
for ( int j = 0; j < childrenPerParent; j++,k++ ) {
|
||||||
|
Child child = new Child();
|
||||||
|
child.childId = k;
|
||||||
|
child.name = "Child_" + i + "_" + j;
|
||||||
|
child.age = 15;
|
||||||
|
child.parent = parent;
|
||||||
|
parent.getChildren().add( child );
|
||||||
|
session.persist( child );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
Parent.class,
|
||||||
|
Child.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
settings.put( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "8" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Parent")
|
||||||
|
public static class Parent {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "parent_id")
|
||||||
|
private int parentId;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "parent")
|
||||||
|
private Set<Child> children = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
public int getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Child> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildren(Set<Child> children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Child")
|
||||||
|
public static class Child {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "child_id")
|
||||||
|
private int childId;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
|
@JoinColumn(name = "parent_id")
|
||||||
|
private Parent parent;
|
||||||
|
|
||||||
|
@Column(name = "age")
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public int getChildId() {
|
||||||
|
return childId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Parent getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(Parent parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.bytecode.enhancement.lazy.proxy.batch;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToOne;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||||
|
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking.NoDirtyCheckEnhancementContext;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@RunWith(BytecodeEnhancerRunner.class)
|
||||||
|
@CustomEnhancementContext({ NoDirtyCheckEnhancementContext.class })
|
||||||
|
public abstract class AbstractBatchingTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
protected String childName = UUID.randomUUID().toString();
|
||||||
|
protected Long parentId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||||
|
ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" );
|
||||||
|
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources sources) {
|
||||||
|
sources.addAnnotatedClass( PaddedBatchingTest.ParentEntity.class );
|
||||||
|
sources.addAnnotatedClass( PaddedBatchingTest.ChildEntity.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadParent() {
|
||||||
|
StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||||
|
statistics.clear();
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
ParentEntity parentEntity = session.find( ParentEntity.class, parentId );
|
||||||
|
|
||||||
|
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
||||||
|
|
||||||
|
ChildEntity childEntity = parentEntity.getChildEntity();
|
||||||
|
|
||||||
|
assertFalse( Hibernate.isPropertyInitialized( childEntity, "name" ) );
|
||||||
|
assertEquals( childName, childEntity.getName() );
|
||||||
|
|
||||||
|
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
PaddedBatchingTest.ParentEntity parent = new PaddedBatchingTest.ParentEntity();
|
||||||
|
inTransaction(
|
||||||
|
session -> {
|
||||||
|
PaddedBatchingTest.ChildEntity childEntity = new PaddedBatchingTest.ChildEntity();
|
||||||
|
|
||||||
|
childEntity.setName( childName );
|
||||||
|
|
||||||
|
parent.setChildEntity( childEntity );
|
||||||
|
session.persist( parent );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
parentId = parent.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "ParentEntity")
|
||||||
|
public static class ParentEntity {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private ChildEntity childEntity;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JoinColumn(name = "FK_CHILD_ENTITY_ID", nullable = false)
|
||||||
|
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||||
|
public ChildEntity getChildEntity() {
|
||||||
|
return childEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildEntity(ChildEntity childEntity) {
|
||||||
|
this.childEntity = childEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "ChildEntity")
|
||||||
|
public static class ChildEntity {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.bytecode.enhancement.lazy.proxy.batch;
|
||||||
|
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.loader.BatchFetchStyle;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-14108")
|
||||||
|
public class DynamicBatchingTest extends AbstractBatchingTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.BATCH_FETCH_STYLE, BatchFetchStyle.DYNAMIC.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.bytecode.enhancement.lazy.proxy.batch;
|
||||||
|
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.loader.BatchFetchStyle;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-14108")
|
||||||
|
public class PaddedBatchingTest extends AbstractBatchingTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.applySetting( AvailableSettings.BATCH_FETCH_STYLE, BatchFetchStyle.PADDED.toString() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.inheritance;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.Query;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.hql.spi.id.inline.InlineIdsInClauseBulkIdStrategy;
|
||||||
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.DialectChecks;
|
||||||
|
import org.hibernate.testing.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@RequiresDialectFeature(DialectChecks.SupportsRowValueConstructorSyntaxInInListCheck.class)
|
||||||
|
@TestForIssue(jiraKey = "HHH-13214")
|
||||||
|
public class InheritanceDeleteBatchTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
TestEntity.class,
|
||||||
|
TestEntityType1.class,
|
||||||
|
TestEntityType2.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
configuration.setProperty(
|
||||||
|
AvailableSettings.HQL_BULK_ID_STRATEGY,
|
||||||
|
InlineIdsInClauseBulkIdStrategy.class.getName()
|
||||||
|
);
|
||||||
|
configuration.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
session.persist( new TestEntity( 1 ) );
|
||||||
|
session.persist( new TestEntityType1( 2 ) );
|
||||||
|
session.persist( new TestEntityType2( 3 ) );
|
||||||
|
session.persist( new TestEntityType2( 4 ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete() {
|
||||||
|
StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||||
|
statistics.clear();
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
for ( int i = 1; i <= 4; i++ ) {
|
||||||
|
Query deleteQuery = session.createQuery( "delete TestEntity e where e.id = :id" );
|
||||||
|
deleteQuery.setParameter( "id", i );
|
||||||
|
deleteQuery.executeUpdate();
|
||||||
|
assertThat( statistics.getPrepareStatementCount(), is( 4L ) );
|
||||||
|
statistics.clear();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TestEntity")
|
||||||
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
|
@Table(name = "test_entity")
|
||||||
|
public static class TestEntity {
|
||||||
|
@Id
|
||||||
|
int id;
|
||||||
|
|
||||||
|
private String field;
|
||||||
|
|
||||||
|
public TestEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestEntity(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TestEntityType1")
|
||||||
|
@Table(name = "test_entity_type1")
|
||||||
|
public static class TestEntityType1 extends TestEntity {
|
||||||
|
|
||||||
|
public TestEntityType1(int id) {
|
||||||
|
super( id );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TestEntityType2")
|
||||||
|
@Table(name = "test_entity_type2")
|
||||||
|
public static class TestEntityType2 extends TestEntity {
|
||||||
|
public TestEntityType2(int id) {
|
||||||
|
super( id );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,3 +21,9 @@ dependencies {
|
||||||
compile gradleApi()
|
compile gradleApi()
|
||||||
compile localGroovy()
|
compile localGroovy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType( GroovyCompile ) {
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
|
sourceCompatibility = project.baselineJavaVersion
|
||||||
|
targetCompatibility = project.baselineJavaVersion
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue