Description: This application is a sample of fetching all attributes of an entity (Author) as a Spring projection (DTO). Commonly, a DTO contains a subset of attributes, but, sometimes we need to fetch the whole entity as a DTO. In such cases, we have to pay attention to the chosen approach. Choosing wisely can spare us from performance penalties.

Key points:

  • fetching the result set as a List<Object[]> or List<AuthorDto> via a JPQL of type SELECT a FROM Author a WILL fetch the result set as entities in Persistent Context as well - avoid this approach
  • fetching the result set as a List<Object[]> or List<AuthorDto> via a JPQL of type SELECT a.id AS id, a.name AS name, ... FROM Author a will NOT fetch the result set in Persistent Context - this is efficient
  • fetching the result set as a List<Object[]> or List<AuthorDto> via a native SQL of type SELECT id, name, age, ... FROM author will NOT fetch the result set in Persistent Context - but, this approach is pretty slow
  • fetching the result set as a List<Object[]> via Spring Data query builder mechanism WILL fetch the result set in Persistent Context - avoid this approach
  • fetching the result set as a List<AuthorDto> via Spring Data query builder mechanism will NOT fetch the result set in Persistent Context
  • fetching the result set as read-only entitites (e.g., via the built-in findAll() method) should be considered after JPQL with explicit list of columns to be fetched and query builder mechanism.

Author.java

@Data
@Entity
public class Author implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String genre;
private int age;
}

AuthorRepository.java

@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {

@Query("SELECT a FROM Author a")
List<Object[]> fetchAsArray();

@Query("SELECT a.id AS id, a.age AS age, a.name AS name, a.genre AS genre FROM Author a")
List<Object[]> fetchAsArrayColumns();

@Query(value = "SELECT id, age, name, genre FROM author", nativeQuery = true)
List<Object[]> fetchAsArrayNative();

List<Object[]> findFirstBy();

@Query("SELECT a FROM Author a")
List<AuthorDto> fetchAsDto();

@Query("SELECT a.id AS id, a.age AS age, a.name AS name, a.genre AS genre FROM Author a")
List<AuthorDto> fetchAsDtoColumns();

@Query(value = "SELECT id, age, name, genre FROM author", nativeQuery = true)
List<AuthorDto> fetchAsDtoNative();

List<AuthorDto> findBy();
}

BookStoreService.java

@RequiredArgsConstructor
@Service
public class BookstoreService {

private final AuthorRepository authorRepository;

@PersistenceContext
private final EntityManager entityManager;

@Transactional(readOnly = true)
public void fetchAuthorAsReadOnlyEntities() {
List<Author> authors = authorRepository.findAll();
authors.forEach(a -> System.out.println(a));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsArrayOfObject() {
List<Object[]> authors = authorRepository.fetchAsArray();
authors.forEach(a -> System.out.println(Arrays.toString(a)));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsArrayOfObjectColumns() {
List<Object[]> authors = authorRepository.fetchAsArrayColumns();
authors.forEach(a -> System.out.println(Arrays.toString(a)));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsArrayOfObjectNative() {
List<Object[]> authors = authorRepository.fetchAsArrayNative();
authors.forEach(a -> System.out.println(Arrays.toString(a)));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsArrayOfObjectQueryBuilderMechanism() {
List<Object[]> authors = authorRepository.findFirstBy();
authors.forEach(a -> System.out.println(Arrays.toString(a)));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsDtoClass() {
List<AuthorDto> authors = authorRepository.fetchAsDto();
authors.forEach(System.out::println);

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsDtoClassColumns() {
List<AuthorDto> authors = authorRepository.fetchAsDtoColumns();
authors.forEach(a -> System.out.println("Author{id=" + a.getId()
+ ", name=" + a.getName() + ", genre=" + a.getGenre()
+ ", age=" + a.getAge() + "}"));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorAsDtoClassNative() {
List<AuthorDto> authors = authorRepository.fetchAsDtoNative();
authors.forEach(a -> System.out.println("Author{id=" + a.getId()
+ ", name=" + a.getName() + ", genre=" + a.getGenre()
+ ", age=" + a.getAge() + "}"));

briefOverviewOfPersistentContextContent();
}

@Transactional(readOnly = true)
public void fetchAuthorByGenreAsDtoClassQueryBuilderMechanism() {
List<AuthorDto> authors = authorRepository.findBy();
authors.forEach(a -> System.out.println("Author{id=" + a.getId()
+ ", name=" + a.getName() + ", genre=" + a.getGenre()
+ ", age=" + a.getAge() + "}"));

briefOverviewOfPersistentContextContent();
}

private void briefOverviewOfPersistentContextContent() {
org.hibernate.engine.spi.PersistenceContext persistenceContext = getPersistenceContext();

int managedEntities = persistenceContext.getNumberOfManagedEntities();

System.out.println("\n-----------------------------------");
System.out.println("Total number of managed entities: " + managedEntities);

// getEntitiesByKey() will be removed and probably replaced with #iterateEntities()
Map<EntityKey, Object> entitiesByKey = persistenceContext.getEntitiesByKey();
entitiesByKey.forEach((key, value) -> System.out.println(key + ": " + value));

for (Object entry : entitiesByKey.values()) {
EntityEntry ee = persistenceContext.getEntry(entry);
System.out.println(
"Entity name: " + ee.getEntityName()
+ " | Status: " + ee.getStatus()
+ " | State: " + Arrays.toString(ee.getLoadedState()));
}
;

System.out.println("\n-----------------------------------\n");
}

private org.hibernate.engine.spi.PersistenceContext getPersistenceContext() {

SharedSessionContractImplementor sharedSession = entityManager.unwrap(
SharedSessionContractImplementor.class
);

return sharedSession.getPersistenceContext();
}

}

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.MySQL8Dialect

spring.jpa.open-in-view=false

spring.datasource.initialization-mode=always
spring.datasource.platform=mysql

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 (33, "Marin Kyrab", "History", 5);

MainApp.java

@SpringBootApplication
public class MainApplication {

@Autowired
private BookstoreService bookstoreService;

public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}

@Bean
public ApplicationRunner init() {
return args -> {
System.out.println("\n\n Fetch authors read-only entities:");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsReadOnlyEntities();

System.out.println("\n\n Fetch authors as array of objects");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsArrayOfObject();

System.out.println("\n\n Fetch authors as array of objects by specifying columns");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsArrayOfObjectColumns();

System.out.println("\n\n Fetch authors as array of objects via native query");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsArrayOfObjectNative();

System.out.println("\n\n Fetch authors as array of objects via query builder mechanism");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsArrayOfObjectQueryBuilderMechanism();

System.out.println("\n\n Fetch authors as Spring projection (DTO):");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsDtoClass();

System.out.println("\n\n Fetch authors as Spring projection (DTO) by specifying columns:");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsDtoClassColumns();

System.out.println("\n\n Fetch authors as Spring projection (DTO) and native query:");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorAsDtoClassNative();

System.out.println("\n\n Fetch authors as Spring projection (DTO) via query builder mechanism:");
System.out.println("-----------------------------------------------------------------------------");
bookstoreService.fetchAuthorByGenreAsDtoClassQueryBuilderMechanism();
};
}
}

--

--

--

Java Developer and enthusiast

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Securing a FastAPI route using JWT token (step-by-step)

Coroutines with Unity!

Knight Dialer

TryHackMe: Kenobi Walkthrough.

Go-Room: Internals

Multi-Factor Authentication System on Raspberry Pi over Cloud Network

Newbie’s Information: How one can Use Terra

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
PA

PA

Java Developer and enthusiast

More from Medium

JPA Key Notes

Spring Security

Using Java API

Build a Spring Boot REST API with Pagination and Sorting