ObjectDB ObjectDB

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.

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 EntityManagerjavax.persistence.EntityManagerJPA interfaceInterface used to interact with the persistence context.See JavaDoc Reference Page... em, the following code fragment demonstrates the retrieval of an Employee object whose primary key is 1:

  Employee employee = em.findfind(entityClass, primaryKey)EntityManager's methodFind by primary key.See JavaDoc Reference Page...(Employee.class, 1);

Casting of the retrieved object to Employee is not required because findfind(entityClass, primaryKey)EntityManager's methodFind by primary key.See JavaDoc Reference Page... 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, getReferencegetReference(entityClass, primaryKey)EntityManager's methodGet an instance, whose state may be lazily fetched.See JavaDoc Reference Page..., can be considered the lazy version of find:

  Employee employee = em.getReferencegetReference(entityClass, primaryKey)EntityManager's methodGet an instance, whose state may be lazily fetched.See JavaDoc Reference Page...(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 EntityNotFoundExceptionjavax.persistence.EntityNotFoundExceptionJPA exceptionThrown by the persistence provider when an entity reference obtained by EntityManager.getReference is accessed but the entity does not exist.See JavaDoc Reference Page... 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.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
class Employee {
   :
  @ManyToOnejavax.persistence.ManyToOneJPA annotationDefines a single-valued association to another entity class that
 has many-to-one multiplicity.See JavaDoc Reference Page...(fetchManyToOne.fetchannotation element(Optional) Whether the association should be lazily 
 loaded or must be eagerly fetched.See JavaDoc Reference Page...=FetchTypejavax.persistence.FetchTypeJPA enumDefines strategies for fetching data from the database.See JavaDoc Reference Page....LAZYFetchType.LAZYenum constantDefines that data can be lazily fetched.See JavaDoc Reference Page...)
  private Employee manager;
   :
}

The default for non collection and map references is FetchTypejavax.persistence.FetchTypeJPA enumDefines strategies for fetching data from the database.See JavaDoc Reference Page....EAGERFetchType.EAGERenum constantDefines that data must be eagerly fetched.See JavaDoc Reference Page..., indicating that the retrieval operation is cascaded through the field. Explicitly specifying FetchTypejavax.persistence.FetchTypeJPA enumDefines strategies for fetching data from the database.See JavaDoc Reference Page....LAZYFetchType.LAZYenum constantDefines that data can be lazily fetched.See JavaDoc Reference Page... in either @OneToOnejavax.persistence.OneToOneJPA annotationDefines a single-valued association to another entity that has one-to-one multiplicity.See JavaDoc Reference Page... or @ManyToOnejavax.persistence.ManyToOneJPA annotationDefines a single-valued association to another entity class that has many-to-one multiplicity.See JavaDoc Reference Page... 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.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
class Employee {
   :
  @ManyToManyjavax.persistence.ManyToManyJPA annotationDefines a many-valued association with many-to-many multiplicity.See JavaDoc Reference Page...(fetchManyToMany.fetchannotation element(Optional) Whether the association should be lazily loaded or
 must be eagerly fetched.See JavaDoc Reference Page...=FetchTypejavax.persistence.FetchTypeJPA enumDefines strategies for fetching data from the database.See JavaDoc Reference Page....EAGERFetchType.EAGERenum constantDefines that data must be eagerly fetched.See JavaDoc Reference Page...)
  private Collection<Project> projects;
   :
}

Specifying FetchTypejavax.persistence.FetchTypeJPA enumDefines strategies for fetching data from the database.See JavaDoc Reference Page....EAGERFetchType.EAGERenum constantDefines that data must be eagerly fetched.See JavaDoc Reference Page... explicitly in @OneToManyjavax.persistence.OneToManyJPA annotationDefines a many-valued association with one-to-many multiplicity.See JavaDoc Reference Page... or @ManyToManyjavax.persistence.ManyToManyJPA annotationDefines a many-valued association with many-to-many multiplicity.See JavaDoc Reference Page... 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.findfind(entityClass, primaryKey)EntityManager's methodFind by primary key.See JavaDoc Reference Page...(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.PersistenceUtilJPA interfaceUtility interface between the application and the persistence
 provider(s).See JavaDoc Reference Page... util = Persistencejavax.persistence.PersistenceJPA classBootstrap class that is used to obtain an EntityManagerFactory
 in Java SE environments.See JavaDoc Reference Page....getPersistenceUtilgetPersistenceUtil()Persistence's static methodReturn the PersistenceUtil instanceSee JavaDoc Reference Page...();
  boolean isObjectLoaded = util.isLoadedisLoaded(entity)PersistenceUtil's methodDetermine the load state of an entity.See JavaDoc Reference Page...(employee);
  boolean isFieldLoaded = util.isLoadedisLoaded(entity, attributeName)PersistenceUtil's methodDetermine the load state of a given persistent attribute.See JavaDoc Reference Page...(employee, "address");

As shown above, a PersistenceUtiljavax.persistence.PersistenceUtilJPA interfaceUtility interface between the application and the persistence provider(s).See JavaDoc Reference Page... instance is obtained from the static getPersistenceUtilgetPersistenceUtil()Persistence's static methodReturn the PersistenceUtil instanceSee JavaDoc Reference Page... 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 refreshrefresh(entity)EntityManager's methodRefresh the state of the instance from the database, overwriting changes made to the entity, if any.See JavaDoc Reference Page... method:

  em.refreshrefresh(entity)EntityManager's methodRefresh the state of the instance from the database, 
 overwriting changes made to the entity, if any.See JavaDoc Reference Page...(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 EntityNotFoundExceptionjavax.persistence.EntityNotFoundExceptionJPA exceptionThrown by the persistence provider when an entity reference obtained by EntityManager.getReference is accessed but the entity does not exist.See JavaDoc Reference Page... is thrown.

Cascading Refresh

Marking a reference field with CascadeTypejavax.persistence.CascadeTypeJPA enumDefines the set of cascadable operations that are propagated to the associated entity.See JavaDoc Reference Page....REFRESHCascadeType.REFRESHenum constantCascade refresh operationSee JavaDoc Reference Page... (or CascadeTypejavax.persistence.CascadeTypeJPA enumDefines the set of cascadable operations that are propagated to the associated entity.See JavaDoc Reference Page....ALLCascadeType.ALLenum constantCascade all operationsSee JavaDoc Reference Page..., which includes REFRESHCascadeType.REFRESHenum constantCascade refresh operationSee JavaDoc Reference Page...) indicates that refreshrefresh(entity)EntityManager's methodRefresh the state of the instance from the database, overwriting changes made to the entity, if any.See JavaDoc Reference Page... 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.EntityJPA annotationSpecifies that the class is an entity.See JavaDoc Reference Page...
class Employee {
     :
    @OneToOnejavax.persistence.OneToOneJPA annotationDefines a single-valued association to another entity that has
 one-to-one multiplicity.See JavaDoc Reference Page...(cascadeOneToOne.cascadeannotation element(Optional) The operations that must be cascaded to 
 the target of the association.See JavaDoc Reference Page...=CascadeTypejavax.persistence.CascadeTypeJPA enumDefines the set of cascadable operations that are propagated 
 to the associated entity.See JavaDoc Reference Page....REFRESHCascadeType.REFRESHenum constantCascade refresh operationSee JavaDoc Reference Page...)
    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).