Different Ways to Retrieve JPA Entity Objects from Database

In this article, we will discuss various ways to retrieve objects from the database.
The Java Persistence API (JPA) provides various ways to retrieve objects from the database. The retrieval of objects does not require an active transaction because it does not change the content of the database.
Learn complete JPA at JPA Tutorial - Java Persistence API
Learn Hibernate ORM Framework at Hibernate Tutorial
The persistence context serves as a cache of retrieved entity objects. If a requested entity object is not found in the persistence context a new object is constructed and filled with data that is retrieved from the database. The new entity object is then added to the persistence context as a managed entity object and returned to the application.
This article covers the following topics:
  1. Retrieval by Class and Primary Key
  2. Retrieval by Eager Fetch
  3. Retrieval by Query
  4. Retrieval by Refresh
  5. Cascading Refresh

1. Retrieval by Class and Primary Key

Every entity object can be uniquely identified and retrieved by the combination of its class and its primary key. Given an EntityManager entityManager, the following code fragment demonstrates retrieval of a Student object whose primary key is 1:
private static void findEntity() {
 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PERSISTENCE");
 EntityManager entityManager = entityManagerFactory.createEntityManager();
 entityManager.getTransaction().begin();
 Student student = entityManager.find(Student.class, 1);
 System.out.println("student id :: " + student.getId());
 System.out.println("student firstname :: " + student.getFirstName());
 System.out.println("student lastname :: " + student.getLastName());
 System.out.println("student email :: " + student.getEmail());
 entityManager.getTransaction().commit();
 entityManager.close();
}
The casting of the retrieved object to Student is not required because find is defined as returning an instance of the same class that it takes as a first argument (using generics). An IllegalArgumentException is thrown if the specified class is not an entity class.
A similar method, getReference, can be considered the lazy version of find:
private static void getReference() {
 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PERSISTENCE");
 EntityManager entityManager = entityManagerFactory.createEntityManager();
 entityManager.getTransaction().begin();
 Student student = entityManager.getReference(Student.class, 1);
 System.out.println("student id :: " + student.getId());
 System.out.println("student firstname :: " + student.getFirstName());
 System.out.println("student lastname :: " + student.getLastName());
 System.out.println("student email :: " + student.getEmail());
 entityManager.getTransaction().commit();
 entityManager.close();
}
The getReference method works like the find method except that if the entity object is not already managed by the EntityManager a hollow object might be returned (null is never returned). A hollow object is initialized with the valid primary key but all its other persistent fields are uninitialized.

2. Retrieval by Eager Fetch

Retrieval of an entity object from the database might cause automatic retrieval of additional entity objects.
The default fetch policy of persistent collection and map fields is FetchType.LAZY. Therefore, by default, when an entity object is retrieved any other entity objects that it references through its collection and map fields are not retrieved with it.
In the following example, the Instructor has one-to-many relationships with Courses. Note that by default fetch type is LAZY and when we retrieve an Instructor then it's courses can't be retrieved:

Instructor.java

@Entity
@Table(name="instructor")
public class Instructor {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="id")
 private int id;
 
 @Column(name="first_name")
 private String firstName;
 
 @Column(name="last_name")
 private String lastName;

 @Column(name="email")
 private String email;
 
 @OneToOne(cascade=CascadeType.ALL)
 @JoinColumn(name="instructor_detail_id")
 private InstructorDetail instructorDetail;
 
 @OneToMany(fetch=FetchType.LAZY, mappedBy="instructor",
      cascade= {CascadeType.PERSIST, CascadeType.MERGE,
       CascadeType.DETACH, CascadeType.REFRESH})
 private List<Course> courses;
        
        // getters and setters
}

Course.java

@Entity
@Table(name="course")
public class Course {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="id")
 private int id;
 
 @Column(name="title")
 private String title;
 
 @ManyToOne(cascade=CascadeType.ALL)
 @JoinColumn(name="instructor_id")
 private Instructor instructor;
       
       // getter and setters
}
The default fetch type can be changed by an explicit FetchType.EAGER setting:
@Entity
@Table(name="instructor")
public class Instructor {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="id")
 private int id;
 
 @Column(name="first_name")
 private String firstName;
 
 @Column(name="last_name")
 private String lastName;

 @Column(name="email")
 private String email;
 
 @OneToOne(cascade=CascadeType.ALL)
 @JoinColumn(name="instructor_detail_id")
 private InstructorDetail instructorDetail;
 
 @OneToMany(fetch=FetchType.EAGER, mappedBy="instructor",
      cascade= {CascadeType.PERSIST, CascadeType.MERGE,
       CascadeType.DETACH, CascadeType.REFRESH})
 private List<Course> courses;
        
        // getters and setters
}
Specifying FetchType.EAGER explicitly in @OneToMany or @ManyToMany annotations enables cascading retrieval for the field. In the above example, when an Instructor instance is retrieved all the referenced Courses instances are also retrieved automatically.

3. Retrieval by Query

The most flexible method for retrieving objects from the database is to use queries. The official query language of JPA is JPQL (Java Persistence Query Language). It enables retrieval of objects from the database by using simple queries as well as complex, sophisticated ones.
Example: Retrieve multiple records:
Query query = em.createQuery("SELECT c FROM Country c");
List results = query.getResultList();
Example: Retrieve single column data:
 TypedQuery<Long> query = em.createQuery(
      "SELECT COUNT(c) FROM Country c", Long.class);
  long countryCount = query.getSingleResult();

4. Retrieval by Refresh

Managed objects can be reloaded from the database by using the refresh method:
entityManager.refresh(student);
The content of the managed object in memory is discarded (including changes, if any) and replaced by data that is retrieved from the database. This might be useful to ensure that the application deals with the most up to date version of an entity object, just in case it might have been changed by another EntityManager since it was retrieved.
An IllegalArgumentException is thrown by refresh if the argument is not a managed entity (including entity objects in the New, Removed or Detached states). If the object does not exist in the database anymore an EntityNotFoundException is thrown.

5. Cascading Refresh

Marking a reference field with CascadeType.REFRESH (or CascadeType.ALL, which includes REFRESH) indicates that refresh operations should be cascaded automatically to entity objects that are referenced by that field (multiple entity objects can be referenced by a collection field):
@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REFRESH)
    private Address address;
     :
}
Refer complete JPA CRUD operations example at JPA CRUD Example.
Learn complete JPA at JPA Tutorial - Java Persistence API
Learn Hibernate ORM Framework at Hibernate Tutorial

Related Articles

Comments