BAEL-7282: Getting all results at once in a paged query method (#15761)
This commit is contained in:
parent
c150165e03
commit
7055bb3f6b
@ -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>
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.baeldung.paging;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface StudentRepository extends JpaRepository<Student, String> {
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
Loading…
x
Reference in New Issue
Block a user