JPA Always Best Trick — DTO Via Constructor And Spring Data Query Builder Mechanism

Prateek
3 min readJul 1, 2021

--

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

— — — — — — — — — — — — — — — — — — — — — — — — — — — — -

--

--

Prateek
Prateek

Written by Prateek

Java Developer and enthusiast

No responses yet