BAEL-7282: Getting all results at once in a paged query method (#15761)

This commit is contained in:
Manfred 2024-02-07 01:52:45 +00:00 committed by GitHub
parent c150165e03
commit 7055bb3f6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 303 additions and 0 deletions

View File

@ -57,6 +57,17 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>${modelmapper.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
@ -76,6 +87,8 @@
<db.util.version>1.0.7</db.util.version>
<hypersistence-utils.version>3.7.0</hypersistence-utils.version>
<jackson.version>2.16.0</jackson.version>
<modelmapper.version>3.2.0</modelmapper.version>
<lombok.version>1.18.30</lombok.version>
</properties>
</project>

View File

@ -0,0 +1,13 @@
package com.baeldung.paging;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PagingApplication {
public static void main(String[] args) {
SpringApplication.run(PagingApplication.class, args);
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung.paging;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "school")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id"})
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "school_id")
private Integer id;
private String name;
}

View File

@ -0,0 +1,42 @@
package com.baeldung.paging;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "student")
@NamedEntityGraph(name = "Student.school", attributeNodes = @NamedAttributeNode("school"))
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id"})
public class Student {
@Id
@Column(name = "student_id")
private String id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school_id", referencedColumnName = "school_id")
private School school;
}

View File

@ -0,0 +1,14 @@
package com.baeldung.paging;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface StudentCustomQueryRepository extends JpaRepository<Student, String> {
@Query(value = "SELECT stu FROM Student stu LEFT JOIN FETCH stu.school ",
countQuery = "SELECT COUNT(stu) FROM Student stu")
Page<Student> findAll(Pageable pageable);
}

View File

@ -0,0 +1,22 @@
package com.baeldung.paging;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id"})
public class StudentDTO {
private String id;
private String firstName;
private String lastName;
}

View File

@ -0,0 +1,13 @@
package com.baeldung.paging;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentEntityGraphRepository extends JpaRepository<Student, String> {
@EntityGraph(attributePaths = "school")
Page<Student> findAll(Pageable pageable);
}

View File

@ -0,0 +1,13 @@
package com.baeldung.paging;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentNamedEntityGraphRepository extends JpaRepository<Student, String> {
@EntityGraph(value = "Student.school")
Page<Student> findAll(Pageable pageable);
}

View File

@ -0,0 +1,6 @@
package com.baeldung.paging;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<Student, String> {
}

View File

@ -0,0 +1,24 @@
package com.baeldung.paging;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id"})
public class StudentWithSchoolNameDTO {
private String id;
private String firstName;
private String lastName;
private String schoolName;
}

View File

@ -0,0 +1,103 @@
package com.baeldung.paging;
import com.baeldung.listvsset.util.TestConfig;
import io.hypersistence.utils.jdbc.validator.SQLStatementCountValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List;
import static io.hypersistence.utils.jdbc.validator.SQLStatementCountValidator.assertSelectCount;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@SpringBootTest(classes = {PagingApplication.class, TestConfig.class}, properties = {
"spring.jpa.show-sql=true",
"spring.jpa.properties.hibernate.format_sql=true",
"spring.jpa.generate-ddl=true",
"spring.jpa.defer-datasource-initialization=true",
"spring.sql.init.data-locations=classpath:school-student-data.sql"
})
@Transactional
class StudentRepositoryIntegrationTest {
@Autowired
private StudentRepository studentRepository;
@Autowired
private StudentCustomQueryRepository studentCustomQueryRepository;
@Autowired
private StudentEntityGraphRepository studentEntityGraphRepository;
@Autowired
private StudentNamedEntityGraphRepository studentNamedEntityGraphRepository;
private static final ModelMapper modelMapper = new ModelMapper();
@BeforeEach
void setUp() {
SQLStatementCountValidator.reset();
}
@Test
public void whenGetStudentsWithPageRequestOfTwo_thenReturnTwoRows() {
int rows = 2;
Pageable pageable = PageRequest.of(0, rows);
Page<Student> studentPage = studentRepository.findAll(pageable);
// Then
List<Student> studentList = studentPage.getContent();
assertThat(studentList.size()).isEqualTo(rows);
}
@Test
public void whenGetStudentsWithUnpagedAndSort_thenReturnAllResultsSorted() {
Sort sort = Sort.by(Sort.Direction.ASC, "lastName");
Pageable pageable = PageRequest.of(0, Integer.MAX_VALUE).withSort(sort);
Page<Student> studentPage = studentRepository.findAll(pageable);
// Then
List<Student> studentList = studentPage.getContent();
assertThat(studentList.size()).isEqualTo(studentPage.getTotalElements());
assertThat(studentList).isSortedAccordingTo(Comparator.comparing(Student::getLastName));
}
@Test
public void whenGetStudentsWithSchool_thenMultipleSelectQueriesAreExecuted() {
Page<Student> studentPage = studentRepository.findAll(Pageable.unpaged());
studentPage.get().map(student -> modelMapper.map(student, StudentWithSchoolNameDTO.class)).toList();
assertSelectCount(studentPage.getContent().size() + 1);
}
@Test
public void whenGetStudentsByCustomQuery_thenOneSelectQueryIsExecuted() {
Page<Student> studentPage = studentCustomQueryRepository.findAll(Pageable.unpaged());
studentPage.get().map(student -> modelMapper.map(student, StudentWithSchoolNameDTO.class)).toList();
assertSelectCount(1);
}
@Test
public void whenGetStudentsByEntityGraph_thenOneSelectQueryIsExecuted() {
Page<Student> studentPage = studentEntityGraphRepository.findAll(Pageable.unpaged());
studentPage.get().map(student -> modelMapper.map(student, StudentWithSchoolNameDTO.class)).toList();
assertSelectCount(1);
}
@Test
public void whenGetStudentsByNamedEntityGraph_thenOneSelectQueryIsExecuted() {
Page<Student> studentPage = studentNamedEntityGraphRepository.findAll(Pageable.unpaged());
studentPage.get().map(student -> modelMapper.map(student, StudentWithSchoolNameDTO.class)).toList();
assertSelectCount(1);
}
}

View File

@ -0,0 +1,9 @@
INSERT INTO school (name) VALUES ('Ada Lovelace CE High School');
INSERT INTO school (name) VALUES ('Ealing Fields High School');
INSERT INTO school (name) VALUES ('Northolt High School');
INSERT INTO school (name) VALUES ('Villiers High School');
INSERT INTO student(student_id, first_name, last_name, school_id) VALUES('23056746', 'James', 'Drover', 1);
INSERT INTO student(student_id, first_name, last_name, school_id) VALUES('23056751', 'Rubin', 'Webber', 2);
INSERT INTO student(student_id, first_name, last_name, school_id) VALUES('23063444', 'Sarah', 'Pelham', 3);
INSERT INTO student(student_id, first_name, last_name, school_id) VALUES('23065783', 'Lucy', 'Watson', 4);