Merge remote-tracking branch 'upstream/master' into wip/6.0_merge_47

This commit is contained in:
Andrea Boriero 2020-07-20 10:50:17 +01:00
commit 4550c70d15
17 changed files with 1054 additions and 23 deletions

View File

@ -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 {

View File

@ -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
}

View File

@ -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.

View File

@ -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.

View File

@ -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

29
gradlew vendored
View File

@ -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" "$@"

3
gradlew.bat vendored
View File

@ -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"

View File

@ -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;
} }

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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() );
}
}

View File

@ -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() );
}
}

View File

@ -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 );
}
}
}

View File

@ -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
}