0
0

JPA Tutorial

Java Persistence Architecture Distilled Tutorial
1085 / 1
Jorge Simao Posted 06 Dec 19

JPA Introduction

JPA (the *Java Persistency Architecture) is a JEE standard to map Java objects to relational databases (ORM). It abstract most of the details of interacting with an underlying data access layer such JDBC. Applications are provided with operations to save, get, update, delete, and find Java objects from/to the data-base, without writing query statements (SQL). The JPA/ORM runtime takes care of connection to the underlying database, and creating the appropriated SQL statements. The JPA/ORM runtime can also create the database scheme automatically from meta-data provided by Java reflection and JPA specific Java annotations.

ORM and JPA Concepts

Entities

An entity is a java class that represents a domain concept and whose instances have a persistent identity. An entity always have one or more database table where the instances state are stored, but depending on the mapping scheme used a table may be shared by several entities under the same class hierarchy. Each entity instance as a corresponding row in each of the tables used to represent the entity. The simplest case is when a single table is used to represent an entity. In this case, each instance will have a row in that table with entity fields or properties mapped to table column. This limit cases occurs only in there are not other entities in the same class hierarchy or we set in configuration that entities should not share tables. Additionally, if an entity is in related with other entities or support classes than this requires further tables to store the relations.

A java class is declared an entity by using the class-level annotation @Entity. For this entity classes, fields and properties are mapped to the artifacts in the database. It also possible to provide field-level and method-level annotations how the mapping is done.

Requirements for JPA Entity Classes

Below, we summarize the full requirements that a java class need to comply to be used as a JPA entity:

  • The class must be annotated with the javax.persistence.Entity annotation.

  • The class must have no-argument constructor, with public or private modifiers. This is because the JPA run-time need to create by reflection instances of entities to be filled with state values. Other constructor are allowed to be used by the application, but they will not be use directly by the JPA run-time.

  • The class must not be declared final. Likewise, persistent fields and all methods (not only property setters and getters) may not be declared final. This is because to implement some features of JPA, the run-time may create proxied instance that extend the class of the entity. This is used to intercept method invokation and lazily load entities state.

  • Persistent fields must not be public. That is, they need to be declared with modifiers private or private, or be package-private (no modifiers). Furthermore, access to instance fields can be done directly only by the methods declared in the same class. Other classes need to access instance state only with property getter and setter methods and other business methods. Again, this is because dynamically created proxy objects can only intercept method invokations and not direct field accesses.

A further requirement on entity classes is that one, and only one, field or property needs to be declared as primary key. This is done with annotation @Id. An entity class may also inherit the field/property primary key from a super-class that is mapped to the data-base.

Below, we show an example of a valid entity class representing a User in some application domain:

Example: Simple Entity Class

@Entity
public class User {
	@Id
	private long id;
	
	private String name;

	private String email;
	
}

Entity classes may be abstract or concrete (non-abstract). Abstract entity classes are annotated with @Entity as concrete classes. However, abstract entities can not be instantiated directly.

Like concrete entity classes, abstract entities can be queried. If a query is performed on a abstract entity, the query operates on all the concrete entity subclasses of the abstract entity.

Entity Inheritance

Entity classes can be related by class inheritance. Entity classes may extend both entity and non-entity classes. Super classes that are entities will provide additional persistent state to entity instances. Super-classes that are not entity themselves may or may not provide additional persistent state. When the non-entity super-class provides persistent state is said to be mapped.

Non-entity classes may also extend entity classes. But the fields or properties defined in this class do not have a persistent state, unless they are mapped classes and are further derived by an entity class.

Below, we show an example of three entity classes related by inheritance:

Example: Entity Classes in Inheritance Tree

@Entity
public class A {
	@Id
	private Integer id;

	private String a;
	...
}

@Entity
public class B extends A {
	private Integer b;
	...
}

@Entity
public class C extends A {
	private Float c;
}

Class A defines common fields to the class hierarchy, including the primary key. Derived entity classes B and C provide additional fields specific to thoses classes and their derived classes.

Mapped Superclasses

Entities may inherit from super-classes that provide persistent state but are not defined as entities. This super-classes are said to be mapped super-classes and are declared with annotation @MappedSuperclass. Mapped super-classes are useful when their is persistent data common multiple entity classes.

Mapped super-classes, like entity classes, can be abstract or concrete. If a mapped super-class is not abstract it can be instance from a Java, but its instances can not be made persistent. Thus, it is more common to have abstract mapped super-classes, rather than concrete mapped super-classes.

Below, we show a set of classes related by inheritance but with the top-level class being a mapped superclass:

Example: A MappedSuperclass

@MappedSuperclass
public abstract class A {
	@Id
	private Integer id;

	private String a;
	...
}

@Entity
public class B extends A {
	private Integer b;

	...
}
@Entity
public class C extends A {
	private Float c;
}

Mapped super-classes do not have any corresponding tables in the underlying database. Entities that inherit directly from the mapped superclass introduce the tables used to store the persistent data defined in the mapped supper-class. For the example above, entity classes B and C will have each a table in the database. Mapped superclass A, on the other hand, will not have a corresponding table in the database.

Mapped super-classes can not be queried, thus they can not by used in EntityManager or Query operations. Only derived entity classes can by queried. Furthermore, mapped super-classes can’t be targets of entity relationships. (This is because the absence of a corresponding database table for mapped super-classes makes the implementation of queries or relations impossible.)

Non-Entity Superclasses

Entities may have also extend non-entity super-classes. These super-classes can be either abstract or concrete. The state of non-entity super-classes is always non-persistent. Thus, any state inherited from the non-entity superclass by an entity class is non-persistent.

Similarly to mapped super-classes, non-entity super-classes may not be used subject to queries. Mapping and relationship annotation present in a non-entity super-classes are ignored. Again, this is because there is not corresponding database table to which the querying operations or relationships can be applied.

Persistent Fields and Properties

The persistent state of an entity can be defined and accessed through either the entity’s instance variables (data-fields) or properties access methods (getters and setters). Entities may use persistent fields, persistent properties, or a combination of both. If the mapping annotations are applied to the field the JPA run-time accesses directly the fields. If the mapping annotations are applied to the getter methods, the JPA run-time uses the property access methods. Due to this equivalence, it is common to use the term property access, also when access is made through fields directly.

Property access methods, if available, should follow JavaBean convenctions, as shown below:

Property TypeMethod CategoryMethod Signature
non-booleangetterType getXX()
settervoid setXX(Type)
booleangetterType isXX()
settervoid setXX(Type)

Java Bean Conventions for Property Accessors&Modifiers

Above, XX is the name of the property, Type is the type of the property, and type is the name of the setter parameter. Note that for boolean fields (boolean or Boolean types), an alternative convention exists.

Non-Persistent Fields and Properties

All entity fields are by default persistent, that is, they state is stored and feteched from the database. A field can by made non-persistent, by annotating it with @Transient. If a field has a java modifier transient it is also made non-persistent. No other mapping annotations can be applied to non-persistent fields or properties.

Field and Property Types

The fields or properties must be of the following Java language types:

  • Basic Java types:

    • Java primitive types
    • java.lang.String
  • Other serializable types:

    • Wrappers of Java primitive types
    • java.math.BigInteger
    • java.math.BigDecimal
    • java.util.Date
    • java.util.Calendar
    • java.sql.Date
    • java.sql.Time
    • java.sql.TimeStamp
  • User-defined serializable types

    • byte[]
    • Byte[]
    • char[]
    • Character[]
    • Enumerated types
  • Other entities and/or collections of entities:

    • Embeddable classes

Persistent Collections

Collection-valued persistent fields and properties must use the standard Java collection interfaces, show below:

  • java.util.Collection
  • java.util.Set
  • java.util.List
  • java.util.Map

All these types are defined as Generics. This, collections with type-checked elements may also be used by providing the erasure type. Setter and getter methods for collection property follow the same conventions as non-collection properties. As example is shown below:

Example: Persistent Collections Annotations

import java.util.Set;

@Entity
public class User {
 	...
	private Set<Preferences> preferences;
	
	public Set<Preferences> getPreferences() {
		return preferences;
	}
	
	public void setPreferences(Set<Preferences> preferences) {
		this.preferences = preferences;
	}
}

Primary Keys

All entity instances have a ``special field'' called the primary key, whose value is used to uniquely identify and distinguish between different instance of the same entity class. Thus, each entity class needs to define a persistent field for identifier, or inherit it from an entity or mapped superclass. This requirement is brought about by relational database tecnologies, that required that at least one column on an entity table be used as a unique primary key. Primary keys that take a single column are named simple primary key, while keys that take more than one column are said to be composite primary keys.

Simple Primary Keys

A field or property that is a primary key, should be annotated with @Id. Furthermore, a primary key field or property, must have one ofthe following Java types:

  • Java primitive types: int, long, short, byte, char
  • Java primitive wrapper types: Integer, Long, Short,JPA run-time Byte, Char
  • java.lang.String
  • java.util.Date
  • java.sql.Date
  • java.math.BigDecimal
  • java.math.BigInteger

Floating-point types can never be used as primary keys. Boolean types are also not very useful as primary keys, since they can only take two values. Integer types are the mostly used primitive types for primary keys. If you use a generated primary key, only integral types will be portable.

Composite Primary Keys

Composite primary keys are primary keys defined with more than one field or property (and database table column). In JPA, composite primary keys need to defined in a dedicated primary key class. A primary key class should be annotated with IdClass. Furthermore, a entity field that is a composite primary key should be annotated with @EmbeddedId.

A composite primary key classes must meet the following requirements:

  • The class must be public.
  • The property getters and setter must be public or private, if property-based access is used.
  • The class must have a public default (no-argument) constructor.
  • The class must implement the hashCode() and equals(Object) methods.
  • The class must serializable (implement interface java.io.Serializable).

The fields and properties of a composite primary key class must have the types as simple primary keys. A composite primary key must be represented and mapped to multiple fields or properties of the entity class or must be represented and mapped as an embeddable class.

If the class is mapped to multiple fields or properties of the entity class, the names and types of the primary key fields or properties in the primary key class must match those of the entity class.

Below, we show an example of composite primary key class. The field userId and jobId when combined uniquely identify an entity:

Example: Composite Key

public final class PreferenceKey implements Serializable {
	private long userId;
	
	private int preferenceId;

	public PreferenceKey() {}

	public PreferenceKey(long userId, int preferenceId) {
		this.userId = userId;
		this.preferenceId = preferenceId;
	}

	public boolean equals(Object obj) {
		if (this==obj) return true;
		if (!(obj instanceof PreferenceKey)) return false;
		PreferenceKey jk = (PreferenceKey) obj;
		return userId==jk.userId && preferenceId==jk.preferenceId;
	}

	public int hashCode() {
		return (int) userId ^ preferenceId;
	}

	public String toString() {
		return userId + " " + preferenceId;
	}
}

Entity Relations

Entities may be related not only by inheritance, but also by association such as in a owner/owned or a contains/part-of relation. A the term entity relation is usually only used for association, to avoid confusion with inheritance relations. This is the convention that we use in this document.

In JPA, relations are defined at the field or property level such that related entity instances are accessible by java references. If an entity class A is related to other entity class B, then entity A defines or inherits a field or property of type B or a collection whose elements have type B.

Relations are characterized by the multiplicity and directionality, such that an entity instance can be related to a collection of other entities instances and this relationship might be explict in only on direction or both. JPA annotations are use to qualify the specific kind of relation.

Most kinds of entity relations (all except one-to-one relations), required that additional database artifacts be used to store information about the related entities. This are called joint tables or relationship tables, whose columns store the primary keys of the related entities. Thus, is a entity class A is related to a collection of entities of class B then this is represented in persistent store as a joint table A-B, whose columns are the primary keys of A and B. This is because in RDBMS, tables need to have a fixed number of columns and column values should not be lists of values. Thus joint tables are the only (reasonable) away to map relations to collections of entity instances.

Multiplicity of Relations

The multiplicity of a relation specifies throws many instances of an entity in one side of the relation can be related to how many instances in the opposite side of the relation. This concept is already worked out and addressed by RDBMS, and is not specific to ORM or JPA. The different possibilities are described below:

One-to-one (1:1)
Each entity instance of class `A` is related to a single instance of entity class `B`. In **JPA** this, corresponds to a have a field or property of type `B` in `A`. If the relation is bidirectional, then `B` will also have a field or property of type `A`. One-to-one relationships are setup by decorating the corresponding field or property getter method with annotation `@OneToOne`. Examples of one-to-one relationships include: `User--ShoppingCart`, and `User--Contact`.
One-to-many (1:N)
An instance of entity class `A` is related with multiple instances of `B`. In **JPA**, this corresponds to a have a field in `A` whose class is a collection of elements of type `B`. `B` might also have a reference to a single instance of `A`, is the relation is bidirectional. One-to-many relationships are setup by decorating the corresponding field or property getter method with annotation `@OneToMany`. Examples of one-to-many relationships include: `User--Role`, `ShoppingCart--SalesItem`, `Contact--Address`, and `Container-Component`.
Many-to-one (N:1)
Multiple instance of class `A` is related with a single instance of entity `B`. This is the converse of a one-to-many relation. In **JPA**, this corresponds to a have a field in `A` that is a reference of type `B`, and a field in class `B` whose type is a collection of `A`. Many-to-one relationships are setup by decorating the corresponding field or property getter method with annotation `@ManyToOne`. When a many-to-one relation is defined with annotation `@ManyToOne`, the converse annotation `@OneToMany` should be present in the other side of the relation. That is, if `A` is related to `B` by means of a `@ManyToOne` annotation, them `B` has a corresponding field annotated with `@OneToMany`. Examples of many-to-one relationships are the same as one-to-many relationshp, but reversed.
Many-to-many (N:M)
The entity instances of one class can be related to multiple instances of the other class. Many-to-one relationships are setup by decorating the corresponding fields or property methods with annotation `@ManyToMany`. In **JPA**, both of the related classes should have a field whose type is a collection to the other type, and both fields or property getter should be annotated with `@ManyToMany`. Examples of many-to-many relationships include: `Student--Course`, `Vendor--ProductCategory`, `Person--Event`, `Worker--Task`, and in some application domains `Employee--Employer`..

Direction in Entity Relationships

Bidirectional Relationships

The directionality of a relationship determines if the existence of related entities can be learn from one side or both sides of the relation. In a bidirectional relationship both sides have references to the other side. One of the sides is defined as the owning side, while the opposite side is the owned side or non-owning side. Declaration of bidirectional relation is asymmetric. Only the owned/non-owning side provides information about directionality by setting attribute mappedBy in the relation specific annotation. For example, @OneToMany(mappedBy="a") or @ManyToMany(mappedBy="a"). The value of the annotation’s attribute is the name of the field or property in owning side of the relation that reference the entity in the owned side.

Consider the example:

Example: One-To-Many Association

import java.util.Set;

@Entity
public class User {
	@Id
	Long id;

	@OneToMany(mappedBy="user")	
	Set<Jobs> jobs;
	
}

@Entity
public class Job {
	@Id
	Long id;
	
	@ManyToOne
	User user;
	
	...
}

Entity class User is in a one-to-many relation to entities of class Job. The relationship is bidirectional since a User knows about its set of Job, and Job knows about its User by means of field user. Field User.jobs is annotated with @OneToMany(mappedBy="user") thus specifing that the User is the owning side of the relation.

Below, we summarize the rules for bidirectional relations:

  • The owned side provides information about the owning side by using the mappedBy attribute in annotations @OneToOne, @OneToMany, or @ManyToMany. The mappedBy attribute designates the field or property in the entity that is the owner of the relationship, that refers to the owned side.
  • The many side of many-to-one bidirectional relationships must not define the mappedBy attribute. The many side is always the owning side of the relationship, that is, the side that has the @OneToMany annotation.
  • For many-to-many bidirectional relationships, either side (but only one side) may be the owning side.
  • For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key.

The owning side of a relationship is relevant has it determines how the JPA runtime makes updates to the relationship in the database. Operation on entities may be set to propagated to related entities. However, only the owning side propagates operations.

Unidirectional Relationships

In a unidirectional relationship, only one entity has a relationship field or property that refers to the other. Examples of unidirectional relations include: SalesItem--Product, Employee--Category, and Voter--Candidate. In all cases, only the first side of the relation contains a reference to the opposite side. For unidirectional relation the attribute mappedBy is meaningless and should not provided, since there is not field or property on the opposite side that can be specified.

Operation Propagation

Operation performed on entity may be setup to propage (cascade) to related entities. This is done by setting attribute cascade of the annotation defining the relation type, such as: @OneToMany(cascade="operation"). Operation propagation can narrowed to a single type of operation or to all operations. The set of possible operations is defined by enumerate type javax.persistence.CascadeType enumerated type. Table below summarizes the cascade options defined by JPA. Note that cascade=ALL is the same as setting cascade={DETACH, MERGE, PERSIST, REFRESH, REMOVE}. The details on these operation are explained elsewhere.

Cascade OperationDescription
PERSISTPersist operations are propagate to related entities
MERGEMerge operations are propagate to related entities
REFRESHRefresh operations are propagate to related entities
REMOVERemove operations are propagate to related entities
DETACHDetach operations are propagate to related entities
ALLAll the above operations propagate to related entities

Summary cascade options.

As an example, suppose we want persistent operation on instances of entity class User to be cascade/propagate to a set of related Job instances. This means that when a User instance is made persistent, the set of related Job instance are automatically made persistent. Then we setup the annotation @OneToMany(cascade="PERSIST") in field of class User coding the relation, as show below:

Example: Cascading Persist Operation

@Entity
public class User {
	@OneToMany(cascade=PERSIST)
	private Set<Job> jobs;
}

In the code fragment below we illustrate the use of cascading, by leaving out the explicit persist operation of created Job instances.

Example: Using Persist Cascade

EntityManager entityManager = ... 
User u = new User(..);
u.addJob(new Job(u, "job1"));
u.addJob(new Job(u, "job2"));

//persist user; job are automatically persisted
entityManager.persist(u);

Operation cascading is performed in a recursive away. Thus, if class A declares that operations should cascade to a related instances of class B, and class B class declared that operations should be cascaded to related instances of class C, then performing the operation on an instance of A will trigger the same operation on instances of B and related instances of C. Formally, one says that operations are defined as transitive.

Orphan Removal

When a target entity in one-to-one or one-to-many relationship is removed from its relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered orphans, and the orphanRemoval attribute can be used to specify that orphaned entities should be removed.

The orphanRemoval attribute in @OneToMany and @oneToOne takes a Boolean value and is by default false.

For example, if an order has many line items and one of them is removed from the order, the removed line item is considered an orphan. If orphanRemoval is set to true, the line item entity will be deleted when the line item is removed from the order.

The following example will cascade the remove operation to the orphaned customer entity when it is removed from the relationship:

Example: Orphon-Removal in One-To-Many Assiociation

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getJobs() { ...
}
@Entity
public class User {
	@OneToMany(mappedBy="customer", )
	private Set<Job> jobs;
}

Embeddable Classes

Entity class can be related to other classes that have persistent state, but are not entities themselves. These are called embeddable classes. These classes share the same persistent identiy as the related identity, meaning that the tables and table rows used to store the state of the entity class intances is the same as the related entity class. In JPA, embedded class should be decorated with annotation Embeddable (but not @Entity). Furthermore, the field or property getter method for the embedded class in the entity class may be decorated with the @Embedded annotation, although this is not strictly required. (Because the embedding can be learn from the definition of the embedded class).

Below, we shown an example a entity class User that has a reference to a embedded class Contact:

Example: Embeddable Classes

@Entity
public class User {
	@Id
	private long id
	
	@Embedded
	Contact c;
 ...
}

@Embeddable
public class Contact {
	String email;
	String address;
	String phone;
	String country;
	...
}

Contact persistent state (email, address, …) shares the database identity of the owning User. Meaning, that the same table and row is used store a user instance and its contact information (stored in additional columns).

An embeddable classes may have any number of fields or properties and the values may be single-valued or collection-valued. Additionally, embeddable classes may themselves use other embeddable classes to represent their state, which in tur may have other Java types or embeddable classes as field or properties. Embeddable classes may also contain relationships to other entities or collections of entities. If the embeddable class has such a relationship, the relationship is made from the target entity or collection of entities to the entity that owns the embeddable class(es).

Fetch Strategy

Whether the association should be lazily loaded or must be eagerly fetched. The EAGER strategy is a requirement on the persistence provider runtime that the associated entity must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime.

Persistence Context

Entity Manager

Entity Instances Lifecycle

Entity instances are in one of four states:

New
The entity was created in the JVM (as a java object), but is not yet managed by a persistence context.
Managed
The entity is being managed by a persistence context.
Detached
The entity has a persistence identity but is not currently being managed by the persistence context.
Removed
The entity has a persistence identity but is scheduled for removal from the data store.

Querying

Abstract entities can be queried. If an abstract entity is the target of a query, the query operates on all the concrete subclasses of the abstract entity.

Mapped super-classes cannot be queried and can not be used in EntityManager or Query operations. You must use entity subclasses of the mapped superclass in EntityManager or Query operations. Mapped super-classes can not be targets of entity relationships. Mapped super-classes can be abstract or concrete.

Queries and Relationship Direction

Java Persistence query language and Criteria API queries often navigate across relationships. The direction of a relationship determines whether a query can navigate from one entity to another. For example, a query can navigate from LineItem to Product but cannot navigate in the opposite direction. For Order and LineItem, a query could navigate in both directions because these two entities have a bidirectional relationship. Cascade Operations and Relationships

Entities that use relationships often have dependencies on the existence of the other entity in the relationship. For example, a line item is part of an order; if the order is deleted, the line item also should be deleted. This is called a cascade delete relationship.

Object-Relational Mapping Meta-Data

Class Annotations

Table below summaries the annotations defined by JPA for classes.

AnnotationAttributesDescription
@Entity Defines an entity
@MappedSuperclass Defines a mapped superclass
@Embeddable Defines a mapped superclass
@Tablename schema catalog uniqueConstraintsDefine table properties

JPA annotations for classes.

Field and Property Annotations

Table below summaries the annotations defined by JPA to fields or property getter and setters.

AnnotationAttributesDescription
@Basicfetch optionalBasic field/property
@Id Primary key field/property
@GeneratedValuestrategyId generation strategy
@Transient field/prop without persistent state
@Columnnamecolumn name in table
@Embedded embedded field/prop
@OneToOnemappedBy cascade fetch optional targetEntityone-to-many relationship
@OneToManyone-to-many relationship
@ManyToOnereverse of one-to-many bidirectional relationship
@ManyToManymany-to-many relationship

JPA annotations for fields and property setters and getters.

ID Generation Strategies

Possible id generation strategies:

Example: ID Generation Strategies

enum GenerationType {
	AUTO,
	IDENTITY,
	SEQUENCE,
	TABLE
}
Id Generation StrategyDescription
AUTOJPA run-time automaticaly selects the strategy
IDENTITYPrimary keys retrieved from the identity column
SEQUENCEPrimary keys retrieved from the sequence column
TABLEPrimary keys retrieved from a dedicated table

Summary of id generation strategy defined by enumaration type GenerationType.

Below, we shown an example of an entity definition with explict identifier generation strategy:

Example: Defining the ID Generation Strategy

@Entity
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	long id;
	private String name;
}

Constraints and Validation

The Java API for bean validation (JSR303) defines the annotations and mechanism for validating application data. Bean validation can be used in several tiers of the application not only the data-access and persistence layer.

Bean Validation constraints are annotations applied to the fields or properties of Java programming language classes. Bean Validation provides a set of constraints as well as an API for defining custom constraints. Custom constraints can be specific combinations of the default constraints, or new constraints that don’t use the default constraints. Each constraint is associated with at least one validator class that validates the value of the constrained field or property. Custom constraint developers must also provide a validator class for the constraint.

Bean Validation constraints are applied to the persistent fields or properties of persistent classes. When adding Bean Validation constraints, use the same access strategy as the persistent class. That is, if the persistent class uses field access, apply the Bean Validation constraint annotations on the class’s fields. If the class uses property access, apply the constraints on the getter methods.

Bean Validation constraints may be applied to persistent entity classes, embeddable classes, and mapped super-classes. By default, the Persistence provider will automatically perform validation on entities with persistent fields or properties annotated with Bean Validation constraints immediately after the PrePersist, PreUpdate, and PreRemove lifecycle events.

Bean Validation will throw a validation error. Similarly, if a previously created instance of Contact has been modified so that firstName or lastName are null, a validation error will be thrown.

Constraints on Object References

The @NotNull annotation specifies that a reference to an object can not be null (is required). Converselly, the annotation @NotNull specifies that a reference to an object need to be null (is not allowed).

Constraints on Numerics

For integer numbers range contraints are specified with annotations @Max and @Min. @Max specifies that the property value needs to be less-than or equal to specified value, while @Min specifies that the property value needs to be greater-than or equal to specified value. The combination of the two contraints can be used to specify that the property value should be within an inclusive integer range $[min,max]$.

Similarly, for decimal numbers range contraints are specified with annotations @DecimalMax and @DecimalMin. @DecimalMax specifies that the property value needs to be less-than or equal to specified value, while @DecimalMin specifies that the property value needs to be greater-than or equal to specified value. The combination of the two contraints can be used to specify that the property value should be within an inclusive numeric range $[min,max]$.

For decimal numbers it also possible to contraint the maximum number of digits for the integer and fractional part of the number. This is done with annotation @Digits. Attribute integer specifies the maximum number of integer digits. Attribute fraction specifies the maximum number of fractional digits.

Constraints on Dates

Date values may be contraint in relation to present time and date. Annotation @Past specifies that the value needs to be before the current date (i.e. represents an event that occured in the past). Annotation @Future specifies that the value needs to be after current date (i.e. represents an event that will occur in the future).

Constraints on Booleans

Constraints on Strings

The email field has a @Pattern constraint applied to it, with a complicated regular expression that matches most valid email addresses. If the value of the email does not match this regular expression, a validation error will be thrown.

Constraints on Collections

Table below summarizes the annotations to constraint field/property values defined in JSR303. All this annotations are defined in package javax.validation.constraints.

AnnotationType(s)Description
@NotNullObjectValue must not be null
@NullObjectValue must be null
@MaxNumericMaximum allowed integer value
@MinNumericMinumum allowed integer value
@DecimalMaxNumericDecimal value less-than or equal to specified value
@DecimalMinNumericDecimal value greater-than or equal to specified value
@DigitsNumericMax. number of integer and fraction digits
@PastDateDate must be in the past.
@FutureDateDate must be the future
@AssertFalsebooleanValue must be false
@AssertTruebooleanValue must be true
@SizeString|Collection|Map|ArrrayMin. and Max. length/size
@PatternStringValue must match the regular expression

Summary of annotations to constraint field/property values (JSR303).

Example: Entity with Validation Constraints

@Entity
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	

	//Value must not be null
	@NotNull String name;

	//Value must be null
	@Null String oldName;

	//Decimal value less-than-or-equal and greater-than-or-equal specified values
	@DecimalMin(1000.00)
	@DecimalMax(5000.00)
	BigDecimal salary;

	//Max. number of integer and fraction digits
	@Digits(integer=6, fraction=2)
	BigDecimal budget;

	//Minimum and Maximum allowed integer value
	@Min(0) @Max(10) int n;

	//Date must be in the past
	@Temporal(javax.persistence.TemporalType.DATE)
	@Past Date born;

	//Date must be the future
	@Future Date event;

	//Min. and Max. length/size
	@Size(min=6, max=10)
	String password;

	//Value must be false
	@AssertFalse
	boolean isUnsupported;

	//Value must be true 
	@AssertTrue
	boolean isActive;

	//Value must match regular expression: 10 digit phone number like: (xxx)xxx-xxxx
	@Pattern(regexp="\\(\\d{3`\\)\\d{3`-\\d{4`", message="{invalid.phonenumber`")
	String phoneNumber;

}

All the built-in constraints defined in JSR303 have a corresponding annotation for grouping multiple constraints of the same type on the same field/property. For a constraint annotation named Constraint, the list annotation is name Constraint.List since is defined as a inner annotation. If a list of contraints is present only one of the contraints needs to be valid.

Below, we show an example of a group of @Pattern constraints:

Example: Validation Constraint Grouping

@Pattern.List({
	@Pattern(regexp="..."),
	@Pattern(regexp="...")
`)

Mapping to a DataBase Scheme

Mapping Entities

Entities are mapped to database tables. For each class or class hierarchy tree a different table is used. Entity fields and properties are mapped to column in the respective table. The naming of tables and column is automatically selected by the JPA implementation, but can also be controlled with annotations. For entites the class annotation @Table("name") is used to specify the table name to use. For fields and property getter the class annotation @Columns("name") should be used.

Explicity selection of table and column names is in many cases unnecessary. However, there are cases in which explicit naming is necessary, such as:

  • The database scheme pre-exists the JPA application. In this case, it is likey that there is not a exact match between the pre-existing naming scheme and the naming scheme expected by the JPA complient run-time.
  • The use of JPA run-time selected names generate errors, because of naming conflict with existing artifacts in the database.
  • The use of JPA run-time selected names generate errors, because names conflit with reserved names in the configured SQL dialect.

Consider a example of a class User as shown below:

Example: Entity with Explicit Column Mapping

@Entity
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column("key")
	long id;
	
	String name;
	String email;

	@Column("dob")
	Date born;

	BigDecimal salary;
	
	@Transient
	boolean loggedIn;

	List<Job> jobs;
}

Consider also that we create a few instance of class User. Then the database representation of the User entity will be a table something like the one shown below:

keynameemaildobsalary
1Joe Slowjoe@jpa-lovers.org10-10-19701100.5
2Mary Wisemary@java-fans.net11-12-1975
3Albert Jr.albert@kindernet.net1-1-2008

Scheme and actual table mapping an entity class User.

Mapping Fields and Properties

Entity fields and other persistant state is stored in the database as table columns. The JPA run-time automatically assigns or assumes a name to for the table column from the name of the field or property. However, this can be modified by decorating the field or property with annotation @Column("name"). The reasons to be explicity about the naming of a column are the same as the ones one might want to be explicity about the name of a table.

Mapping Collections

If a field or property of an entity consists of a collection of basic types or embeddable classes, use the javax.persistence.ElementCollection annotation on the field or property.

The two attributes of @ElementCollection are targetClass and fetch. The targetClass attribute specifies the class name of the basic or embeddable class and is optional if the field or property is defined using Java programming language generics. The optional fetch attribute is used to specify whether the collection should be retrieved lazily or eagerly, using the javax.persistence.FetchType constants of either LAZY or EAGER, respectively. By default, the collection will be fetched lazily.

The following entity, Person, has a persistent field, nicknames, which is a collection of String classes that will be fetched eagerly. The targetClass element is not required, because it uses generics to define the field.

Example: Entity with ElementCollection

@Entity
public class User {
	...
	@ElementCollection(fetch=EAGER)
	private Set<String> emails = new HashSet();
	...
}

Mapping Java Maps

Collections of entity elements and relationships may be represented by java.util.Map collections. A Map consists of a key and a value.

When using Map elements or relationships, the following rules apply.

  • The Map key or value may be a basic Java programming language type, an embeddable class, or an entity.
  • When the Map value is an embeddable class or basic type, use the @ElementCollection annotation.
  • When the Map value is an entity, use the @OneToMany or @ManyToMany annotation.
  • Use the Map type on only one side of a bidirectional relationship.

If the key type of a Map is a Java programming language basic type, use the annotation javax.persistence.MapKeyColumn to set the column mapping for the key. By default, the name attribute of @MapKeyColumn is of the form RELATIONSHIP-FIELD/PROPERTY-NAME_KEY. For example, if the referencing relationship field name is image, the default name attribute is IMAGE_KEY.

If the key type of a Map is an entity, use the javax.persistence.MapKeyJoinColumn annotation. If the multiple columns are needed to set the mapping, use the annotation javax.persistence.MapKeyJoinColumns to include multiple @MapKeyJoinColumn annotations. If no @MapKeyJoinColumn is present, the mapping column name is by default set to RELATIONSHIP-FIELD/PROPERTY-NAME_KEY. For example, if the relationship field name is employee, the default name attribute is EMPLOYEE_KEY.

If Java programming language generic types are not used in the relationship field or property, the key class must be explicitly set using the javax.persistence.MapKeyClass annotation.

If the Map key is the primary key or a persistent field or property of the entity that is the Map value, use the javax.persistence.MapKey annotation. The @MapKeyClass and @MapKey annotations cannot be used on the same field or property.

If the Map value is a Java programming language basic type or an embeddable class, it will be mapped as a collection table in the underlying database. If generic types are not used, the @ElementCollection annotation’s targetClass attribute must be set to the type of the Map value.

If the Map value is an entity and part of a many-to-many or one-to-many unidirectional relationship, it will be mapped as a join table in the underlying database. A unidirectional one-to-many relationship that uses a Map may also be mapped using the @JoinColumn annotation.

If the entity is part of a one-to-many/many-to-one bidirectional relationship, it will be mapped in the table of the entity that represents the value of the Map. If generic types are not used, the targetEntity attribute of the @OneToMany and @ManyToMany annotations must be set to the type of the Map value.

Mapping Relations

Information about entity relations is stored explicitilty in the database artifacts.

Foreign Keys

For one-to-one relation, entity tables include a column for the primary key of the related entity, designated as a foreign key. If the relation is bidirectional only one table of the two related entites, has a forign key. If the relation is bidirectional, both table have a forign key.

Consider the example below with a bidirectional one-to-one relation between entities User and Profile:

Example: Bidirectional Associations

@Entity
public class User {
	@Id
	@Column("userId")
	private int id;
	
	private String name;
	...

	@OneToOne(mappedBy="user")
	private Profile profile;
}

@Entity
public class Profile {
	@Id	
	@Column("profileId")	
	private int id;
	
	private String education;
	
	private User user;
	...
}

This produces the following database schemas for the table for entity User and Profile:

userIdKNAMEprofileIdFK
1Joe1
2Jenny3
3Albert5

Tables for entities User and Profile with foreign keys mapping a bidirectional one-to-one relation.

profileIdKEDUCATIONuserIdFK
1B.Sc.1
3Ph.D.2
4M.Sc.3

Tables for entities User and Profile with foreign keys mapping a bidirectional one-to-one relation.

For convenience, primary keys are marked with superscript <sup>K</sup> and foreign keys are marked with superscript <sup>FK</sup>.

Joint Tables

For other one-to-many/many-to-one and many-to-many relations, information is stored using joint tables whose columns are the primary keys of related entities. For embeddable classes the persistent state is also stored in the joint tables.

Consider the example below of a one-to-many bidirectional relation between entities User and Job:

Example: One-To-Many Bidirectional Association

@Entity
public class User {
	@Id
	Long id;
	... 	
	@OneToMany(mappedBy="user")	
	Set<Jobs> jobs;
	
}

@Entity
public class Job {
	@Id
	@Column("jobId")
	Long id;
	...	
	@ManyToOne
	User user;	
}

Then the following joint-table is setup or assumed by the JPA provider:

userIdprofileId
11
122
23
34

Joint table for entities User and Job.

Mapping Inheritance

When entities are not related with other entities by inheritance, there is a simple mapping between entities and database tables. Each entity gets a separeted table in the database. Things become more elaborated when entities are related by inheritance. The way the JPA provider maps a set of entities related by inheritance is knows as the inheritance mapping strategy. The strategy to use is defined with class annotation @Inheritance, that should be setup only at the root of entity tree. The mapping strategies known to JPA are defined by enumerate type InheritanceType, whose values are shown below:

Example: Inheritance Strategies

public enum InheritanceType {
	SINGLE_TABLE,
	JOINED,
	TABLE_PER_CLASS
`;

The meaning of each of values is explained below:

SINGLE_TABLE
A single table per class hierarchy
JOINED
A join strategy, whereby fields or properties that are specific to a subclass are mapped to a different table than the fields or properties that are common to the parent class.
TABLE_PER_CLASS
A table per concrete entity class

The default strategy is InheritanceType.SINGLE_TABLE. This is the value use if the @Inheritance annotation is not specified on the root class of the entity hierarchy.

The Single Table per Class Hierarchy Strategy

With this strategy, which corresponds to the default InheritanceType.SINGLE_TABLE, all classes in the hierarchy are mapped to a single table in the database. This table has a discriminator column containing a value that identifies the subclass to which the instance represented by the row belongs.

The discriminator column can be specified by using the javax.persistence.DiscriminatorColumn annotation on the root of the entity class hierarchy.

Table below summarizes the attributes of the @DiscriminatorColumn annotation.

NameTypeDefaultDescription
nameStringDTYPEName of discriminator column
discriminatorTypeDiscriminatorTypeSTRINGType of dicriminator column
columnDefinitionString(Impl.Dep.)SQL fragment to create discriminator column
lengthString31length of String discriminator column

Summary of attribute of @DiscriminatorColumn annotation.

The definition of the enumeration type DiscriminatorType is shown below:

Example: Discriminator Column Types

public enum DiscriminatorType {
	STRING,
	CHAR,
	INTEGER
};

If @DiscriminatorColumn is not specified on the root of the entity hierarchy and a discriminator column is required, the Persistence provider assumes a default column name of DTYPE and column type of DiscriminatorType.STRING.

The javax.persistence.DiscriminatorValue annotation may be used to set the value entered into the discriminator column for each entity in a class hierarchy. You may decorate only concrete entity classes with @DiscriminatorValue.

If @DiscriminatorValue is not specified on an entity in a class hierarchy that uses a discriminator column, the Persistence provider will provide a default, implementation-specific value. If the discriminatorType element of @DiscriminatorColumn is DiscriminatorType.STRING, the default value is the name of the entity.

This strategy provides good support for polymorphic relationships between entities and queries that cover the entire entity class hierarchy. However, this strategy requires the columns that contain the state of subclasses to be nullable.

The Table per Concrete Class Strategy

In this strategy, which corresponds to InheritanceType.TABLE_PER_CLASS, each concrete class is mapped to a separate table in the database. All fields or properties in the class, including inherited fields or properties, are mapped to columns into the class’s table.

This strategy provides poor support for polymorphic relationships and usually requires either SQL UNION queries or separate SQL queries for each subclass for queries that cover the entire entity class hierarchy.

Support for this strategy is optional and may not be supported by all Java Persistence API providers. The default Java Persistence API provider in the GlassFish Server does not support this strategy.

Joined Subclass Strategy

In this strategy, which corresponds to InheritanceType.JOINED, the root of the class hierarchy is represented by a single table, and each subclass has a separate table that contains only those fields specific to that subclass. That is, the subclass table does not contain columns for inherited fields or properties. The subclass table also has a column or columns that represent its primary key, which is a foreign key to the primary key of the superclass table.

This strategy provides good support for polymorphic relationships but requires one or more join operations to be performed when instantiating entity subclasses. This may result in poor performance for extensive class hierarchies. Similarly, queries that cover the entire class hierarchy require join operations between the subclass tables, resulting in decreased performance.

Some Java Persistence API providers, including the default provider in the GlassFish Server, require a discriminator column that corresponds to the root entity when using the joined subclass strategy. If you are not using automatic table creation in your application, make sure that the database table is set up correctly for the discriminator column defaults, or use the @DiscriminatorColumn annotation to match your database schema. For information on discriminator columns, see The Single Table per Class Hierarchy Strategy.

The Entitiy Manager

The EntityManager Interface:

Example: EntityManager API Workflow

	String PERSISTENCE_UNIT_NAME = "Demo1";

	EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
	
	EntiryManager entityManager = factory.createEntityManager();

	entityManager.getTransaction().begin();
	
	//...do real work inside transactional contex
	
	entityManager.getTransaction().commit();
	
	entityManager.close();

Managing Entity Instances

An EntityManager provides the API need to manage entity instance, including: creation, removal, of persistent context.

Making Entities Persistent

New entities are made persistent by invoking method EntityManager.persist(). From this point on, the entity will have a persistent entity on the data store.

If the persist method is called on a entity that is already in a managed and persistent state the operation has not effect on that entity, but can affect related entities (see below). If the persist method is called on a removed entity instance, the entity becomes managed again. If the entity is detached, the exception IllegalArgumentException is thrown if there no on-going transaction. If there is an on-going transaction the commit operation will fail.

A simple example is shown below, where an entity instance of class User is made persistent.

Example: Persisting Entities

EntityManager entityManager = ... ;

public User createUser(String name, String email) {
	User u = new User(name, email);
	entityManager.persist(u);
	return u;
}

Another example is shown below, where a Job entity is related to a owning User entity. Note that the owning User is updated to reference the created job. However, it the User entity does not need to be made persistent again. Modifications to the User entity will be propagate to the database at transaction commit time or flushing time.

Example: Persisting Entities with Cascading

EntiryManager entityManager = ... ;

public Job createJob(User u, String jobName, String descr) {
	Job j = new Job(u, jobName, descr);
	u.getJobs().add(j);
	entityManager.persist(j);
	return j;
}

Persistence Propagation

When EntityManager.persist() is invoked on an entity that as related entities, and the cascade attribute is set to PERSIST or ALL in the relationship annotation, then the persist action is propagate to those related entities. This process applies recursively so that if a related entity $A$ is related to yet another entity $B$, $B$ is also made persistence provided that that cascade option set appropriately for that relation. This means that a persist operation might affect the state of a large tree of entities. (Formally, the persistence operation with the cascade options is said to be transitive.).

Note that if an entity is already in a managed and persistent state the operation persist() has not effect on the entity, but the recursive propagation rule still applies to that entity and its related entities.

As example of persist propagation, consider relation defined below:

Example: Association Property

@OneToMany(cascade=ALL, mappedBy="user")
public List<Job> getJobs() {
	return jobs;
}

Makes persist actions on a User entity to propagate to all related Job entities.

User u = ...;
u.addJob(new Job(u, "job1"));
u.addJob(new Job(u, "job2"));
entityManager.persist(u);

Finding Entities

The EntityManager.find() method is used to look up entities in the data store by the entity’s primary key:

Example: Finding Entity Instance by ID

EntiryManager entityManager = ... ;

public void addJob(int id, Job j) {
	User u = entityManager.find(User.class, id);
	j.setUser(u);
	u.getContacts().add(c);
}

Removing Entities

Managed entity instances are removed from the database by invoking the method EntityManager.remove. An entity instance set into the removed state, is scheduled for removal. A remove operation is mapped to a SQL DELETE statment. The statement is executed when the on-going transaction commits or a flush is performed. If remove is invoked on a detached entity, the remove operation throws an IllegalArgumentException exception if there is not on-going transcation. If a transaction is open the commit operation will fail.

When a entity is deleted all related entities for which the cascade option is set to REMOVE or ALL are also removed. As in the persist operation, the remove propagation is applied recursively. If instance asked for removal is a new entity and is not yet in a managed state, the operation is ignored for that entity since there is no persistante state to be removed from the store. However, the propagation rule still applies if the instance is related to other managed entities set with the cascade option appropriatelly.

Example: Deleteing Entity Instances

public void removeUser(long id) {
	try {
		User u = entityManager.find(User.class, id);
		entityManager.remove(u);
	} catch(..) {
	}
}

In the example above, a user is searched and removed from the store. All related Job instance will also be scheduled for removal, assuming the cascade option is set to REMOVE or ALL.

Table below summarizes the methods of the EntityManager class to manage individual entities.

MethodReturnsDescription
persist(Object entity) Make entity instance persistent
merge(T entity) Merge the state of the entity
refresh(Object entity) Refresh the in-memory state of the instance
remove(Object entity) Remove the entity instance
contains(Object entity)booleanCheck if the instance exists
find(Class<T> type, Object key)TFind by primary key
getReference(Class<T> type, Object key)TGet lazily fetched instance (proxy)

Summary of EntityManager methods to manage individual entities.

Synchronization and Flushing

The state of persistent entities is synchronized to the database when an on-going transaction associated with the entity commits. It also possible to force synchronization of managed entities to the data store, by invoking method EntityManager.flush().

If the entity is related to another entity and the relationship annotation has the cascade element set to PERSIST or ALL, the related entity’s data will be synchronized with the data store when flush is called.

If the entity is removed, calling flush will remove the entity data from the data store.

If a managed entity is in a bidirectional relationship with another managed entity, the data will be persisted, based on the owning side of the relationship.

Table below summarizes the methods of the EntityManager class.

MethodReturnsDescription
flush() Synchronize the persistence context
setFlushMode(FlushModeType mode) Set the flush mode
getFlushMode()FlushModeTypeGet the flush mode

Summary of EntityManager flushing methods.

Table below summarizes the methods of the EntityManager class for management of the full persistence context.

MethodDescription
clear()Clears the persistence context (detach all entitied)
isOpen()Check if EntityManager is open
close()Close the EntityManager
getDelegate()Get provider object for the EntityManager

Summary of EntityManager methods for management of the full persistence context.

Configuring the Persistency Unit

A persistence unit defines a set of all entity classes that are managed by EntityManager instances in an application. This set of entity classes represents the data contained within a single data store.

Persistence units are defined in a XML configuration file that should be named persistence.xml. This file should be located in a directory named META-INF. In eclipse IDE this is located under directory src.

Below we show an example:

Example: Persistence Unit Configuration

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
	http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

	<persistence-unit name="UserJobs" transaction-type="RESOURCE_LOCAL">

		<description>
			This a demo persistent unit with the description of users and jobs.
			</description>

		<class>demojpa.User</class>
		<class>demojpa.Job</class>

		<jar-file>UserJobs.jar</jar-file>

		<jta-data-source>jdbc/MyOrderDB</jta-data-source>
				
		<properties>
			<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
			<property name="javax.persistence.jdbc.url"
				value="jdbc:derby:db/demo1;create=true" />
			<property name="javax.persistence.jdbc.user" value="test" />
			<property name="javax.persistence.jdbc.password" value="test" />

			<!-- EclipseLink specific properties -->
			<property name="eclipselink.ddl-generation" value="create-tables" />
			<property name="eclipselink.ddl-generation.output-mode"
				value="database" />
		</properties>

	</persistence-unit>

</persistence>

Quering

Table below summarizes the methods of the EntityManager class to create Query objects.

MethodDescription
createNamedQuery(String name)Create named Query (JPQL or SQL)
createNativeQuery(String sql)Creates SQL query (UPDATE or DELETE)
createNativeQuery(String sql, Class resultType)Create SQL query (SELECT)
createNativeQuery(String sql, String resultSetMapping)Creates a SQL query
createQuery(String ql)Create JPQL query

Summary of EntityManager methods for creationg of Query objects.

Transactions and Locking

Table below summarizes the methods of the EntityManager class for management of the full persistence context.

MethodReturnsDescription
getTransaction()EntityTransactionGet resource-level transaction object
joinTransaction() Indicate that a JTA transaction is active
lock(Object entity, LockModeType lockMode) Set the lock mode for entity

Summary of EntityManager methods for transactions and locking.

Persistence inside a JEE Container

Example: Container-Managed Transactional Contexts

@Singleton
public clas MyService {

	@PersistenceContext
	private EntityManagerFactory emf;

	private EntiryManager entityManager;

	@Resource
	UserTransaction tx;

	public void doService() {
		entityManager = emf.createEntityManager();
		try {
			tx.begin();
			...
			tx.commit();
		} catch (Exception e) {
			utx.rollback();
		}
	}
}

Web Resources

Comments and Discussion

Content