HHH-15449 Add test for issue

This commit is contained in:
Andrea Boriero 2022-08-16 20:32:53 +02:00 committed by Andrea Boriero
parent 6507ac4f88
commit 960b2c7f1c
4 changed files with 745 additions and 0 deletions

View File

@ -0,0 +1,220 @@
/*
* 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.orm.test.batchfetch;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.hibernate.Hibernate;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DomainModel(
annotatedClasses = { EagerManyToOneStreamTest.Child.class, EagerManyToOneStreamTest.Parent.class }
)
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
@ServiceRegistry(settings = @Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "2"))
@JiraKey("HHH-15449")
public class EagerManyToOneStreamTest {
public static final String FIELD_VALUE = "a field";
public static final String FIELD_VALUE_2 = "a second field";
@BeforeEach
public void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Parent parent = new Parent( FIELD_VALUE );
session.persist( parent );
session.persist( new Child( parent ) );
Parent parent2 = new Parent( FIELD_VALUE_2 );
session.persist( parent2 );
session.persist( new Child( parent2 ) );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete from Child" ).executeUpdate();
session.createMutationQuery( "delete from Parent" ).executeUpdate();
}
);
}
@Test
public void testGetResultStreamCollectSingleResult(SessionFactoryScope scope) {
final SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c where c.parent.someField=:someField", Child.class )
.setParameter( "someField", FIELD_VALUE );
Stream<Child> resultStream = query.getResultStream();
List<Child> children = resultStream.collect( Collectors.toList() );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
assertThat( children.size() ).isEqualTo( 1 );
Parent parent = children.get( 0 ).getParent();
assertThat( parent ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isTrue();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
assertThat( parent.getSomeField() ).isEqualTo( FIELD_VALUE );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
}
);
}
@Test
public void testGetResultStreamCollect(SessionFactoryScope scope) {
final SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c ", Child.class );
Stream<Child> resultStream = query.getResultStream();
List<Child> children = resultStream.collect( Collectors.toList() );
// with Stream the association is not batch loaded
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 3 );
assertThat( children.size() ).isEqualTo( 2 );
Parent parent = children.get( 0 ).getParent();
assertThat( parent ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isTrue();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 3 );
assertThat( parent.getSomeField() ).isEqualTo( FIELD_VALUE );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 3 );
Parent parent1 = children.get( 1 ).getParent();
assertThat( parent1 ).isNotNull();
assertThat( Hibernate.isInitialized( parent1 ) ).isTrue();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 3 );
assertThat( parent1.getSomeField() ).isEqualTo( FIELD_VALUE_2 );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 3 );
}
);
}
@Test
public void testGetResultStreamForEach(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c", Child.class );
query.getResultStream().forEach(
child -> assertThat( child.getParent() ).isNotNull()
);
}
);
}
@Test
public void testGetResultStreamFindFirst(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c where c.parent.someField=:someField", Child.class )
.setParameter( "someField", FIELD_VALUE );
Stream<Child> resultStream = query.getResultStream();
Optional<Child> child = resultStream.findFirst();
assertThat( child.isEmpty() ).isFalse();
assertThat( child.get().getParent() ).isNotNull();
}
);
}
@Entity(name = "Child")
@Table(name = "CHILD_TABLE")
public static class Child {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "parent_id", nullable = false, updatable = false)
private Parent parent;
public Child() {
}
public Child(Parent parent) {
this.parent = parent;
}
public Parent getParent() {
return parent;
}
public Long getId() {
return id;
}
}
@Entity(name = "Parent")
@Table(name = "PARENT_TABLE")
public static class Parent {
@Id
@GeneratedValue
private Long id;
private String someField;
public Parent() {
}
public Parent(String someField) {
this.someField = someField;
}
public String getSomeField() {
return someField;
}
public Long getId() {
return id;
}
}
}

View File

@ -0,0 +1,157 @@
/*
* 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.orm.test.batchfetch;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.query.Query;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DomainModel(
annotatedClasses = { EagerManyToOneTest.Child.class, EagerManyToOneTest.Parent.class }
)
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
@ServiceRegistry(settings = @Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "2"))
@JiraKey("HHH-15449")
public class EagerManyToOneTest {
public static final String FIELD_VALUE = "a field";
public static final String FIELD_VALUE_2 = "a second field";
@BeforeEach
public void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Parent parent = new Parent( FIELD_VALUE );
session.persist( parent );
session.persist( new Child( parent ) );
Parent parent2 = new Parent( FIELD_VALUE_2 );
session.persist( parent2 );
session.persist( new Child( parent2 ) );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete from Child" ).executeUpdate();
session.createMutationQuery( "delete from Parent" ).executeUpdate();
}
);
}
@Test
public void testGetResultList(SessionFactoryScope scope) {
final SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query<Child> query = session
.createQuery( "select c from Child as c ", Child.class );
List<Child> resultList = query.getResultList();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
Parent parent = resultList.get( 0 ).getParent();
assertThat( parent ).isNotNull();
Parent parent1 = resultList.get( 1 ).getParent();
assertThat( parent1 ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isTrue();
assertThat( Hibernate.isInitialized( parent1 ) ).isTrue();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
assertThat( parent.getSomeField() ).isEqualTo( FIELD_VALUE );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
assertThat( parent1.getSomeField() ).isEqualTo( FIELD_VALUE_2 );
// parent2 has been batch loaded
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
}
);
}
@Entity(name = "Child")
@Table(name = "CHILD_TABLE")
public static class Child {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "parent_id", nullable = false, updatable = false)
private Parent parent;
public Child() {
}
public Child(Parent parent) {
this.parent = parent;
}
public Parent getParent() {
return parent;
}
public Long getId() {
return id;
}
}
@Entity(name = "Parent")
@Table(name = "PARENT_TABLE")
public static class Parent {
@Id
@GeneratedValue
private Long id;
private String someField;
public Parent() {
}
public Parent(String someField) {
this.someField = someField;
}
public String getSomeField() {
return someField;
}
public Long getId() {
return id;
}
}
}

View File

@ -0,0 +1,211 @@
/*
* 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.orm.test.batchfetch;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.hibernate.Hibernate;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DomainModel(
annotatedClasses = { LazyManyToOneStreamTest.Child.class, LazyManyToOneStreamTest.Parent.class }
)
@SessionFactory( statementInspectorClass = SQLStatementInspector.class)
@ServiceRegistry(settings = @Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "2"))
@JiraKey("HHH-15449")
public class LazyManyToOneStreamTest {
public static final String FIELD_VALUE = "a field";
public static final String FIELD_VALUE_2 = "a second field";
@BeforeEach
public void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Parent parent = new Parent( FIELD_VALUE );
session.persist( parent );
session.persist( new Child( parent ) );
Parent parent2 = new Parent( FIELD_VALUE_2 );
session.persist( parent2 );
session.persist( new Child( parent2 ) );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete from Child" ).executeUpdate();
session.createMutationQuery( "delete from Parent" ).executeUpdate();
}
);
}
@Test
public void testGetResultStreamCollectSingleResult(SessionFactoryScope scope) {
final SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c where c.parent.someField=:someField", Child.class )
.setParameter( "someField", FIELD_VALUE );
Stream<Child> resultStream = query.getResultStream();
List<Child> children = resultStream.collect( Collectors.toList() );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 1 );
assertThat( children.size() ).isEqualTo( 1 );
Parent parent = children.get( 0 ).getParent();
assertThat( parent ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isFalse();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 1 );
assertThat( parent.getSomeField() ).isEqualTo( FIELD_VALUE );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
}
);
}
@Test
public void testGetResultStreamCollect(SessionFactoryScope scope) {
final SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c order by id", Child.class );
Stream<Child> resultStream = query.getResultStream();
List<Child> children = resultStream.collect( Collectors.toList() );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 1 );
assertThat( children.size() ).isEqualTo( 2 );
Parent parent = children.get( 0 ).getParent();
assertThat( parent ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isFalse();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 1 );
assertThat( parent.getSomeField() ).isEqualTo( FIELD_VALUE );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
Parent parent1 = children.get( 1 ).getParent();
assertThat( parent1 ).isNotNull();
// parent2 has been batch loaded
assertThat( Hibernate.isInitialized( parent1 ) ).isTrue();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
assertThat( parent1.getSomeField() ).isEqualTo( FIELD_VALUE_2 );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
}
);
}
@Test
public void testGetResultStreamFindFirst(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
QueryImplementor<Child> query = session
.createQuery( "select c from Child as c where c.parent.someField=:someField", Child.class )
.setParameter( "someField", FIELD_VALUE );
Stream<Child> resultStream = query.getResultStream();
Optional<Child> child = resultStream.findFirst();
assertThat( child.isEmpty() ).isFalse();
Parent parent = child.get().getParent();
assertThat( parent ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isFalse();
}
);
}
@Entity(name = "Child")
@Table(name = "CHILD_TABLE")
public static class Child {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id", nullable = false, updatable = false)
private Parent parent;
public Child() {
}
public Child(Parent parent) {
this.parent = parent;
}
public Parent getParent() {
return parent;
}
public Long getId() {
return id;
}
}
@Entity(name = "Parent")
@Table(name = "PARENT_TABLE")
public static class Parent {
@Id
@GeneratedValue
private Long id;
private String someField;
public Parent() {
}
public Parent(String someField) {
this.someField = someField;
}
public String getSomeField() {
return someField;
}
public Long getId() {
return id;
}
}
}

View File

@ -0,0 +1,157 @@
/*
* 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.orm.test.batchfetch;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.query.Query;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DomainModel(
annotatedClasses = { LazyManyToOneTest.Child.class, LazyManyToOneTest.Parent.class }
)
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
@ServiceRegistry(settings = @Setting(name = AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, value = "2"))
@JiraKey("HHH-15449")
public class LazyManyToOneTest {
public static final String FIELD_VALUE = "a field";
public static final String FIELD_VALUE_2 = "a second field";
@BeforeEach
public void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Parent parent = new Parent( FIELD_VALUE );
session.persist( parent );
session.persist( new Child( parent ) );
Parent parent2 = new Parent( FIELD_VALUE_2 );
session.persist( parent2 );
session.persist( new Child( parent2 ) );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete from Child" ).executeUpdate();
session.createMutationQuery( "delete from Parent" ).executeUpdate();
}
);
}
@Test
public void testGetResultList(SessionFactoryScope scope) {
final SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
sqlStatementInterceptor.clear();
scope.inTransaction(
session -> {
Query<Child> query = session
.createQuery( "select c from Child as c ", Child.class );
List<Child> resultList = query.getResultList();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 1 );
Parent parent = resultList.get( 0 ).getParent();
assertThat( parent ).isNotNull();
Parent parent1 = resultList.get( 1 ).getParent();
assertThat( parent1 ).isNotNull();
assertThat( Hibernate.isInitialized( parent ) ).isFalse();
assertThat( Hibernate.isInitialized( parent1 ) ).isFalse();
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 1 );
assertThat( parent.getSomeField() ).isEqualTo( FIELD_VALUE );
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
assertThat( parent1.getSomeField() ).isEqualTo( FIELD_VALUE_2 );
// parent2 has been batch loaded
assertThat( sqlStatementInterceptor.getSqlQueries().size() ).isEqualTo( 2 );
}
);
}
@Entity(name = "Child")
@Table(name = "CHILD_TABLE")
public static class Child {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id", nullable = false, updatable = false)
private Parent parent;
public Child() {
}
public Child(Parent parent) {
this.parent = parent;
}
public Parent getParent() {
return parent;
}
public Long getId() {
return id;
}
}
@Entity(name = "Parent")
@Table(name = "PARENT_TABLE")
public static class Parent {
@Id
@GeneratedValue
private Long id;
private String someField;
public Parent() {
}
public Parent(String someField) {
this.someField = someField;
}
public String getSomeField() {
return someField;
}
public Long getId() {
return id;
}
}
}