Enterprise Java

Retrieving Lists of Entities from a Database Using Hibernate

Hibernate is a powerful Object-Relational Mapping (ORM) framework for Java that simplifies the interaction between an application and a database through a powerful object-oriented API. One of the most common operations in any database-driven application is to fetch a list of entities. This article will explore various techniques for retrieving entity lists in Hibernate.

1. Mapping Database Tables to Entities

Before exploring the techniques for retrieving entities, it is crucial to understand how Hibernate maps database tables to Java entities. This mapping enables Hibernate to translate between database rows and Java objects seamlessly.

1.1 Entity Class Example

To illustrate, let’s define an entity class that maps to a database table. Consider a simple table book with columns id, title, and author.

CREATE TABLE book (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    author VARCHAR(255)
);

The corresponding Java entity class Book would look like this:

@Entity
public class Book {

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

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

Explanation:

  • @Entity: This annotation specifies that the class is an entity and is mapped to a database table.
  • @Id: This annotation specifies the primary key of the entity.
  • @GeneratedValue: This annotation provides the specification of generation strategies for the primary key values.
  • Long id: This field maps to the id column in the book table.
  • String title: This field maps to the title column in the book table.
  • String author: This field maps to the author column in the book table.

Hibernate uses these annotations to understand how the class and its fields relate to the corresponding database table and columns. Once the entity class is defined and mapped, Hibernate can handle the conversion between database rows and Java objects.

When a query is executed using HQL, Criteria API, or native SQL, Hibernate uses these mappings to convert the query into SQL statements that the database understands. It translates Java-based queries into SQL, retrieves the result set, and then maps the result back into Java objects.

2. Setting Up Hibernate

Add the following dependencies in your pom.xml if you are using Maven:

    <dependencies>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.6.4.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-spatial</artifactId>
            <version>5.6.4.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
    </dependencies>

2.1 Configuring Hibernate with persistence.xml

We can configure Hibernate using the persistence.xml file, which is part of the Jakarta Persistence API (JPA) standard. This file should be placed in the src/main/resources/META-INF directory.

2.1.1 Directory Structure

Here’s the typical structure of a Maven project with the persistence.xml file in the correct location:

Fig 1: Example Project Structure for Fetching Entity List with Java Hibernate
Fig 1: Example Project Structure for Fetching Entity List with Java Hibernate

Here’s an example of what the content might look like:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">

    <persistence-unit name="example-unit">
        <class>com.jcg.model.Book</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.cj.jdbc.Driver"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/yourdatabase"/>
            <property name="hibernate.connection.username" value="yourusername"/>
            <property name="hibernate.connection.password" value="yourpassword"/>
            <property name="hibernate.hbm2ddl.auto" value="none"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

With this setup complete, let’s explore various techniques for retrieving lists of entities.

3. Using JPQL (Java Persistence Query Language)

JPQL uses a syntax similar to SQL, but instead of working with tables and columns, it works with entities and their attributes. This makes the queries easier to read and build.

Example:

public class JPQLExample {

    public static void main(String[] args) {
        // Load configuration and build EntityManagerFactory
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
        
        // Obtain EntityManager and start transaction
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        
        // JPQL query to retrieve all books
        List<Book> bookList = em.createQuery("SELECT b FROM Book b", Book.class).getResultList();
        
        // Print the result
        for (Book book : bookList) {
            System.out.println("Book ID: " + book.getId() + ", Title: " + book.getTitle() + ", Author: " + book.getAuthor());
        }
        
        // Commit transaction and close EntityManager
        em.getTransaction().commit();
        em.close();
        emf.close();
    }
}

In this example, we obtain an EntityManager instance to interact with the persistence context. The JPQL query string SELECT b FROM Book b instructs Hibernate to select all Book entities from the database. We create a query object using em.createQuery and specify the JPQL string and the expected result type (Book.class). The getResultList() method executes the query and returns a list of Book objects.

4. Criteria API

The Criteria API uses an object-oriented method to build queries. It leverages Java classes and methods to express query logic, making it ideal for dynamic queries.

Example:

public class CriteriaAPIExample {

    public static void main(String[] args) {
        // Load configuration and build EntityManagerFactory
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");   
        
        // Obtain EntityManager and start transaction
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        
        // Create CriteriaBuilder and CriteriaQuery
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
        CriteriaQuery<Book> criteriaQuery = criteriaBuilder.createQuery(Book.class);
        
        // Define the root of the query
        Root<Book> root = criteriaQuery.from(Book.class);
        criteriaQuery.select(root);
        
        // Execute the query and get the result list
        List<Book> bookList = em.createQuery(criteriaQuery).getResultList();
        
        // Print the result
        for (Book book : bookList) {
            System.out.println("Book ID: " + book.getId() + ", Title: " + book.getTitle() + ", Author: " + book.getAuthor());
        }
        
        // Commit transaction and close EntityManager
        em.getTransaction().commit();
        em.close();
        emf.close();
    }
}

In this example, we use the Criteria API to build and execute a query to retrieve all Book objects from the database. After obtaining an EntityManager instance, a CriteriaBuilder is used to create criteria objects. We define a CriteriaQuery specifying the result type (Book.class). The from method establishes the root entity (Book). Finally, the criteria query is converted to a standard query using em.createQuery and executed with getResultList.

5. Native SQL Queries

For specific database functionalities or performance optimizations, Hibernate allows the execution of raw SQL queries.

Example:

public class NativeSQLExample {

    public static void main(String[] args) {
        // Load configuration and build EntityManagerFactory
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
        
        // Obtain EntityManager and start transaction
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        
        // Native SQL query to retrieve all books
        List<Book> books = em.createNativeQuery("SELECT * FROM book").getResultList();
        
        // Print the result
        for (Book book : books) {
            System.out.println("Book ID: " + book.getId() + ", Title: " + book.getTitle() + ", Author: " + book.getAuthor());
        }
        
        // Commit transaction and close EntityManager
        em.getTransaction().commit();
        em.close();
        emf.close();
    }
}


In this example, we use a native SQL query SELECT * FROM book to fetch all records from the book table. The query is executed with getResultList to retrieve a list of Book objects.

6. Accessing the Collection of Associated Entities from the Parent Entity

In many cases, entities have relationships with other entities, such as one-to-many or many-to-many associations. Hibernate provides a straightforward way to access collections of associated entities from the parent entity. For example, Let’s extend our Book entity to include a collection of Review entities. Assume we have a Review table and entity defined as follows:

CREATE TABLE review (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    book_id BIGINT,
    content TEXT,
    FOREIGN KEY (book_id) REFERENCES book(id)
);

6.1 Review Entity Class

@Entity
public class Review implements Serializable {

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

    private String content;

    @ManyToOne
    @JoinColumn(name = "book_id")
    private Book book;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }
}

6.2 Update Book Entity Class

Add a collection of Review entities to the Book class:

@Entity
public class Book implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String author;
    
    @OneToMany(mappedBy = "book", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Review> reviews;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public List<Review> getReviews() {
        return reviews;
    }

    public void setReviews(List<Review> reviews) {
        this.reviews = reviews;
    }
    
}

In the above example, the @OneToMany relationship is configured with fetch = FetchType.EAGER, therefore the associated entity will be fetched immediately with the parent entity.

6.2.1 Example of Fetch Book with Reviews

Let’s examine an example demonstrating how to use parameterized JPQL queries to fetch an entity by a specific criterion and access its associated collections. We will fetch the related reviews using the getReviews method.

public class FetchBookByTitle {

    public static void main(String[] args) {
        // Load configuration and build EntityManagerFactory
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");

        // Obtain EntityManager and start transaction
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        try {
            // JPQL query to fetch book by title
            String jpql = "SELECT b FROM Book b WHERE b.title = :title";
            TypedQuery<Book> query = em.createQuery(jpql, Book.class);
            query.setParameter("title", "The Great Gatsby");

            // Get single result
            Book book = query.getSingleResult();

            // Print the book details
            System.out.println("Book ID: " + book.getId() + ", Title: " + book.getTitle() + ", Author: " + book.getAuthor());

            // Print the associated reviews
            List<Review> reviews = book.getReviews();
            for (Review review : reviews) {
                System.out.println("Review ID: " + review.getId() + ", Content: " + review.getContent());
            }

        } catch (Exception e) {
        } finally {
            // Commit transaction and close EntityManager
            em.getTransaction().commit();
            em.close();
            emf.close();
        }
    }
}

In this example, we fetch a Book entity along with its associated Review entities. The JPQL query SELECT b FROM Book b WHERE b.title = :title is defined to fetch a book by its title. The :title parameter is a placeholder for the actual title value. The setParameter method is used to set the value of the title parameter. In this case, it’s set to "The Great Gatsby". The getSingleResult() method is used to execute the query and retrieve a single Book entity. The getReviews method of the Book entity is called to retrieve the list of associated Review entities.

7. Conclusion

Retrieving lists of entities from a database is a common operation in any application using Hibernate. We have explored three different techniques. Each technique has its advantages and use cases, and understanding these will help you choose the right approach for your specific needs. With the provided examples and explanations, you should now be able to retrieve lists of entities from your database using Hibernate effectively.

8. Download the Source Code

This was an article on using Java hibernate to fetch an entity List.

Download
You can download the full source code of this example here: Java Hibernate fetch entity list

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button