JPA Primary Key

Every entity object that is stored in the database has a primary key. Once assigned, the primary key cannot be modified. It represents the entity object as long as it exists in the database.

As an object database, ObjectDB supports implicit object IDs, so an explicitly defined primary key is not required. But ObjectDB also supports explicit standard JPA primary keys, including composite primary keys and automatic sequential value generation. This is a very powerful feature of ObjectDB that is absent from other object oriented databases.

Entity Identification

Every entity object in the database is uniquely identified (and can be retrieved from the database) by the combination of its type and its primary key. Primary key values are unique per entity class. Instances of different entity classes, however, may share the same primary key value.

Only entity objects have primary keys. Instances of other persistable types are always stored as part of their containing entity objects and do not have their own separate identity.

Automatic Primary Key

By default, the primary key is a sequential 64 bit number (long) that is set automatically by ObjectDB for every new entity object that is stored in the database. The primary key of the first entity object in the database is 1, the primary key of the second entity object is 2, etc. Primary key values are not recycled when entity objects are deleted from the database.

The primary key value of an entity can be accessed by declaring a primary key field:

@Entityjavax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity.
public class Project {
    @Idjavax.persistence.Id - JPA AnnotationSpecifies the primary key of an entity. @GeneratedValuejavax.persistence.GeneratedValue - JPA AnnotationProvides for the specification of generation strategies for the
 values of primary keys. long id; // still set automatically
     :
}

The @Idjavax.persistence.Id - JPA AnnotationSpecifies the primary key of an entity. annotation marks a field as a primary key field. When a primary key field is defined the primary key value is automatically injected into that field by ObjectDB.

The @GeneratedValuejavax.persistence.GeneratedValue - JPA AnnotationProvides for the specification of generation strategies for the values of primary keys. annotation specifies that the primary key is automatically allocated by ObjectDB. Automatic value generation is discussed in detail in the Generated Values section.

Application Set Primary Key

If an entity has a primary key field that is not marked with @GeneratedValuejavax.persistence.GeneratedValue - JPA AnnotationProvides for the specification of generation strategies for the values of primary keys., automatic primary key value is not generated and the application is responsible to set a primary key by initializing the primary key field. That must be done before any attempt to persist the entity object:

@Entityjavax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity.
public class Project {
    @Idjavax.persistence.Id - JPA AnnotationSpecifies the primary key of an entity. long id; // must be initialized by the application
     :
}

A primary key field that is set by the application can have one of the following types:

  • Primitive types: boolean, byte, short, char, int, long, float, double.
  • Equivalent wrapper classes from package java.lang:
    Byte, Short, Character, Integer, Long, Float, Double.
  • java.math.BigInteger, java.math.BigDecimal.
  • java.lang.String.
  • java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp.
  • Any enum type.
  • Reference to an entity object.

Composite Primary Key

A composite primary key consists of multiple primary key fields. Each primary key field must be one of the supported types listed above.

For example, the primary key of the following Project entity class consists of two fields:

@Entityjavax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity. @IdClassjavax.persistence.IdClass - JPA AnnotationSpecifies a composite primary key class that is mapped to
 multiple fields or properties of the entity.(ProjectId.class)
public class Project {
    @Idjavax.persistence.Id - JPA AnnotationSpecifies the primary key of an entity. int departmentId;
    @Idjavax.persistence.Id - JPA AnnotationSpecifies the primary key of an entity. long projectId;
     :
}

When an entity has multiple primary key fields, JPA requires defining a special ID class that is attached to the entity class using the @IdClassjavax.persistence.IdClass - JPA AnnotationSpecifies a composite primary key class that is mapped to multiple fields or properties of the entity. annotation. The ID class reflects the primary key fields and its objects can represent primary key values:

Class ProjectId {
    int departmentId;
    long projectId;
}

ObjectDB does not enforce defining ID classes. However, an ID class is required if entity objects have to be retrieved by their primary key as shown in the Retrieving Entities section.

Embedded Primary Key

An alternate way to represent a composite primary key is to use an embeddable class:

@Entity
javax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity.public class Project {
    @EmbeddedIdjavax.persistence.EmbeddedId - JPA AnnotationApplied to a persistent field or property of an entity
 class or mapped superclass to denote a composite primary
 key that is an embeddable class. ProjectId id;
     :
}

@Embeddablejavax.persistence.Embeddable - JPA AnnotationSpecifies a class whose instances are stored as an intrinsic
 part of an owning entity and share the identity of the entity.
Class ProjectId {
    int departmentId;
    long projectId;
}

The primary key fields are defined in an embeddable class. The entity contains a single primary key field that is annotated with @EmbeddedIdjavax.persistence.EmbeddedId - JPA AnnotationApplied to a persistent field or property of an entity class or mapped superclass to denote a composite primary key that is an embeddable class. and contains an instance of that embeddable class. When using this form a separate ID class is not defined because the embeddable class itself can represent complete primary key values.

Obtaining the Primary Key

JPA 2 provides a generic method for getting the object ID (primary key) of a specified managed entity object. For example:

PersistenceUnitUtiljavax.persistence.PersistenceUnitUtil - JPA InterfaceUtility interface between the application and the persistence
 provider managing the persistence unit. util = emf.getPersistenceUnitUtilEntityManagerFactory.getPersistenceUnitUtil() - JPA MethodReturn interface providing access to utility methods
 for the persistence unit.();
Object projectId = util.getIdentifierPersistenceUnitUtil.getIdentifier(entity) - JPA MethodReturn the id of the entity.(project);

A PersistenceUnitUtilEntityManagerFactory.getPersistenceUnitUtil() - JPA MethodReturn interface providing access to utility methods for the persistence unit. instance is obtained from the EntityManagerFactoryjavax.persistence.EntityManagerFactory - JPA InterfaceInterface used to interact with the entity manager factory for the persistence unit.. The getIdentifierPersistenceUnitUtil.getIdentifier(entity) - JPA MethodReturn the id of the entity. method takes one argument, a managed entity object, and returns the primary key. In the case of a composite primary key - an instance of the ID class or the embeddable class is returned.

Using Primary Keys for Object Clustering

Entity objects are physically stored in the database ordered by their primary key. Sometimes it is useful to choose a primary key that helps clustering entity objects in the database in an efficient way. This is especially useful when using queries that return large result sets.

As an example, consider a real time system that detects events from various sensors and stores the details in a database. Each event is represented by an Event entity object that holds time, sensor ID and additional details. Suppose that queries that retrieve all the events of a specified sensor in a specified period are common and return thousands of Event objects. In that case, the following primary key can significantly improve query run performance:

@Entity
javax.persistence.Entity - JPA AnnotationSpecifies that the class is an entity.public class Event {
    @EmbeddedIdjavax.persistence.EmbeddedId - JPA AnnotationApplied to a persistent field or property of an entity
 class or mapped superclass to denote a composite primary
 key that is an embeddable class. EventId id;
     :
}

@Embeddablejavax.persistence.Embeddable - JPA AnnotationSpecifies a class whose instances are stored as an intrinsic
 part of an owning entity and share the identity of the entity.
Class EventId {
    int sensorId;
    Date time;
}

Because entity objects are ordered in the database by their primary key, events of the same sensor during a period of time are stored continuously and can be collected by accessing a minimum number of database pages.

On the other end, such a primary key requires more storage space (especially if there are many references to Event objects in the database because references to entities hold primary key values) and is less efficient in store operations. Therefore, all factors have to be considered and a benchmark might be needed to evaluate the different alternatives in order to select the best solution.