Skip to content

Commit

Permalink
HHH-15449 Add test for issue
Browse files Browse the repository at this point in the history
  • Loading branch information
dreab8 committed Aug 24, 2022
1 parent 6507ac4 commit 960b2c7
Show file tree
Hide file tree
Showing 4 changed files with 745 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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;
}

}


}
Original file line number Diff line number Diff line change
@@ -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;
}

}


}

0 comments on commit 960b2c7

Please sign in to comment.