JPA Always Best Trick — DTO Via Constructor And Spring Data Query Builder Mechanism
Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on constructor and Spring Data Query Builder Mechanism.
Key points:
- write a proper constructor in the DTO class
- rely on Spring Data Query Builder Mechanism to write the SQL
- for using Spring Data Projections check this item.
Author.java
@Data
@Entity
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int age;
private String name;
private String genre;
}
AuthorRepository.java
@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
@Transactional(readOnly = true)
List<AuthorDto> findByGenre(String genre);
}
BookStoreService.java
@Service
@RequiredArgsConstructor
public class BookstoreService {
private final AuthorRepository authorRepository;
public List<AuthorDto> fetchByGenre() {
return authorRepository.findByGenre("Anthology");
}
}
AuthorDto.java
@Getter
@ToString
@AllArgsConstructor
public class AuthorDto implements Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final int age;
}
MainApp.java
@SpringBootApplication
@RequiredArgsConstructor
public class MainApplication {
private final BookstoreService bookstoreService;
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
@Bean
public ApplicationRunner init() {
return args -> {
List<AuthorDto> authors = bookstoreService.fetchByGenre();
System.out.println("Number of authors:" + authors.size());
for (AuthorDto author : authors) {
System.out.println("Author name: " + author.getName() + " | Age: " + author.getAge());
}
};
}
}
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/bookstoredb?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.datasource.initialization-mode=always
spring.datasource.platform=mysql
spring.jpa.open-in-view=false
data-mysql.sql
insert into author (age, name, genre, id) values (23, "Mark Janel", "Anthology", 1);
insert into author (age, name, genre, id) values (43, "Olivia Goy", "Horror", 2);
insert into author (age, name, genre, id) values (51, "Quartis Young", "Anthology", 3);
insert into author (age, name, genre, id) values (34, "Joana Nimar", "History", 4);
insert into author (age, name, genre, id) values (38, "Alicia Tom", "Anthology", 5);
insert into author (age, name, genre, id) values (56, "Katy Loin", "Anthology", 6);
Output.console
Hibernate: select author0_.name as col_0_0_, author0_.age as col_1_0_ from author author0_
Number of authors:6
Author name: Mark Janel | Age: 23
Author name: Olivia Goy | Age: 43
Author name: Quartis Young | Age: 51
Author name: Joana Nimar | Age: 34
Author name: Alicia Tom | Age: 38
Author name: Katy Loin | Age: 56
— — — — — — — — — — — — — — — — — — — — — — — — -
How To Fetch DTO Via Constructor Expression and JPQL
Description: Fetching more data than needed is prone to performance penalities. Using DTO allows us to extract only the needed data. In this application we rely on Constructor Expression and JPQL.
Key points:
- write a proper constructor in the DTO class
- use a query as
SELECT new com.bookstore.dto.AuthorDto(a.name, a.age) FROM Author a
- for using Spring Data Projections check this item
AuthorDto.java
@Getter
public class AuthorDto implements Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final int age;
public AuthorDto(String name, int age) {
this.name = name;
this.age = age;
}
}
AuthorRepository.java
@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {
@Transactional(readOnly = true)
@Query(value = "SELECT new com.bookstore.dto.AuthorDto(a.name, a.age) FROM Author a")
List<AuthorDto> fetchAuthors();
}
BookService.java
@RequiredArgsConstructor
@Service
public class BookstoreService {
private final AuthorRepository authorRepository;
public List<AuthorDto> fetchAuthors() {
return authorRepository.fetchAuthors();
}
}
Author.java
@Data
@Entity
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int age;
private String name;
private String genre;
}
MainApp.java
@RequiredArgsConstructor
@SpringBootApplication
public class MainApplication {
private final BookstoreService bookstoreService;
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
@Bean
public ApplicationRunner init() {
return args -> {
List<AuthorDto> authors = bookstoreService.fetchAuthors();
System.out.println("Number of authors:" + authors.size());
System.out.println("---------------------------");
for (AuthorDto author : authors) {
System.out.println("Author name: " + author.getName() + " | Age: " + author.getAge());
}
};
}
}
Console
Number of authors:6
---------------------------
Author name: Mark Janel | Age: 23
Author name: Olivia Goy | Age: 43
Author name: Quartis Young | Age: 51
Author name: Joana Nimar | Age: 34
Author name: Alicia Tom | Age: 38
Author name: Katy Loin | Age: 56
— — — — — — — — — — — — — — — — — — — — — — — — — — — — -