Retrieving JPA Entity Objects
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.
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 (or from the L2 cache - if enabled). The new entity object is then added to the persistence context as a managed entity object and returned to the application.
Notice that construction of a new managed object during retrieval uses the no-arg constructor. Therefore, it is recommended to avoid unnecessary time consuming operations in no-arg constructors of entity classes and to keep them as simple as possible.
This page covers the following topics:
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
javax.persistence.EntityManager - JPA InterfaceInterface used to interact with the persistence context. em
, the following code fragment demonstrates the retrieval of an Employee
object whose primary key is 1:
Employee employee = em.findEntityManager.find(entityClass,primaryKey) - JPA MethodFind by primary key.(Employee.class, 1);
Casting of the retrieved object to Employee
is not required because find
EntityManager.find(entityClass,primaryKey) - JPA MethodFind by primary key. 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.
If the EntityManager
already manages the specified entity object in its persistence context no retrieval is required and the existing managed object is returned as is. Otherwise, the object data is retrieved from the database and a new managed entity object with that retrieved data is constructed and returned. If the object is not found in the database null
is returned.
A similar method, getReference
EntityManager.getReference(entityClass,primaryKey) - JPA MethodGet an instance, whose state may be lazily fetched., can be considered the lazy version of find
:
Employee employee = em.getReferenceEntityManager.getReference(entityClass,primaryKey) - JPA MethodGet an instance, whose state may be lazily fetched.(Employee.class, 1);
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. The object content is retrieved from the database and the persistent fields are initialized, lazily, when the entity object is first accessed. If the requested object does not exist an EntityNotFoundException
javax.persistence.EntityNotFoundException - JPA ExceptionThrown by the persistence provider when an entity reference obtained by {@link EntityManager#getReference EntityManager.getReference} is accessed but the entity does not exist. is thrown when the object is first accessed.
The getReference
method is useful when a reference to an entity object is required but not its content, such as when a reference to it has to be set from another entity object.
Retrieval by Eager Fetch
Retrieval of an entity object from the database might cause automatic retrieval of additional entity objects. By default, a retrieval operation is automatically cascaded through all the non collection and map persistent fields (i.e. through one-to-one and many-to-one relationships). Therefore, when an entity object is retrieved, all the entity objects that are reachable from it by navigation through non collection and map persistent fields are also retrieved. Theoretically, in some extreme situations this might cause the retrieval of the entire database into the memory, which is usually unacceptable.
A persistent reference field can be excluded from this automatic cascaded retrieval by using a lazy fetch type:
@Entityjavax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity. class Employee { : @ManyToOnejavax.persistence.ManyToOne - JPA AnnotationSpecifies a single-valued association to another entity class that has many-to-one multiplicity.(fetchjavax.persistence.ManyToOne.fetch - JPA Annotation Attribute(Optional) Whether the association should be lazily loaded or must be eagerly fetched.=FetchTypejavax.persistence.FetchType - JPA EnumDefines strategies for fetching data from the database..LAZYjavax.persistence.FetchType.LAZY - JPA Enum ConstantDefines that data can be lazily fetched.) private Employee manager; : }
The default for non collection and map references is FetchTypejavax.persistence.FetchType - JPA EnumDefines strategies for fetching data from the database..EAGERjavax.persistence.FetchType.EAGER - JPA Enum ConstantDefines that data must be eagerly fetched.
, indicating that the retrieval operation is cascaded through the field. Explicitly specifying FetchTypejavax.persistence.FetchType - JPA EnumDefines strategies for fetching data from the database..LAZYjavax.persistence.FetchType.LAZY - JPA Enum ConstantDefines that data can be lazily fetched.
in either @OneToOne
javax.persistence.OneToOne - JPA AnnotationSpecifies a single-valued association to another entity that has one-to-one multiplicity. or @ManyToOne
javax.persistence.ManyToOne - JPA AnnotationSpecifies a single-valued association to another entity class that has many-to-one multiplicity. annotations (currently ObjectDB does not distinguish between the two) excludes the field from participating in retrieval cascading.
When an entity object is retrieved all its persistent fields are initialized. A persistent reference field with the FetchType.LAZY
fetch policy is initialized to reference a new managed hollow object (unless the referenced object is already managed by the EntityManager
). In the example above, when an Employee
instance is retrieved its manager
field might reference a hollow Employee
instance. In a hollow object the primary key is set but other persistent fields are uninitialized until the object fields are accessed.
On the other hand, 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.
This can be changed by an explicit FetchType.EAGER
setting:
@Entityjavax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity. class Employee { : @ManyToManyjavax.persistence.ManyToMany - JPA AnnotationSpecifies a many-valued association with many-to-many multiplicity.(fetchjavax.persistence.ManyToMany.fetch - JPA Annotation Attribute(Optional) Whether the association should be lazily loaded or must be eagerly fetched.=FetchTypejavax.persistence.FetchType - JPA EnumDefines strategies for fetching data from the database..EAGERjavax.persistence.FetchType.EAGER - JPA Enum ConstantDefines that data must be eagerly fetched.) private Collection<Project> projects; : }
Specifying FetchTypejavax.persistence.FetchType - JPA EnumDefines strategies for fetching data from the database..EAGERjavax.persistence.FetchType.EAGER - JPA Enum ConstantDefines that data must be eagerly fetched.
explicitly in @OneToMany
javax.persistence.OneToMany - JPA AnnotationSpecifies a many-valued association with one-to-many multiplicity. or @ManyToManyjavax.persistence.ManyToMany - JPA AnnotationSpecifies a many-valued association with many-to-many multiplicity.
annotations (currently ObjectDB does not distinguish between the two) enables cascading retrieval for the field. In the above example, when an Employee
instance is retrieved all the referenced Project
instances are also retrieved automatically.
Retrieval by Navigation and Access
All the persistent fields of an entity object can be accessed freely, regardless of the current fetch policy, as long as the EntityManager
is open. This also includes fields that reference entity objects that have not been loaded from the database yet and are represented by hollow objects. If the EntityManager
is open when a hollow object is first accessed its content is automatically retrieved from the database and all its persistent fields are initialized.
From the point of view of the developer, it looks like the entire graph of objects is present in memory. This illusion, which is based on lazy transparent activation and retrieval of objects by ObjectDB, helps hide some of the direct interaction with the database and makes database programming easier.
For example, after retrieving an Employee
instance from the database the manager
field may include a hollow Employee
entity object:
Employee employee = em.findEntityManager.find(entityClass,primaryKey) - JPA MethodFind by primary key.(Employee.class, 1); Employee managed = employee.getManager(); // might be hollow
If manager
is hollow transparent activation occurs when it is first accessed. For example:
String managerName = manager.getName();
Accessing a persistent field in a hollow object (e.g. the name of the manager
in the example above) causes the retrieval of missing content from the database and initialization of all the persistent fields.
As seen, the entire graph of objects is available for navigation, regardless of the fetch policy. The fetch policy, however, does affect performance. Eager retrieval might minimize the round trips to the database and improve performance, but unnecessary retrieval of entity objects that are not in use will decrease performance.
The fetch policy also affects objects that become detached (e.g. when the EntityManager
is closed). Transparent activation is not supported for detached objects. Therefore, only content that has already been fetched from the database is available in objects that are detached.
JPA 2 introduces methods for checking if a specified entity object or a specified persistent field is loaded. For example:
PersistenceUtiljavax.persistence.PersistenceUtil - JPA InterfaceUtility interface between the application and the persistence provider(s). util = Persistencejavax.persistence.Persistence - JPA ClassBootstrap class that is used to obtain an {@link EntityManagerFactory} in Java SE environments..getPersistenceUtilPersistence.getPersistenceUtil() - JPA Static MethodReturn the PersistenceUtil instance(); boolean isObjectLoaded = util.isLoadedPersistenceUtil.isLoaded(entity) - JPA MethodDetermine the load state of an entity.(employee); boolean isFieldLoaded = util.isLoadedPersistenceUtil.isLoaded(entity,attributeName) - JPA MethodDetermine the load state of a given persistent attribute.(employee, "address");
As shown above, a PersistenceUtil
javax.persistence.PersistenceUtil - JPA InterfaceUtility interface between the application and the persistence provider(s). instance is obtained from the static getPersistenceUtilPersistence.getPersistenceUtil() - JPA Static MethodReturn the PersistenceUtil instance
method. It provides two isLoaded
methods - one for checking an entity object and the other for checking a persistent field of an entity object.
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. JPA queries and JPQL are described in chapter 4.
Retrieval by Refresh
Managed objects can be reloaded from the database by using the refresh
EntityManager.refresh(entity) - JPA MethodRefresh the state of the instance from the database, overwriting changes made to the entity, if any. method:
em.refreshEntityManager.refresh(entity) - JPA MethodRefresh the state of the instance from the database, overwriting changes made to the entity, if any.(employee);
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
javax.persistence.EntityNotFoundException - JPA ExceptionThrown by the persistence provider when an entity reference obtained by {@link EntityManager#getReference EntityManager.getReference} is accessed but the entity does not exist. is thrown.
Cascading Refresh
Marking a reference field with CascadeTypejavax.persistence.CascadeType - JPA EnumDefines the set of cascadable operations that are propagated
to the associated entity..
REFRESH
javax.persistence.CascadeType.REFRESH - JPA Enum ConstantCascade refresh operation (or CascadeTypejavax.persistence.CascadeType - JPA EnumDefines the set of cascadable operations that are propagated
to the associated entity..ALLjavax.persistence.CascadeType.ALL - JPA Enum ConstantCascade all operations
, which includes REFRESH
javax.persistence.CascadeType.REFRESH - JPA Enum ConstantCascade refresh operation) indicates that refresh
EntityManager.refresh(entity) - JPA MethodRefresh the state of the instance from the database, overwriting changes made to the entity, if any. operations should be cascaded automatically to entity objects that are referenced by that field (multiple entity objects can be referenced by a collection field):
@Entityjavax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity.
class Employee {
:
@OneToOnejavax.persistence.OneToOne - JPA AnnotationSpecifies a single-valued association to another entity that has
one-to-one multiplicity.(cascadejavax.persistence.OneToOne.cascade - JPA Annotation Attribute(Optional) The operations that must be cascaded to
the target of the association.=CascadeTypejavax.persistence.CascadeType - JPA EnumDefines the set of cascadable operations that are propagated
to the associated entity..REFRESH
javax.persistence.CascadeType.REFRESH - JPA Enum ConstantCascade refresh operation)
private Address address;
:
}
In the example above, the Employee
entity class contains an address
field that references an instance of Address
, which is another entity class. Due to the CascadeType.REFRESH
setting, when an Employee
instance is refreshed the operation is automatically cascaded to the referenced Address
instance, which is then automatically refreshed as well. Cascading may continue recursively when applicable (e.g. to entity objects that the Address
object references, if any).