Java Persistence API is the standard API used for the management of the
persistent data and object/relational mapping. Java Persistence API is added in Java EE 5 platform. Every application server compatible with Java EE 5
supports the Java Persistent APIs.
Java Persistence API ensures the management of
persistence and object/relational mapping. These are helpful while using the JPA
in the development of applications using the platform for Java EE 5. It
provides O-R mapping facility to manage relational data in java application. The
Java Persistence API contains the following areas:
- Java Persistence API
- O-R mapping metadata
- The query language
Features of JPA:
Java Persistence API is a
lightweight framework based on POJO for object-relational mapping. Java language
metadata annotations and/or XML deployment descriptor is used for the mapping
between Java objects and a relational database. It allows the SQL-like query
language that works for both static as well as dynamic queries. It also allows
the use of the pluggable persistence API. Java Persistence APIs are mainly
depends on metadata annotations. API includes:
- Java Persistence API
- Metadata annotations
- Java Persistence query language
Advantages of JPA:
Java Persistence API is build
upon the best ideas from the persistence technologies like TopLink, JDO and
Hibernate. Java Persistence API is compatible with Java SE environment as well
as Java EE and allows developers to take advantages of the standard persistence
API.
Persistency of data is not so easy for most of the
enterprise applications because for this they require access to the relational
database like Oracle 10g. It is your responsibility to update and retrieve the
database by writing the code using SQL and JDBC. While several object-relational
(O-R) frameworks such as JBoss Hibernate and OracleTopLink make persistence challenges
simpler and became popular. They let the java developer free from writing JDBC code and to concentrate only on the business logic. In EJB 2.x, container
manage persistence (CMP) try to solve the persistence challenges but not
successful completely.
Persistence tier of the application can be developed in
several ways but Java platform does not follow any standard that can be used by
both Java EE and Java SE environment. But the Java Persistence API (JPA) part of
EJB 3.0 spec (JSR-220) makes the persistence API standard for the Java platform.
O/R mapping vendors like Hibernate and TopLink as well as JDO vendors and other
leading application server vendors are receiving the JSR-220.
Here we are describing EJB3 JPA by using the
simple domain object model by an example.
Working process of an EJB application using JPA:

Domain Model:
While developing an enterprise
application, first design the domain object model required to persist the data
in the database. Domain model represents the persistence objects or entities in
the database. An entity represents a row in the data. An entity may be a person,
place or a thing about which you want to store the data in the database. A rich
domain model includes the characteristics of all the object oriented behavior
like inheritance, polymorphism and many more.
While developing an enterprise application, first
design the domain object model to persist the data in the database then design
the database schema with the help of database designer.
The figure illustrated below
shows the bi-directional one-to-many relationship between the Employee and
Department. The Contractor and the fulltime entities are inherited from the
entity Employee.
Sample domain object model
The Basics of EJB3 JPA and O-R Mapping Framework: Each
of the O-R mapping framework such as Oracle TopLink provides three facilities:
- It defines a declarative way known as O-R mapping
metadata to perform O-R mapping. Most of the framework use XML to store the
O-R mapping metadata.
- An API is required to manipulate like to perform
CRUD (CRUD stands for create, read, update, and delete) operations. The API allows you to persist, remove, update or retrieve
the object from the database. O-R framework performs operations using
the API and the O-R mapping metadata on your behalf.
- Use of a query language for retrieving objects from
the database is the proper way since improper SQL statements may result in
slow down the performance of the operation performing on the database. A query language allows
to retrieve the entities from the database and spares you from writing the
SQL SELECT statements.
EJB 3 provides a standard way to use the persistence by
providing a standard O-R mapping mechanism, a way to extend EJB-QL to retrieve
entities and an EntityManager API to perform CRUD operations.
EJB3 Java Persistence API (JPA) standardizes the use of persistence for
the Java platform by providing a standard mechanism for O-R mapping, an
EntityManager API to perform CRUD operations, and a way to extend EJB-QL to
retrieve entities. I'll discuss these three aspects of JPA later.
Metadata Annotation in Action: Metadata
annotations are first time introduced in Java SE 5.0. To make the development easy
all the components of Java EE including EJB3 uses the metadata annotations. In
EJB3 JPA annotation defines the objects, O-R mappings, and the relationships
among them. JPA also have another option to use XML descriptor, But use of the
metadata annotations make the development simpler and more efficient.
Entities:
An entity can be considered as a light
weight persistence domain object. An entity defines a table in a relational
database and each instance of an entity corresponds to a row in that table. An
entity refers to a logical collection of data that can be stored or retrieved as
a whole. For example, in a banking application, Customer and BankAccount
can be treated as entities. Customer name, customer address etc can be logically
grouped together for representing a Customer entity. Similarly account
number, total balance etc may be logically grouped under BankAccount
entity.
Persistence fields or persistent properties defines the persistent state of an
entity. To map the entities and their relationship to the data in the relational
database these entities use the object-relational mapping.
Requirements of Entity Classes: There are some
requirements that an entity must follow:
- The class must contain either a public or a protect
no argument constructor, while it can contain other constructors.
- The class as well as methods and persistence
instance variables must not be declared as final.
- Use the annotation javax.persistence.Entity to
annotate the class.
- Declare the persistence instance variables as
protected, private or package-private so that they can directly
accessed only by the entity class's methods.
- Entity class may extend the entity as well as
non-entity classes or vice-versa.
- The class must implement the serializable interface
if an entity instance is passed by value.
Persistence Fields and Properties in Entity Classes:
There are two ways to access the persistent state of an entity either by
instance variables or by using the JavaBeans-style properties. The fields or the
properties must follow the Java language types:
- Java primitive types
- java.lang.String
- Other serialization types including:
- wrappers of java primitive types
- java.util.Date
- java.util.Calender
- java.math.BigDecimal
- java.math.BigInteger
- java.sql.Time
- java.sql.Date
- java.sql.TimeStamp
- User-defined serializable types
- char[]
- Character[]
- byte[]
- Byte[]
- Enumerated types
- Other entities and/or collection of entities
- Embedded classes
Entity uses the persistent fields while mapping
annotations. Annotations are applied to the entity's instance variable. On the other hand
entity uses the persistence properties while mapping annotations. Annotations are applied to
the entity's getter methods for JavaBeans-style properties. We can not apply
mapping annotations to both fields as well as properties simultaneously in a
single entity.
Persistence Fields: Persistence accesses the
entity class instance variables directly at runtime, if the entity class uses
persistence fields. It is necessary to apply the object/relational mapping
annotation on the instance variables.
Persistent Properties: Entity must follow the
method conventions of JavaBeans components while using the persistent
properties. JavaBeans-style properties use getter and setter methods that are
used after the entity class's instance variable names. There is a getter and a setter method for each persistence property. In case of a boolean property you
may use isProperty instead of getProperty. Lets take an example to clarify this:
Suppose an entity of type customer uses persistent
property that has a private instance variable named firstName, the class defines
two methods named getFirstName and setFirstName to retrieve and set the values
of the instance variable. Use the following method signature for a single-valued
persistent property.
- Type getProperty()
- void setProperty(Type type)
Multi-valued (Collection-valued) persistent fields and
properties must use the supported Java collection interfaces without worrying
whether the entity uses the persistence fields or properties. The collection
interfaces may be used at the following places:
- java.util.Collection
- java.util.Set
- java.util.Map
- java.util.List
If the entity class uses persistent fields then the
method signatures of the collection types must be one of these collection types.
Suppose an entity of type customer includes a persistent property that uses a
set of phone numbers then it should have the following methods:
Set<PhoneNumber> getPhoneNumber() {}
void setPhoneNumbers(Set<PhoneNumber>) {}
The O-R mapping annotations must be applied to the
getter methods. Note here that mapping annotations can not be applied to the
fields or properties marked transient or annotated transient.
Primary Keys in Entities:
Each entity contains a
unique identity contained in the object. E.g. A customer entity has an identity
that might be identified by the customer number. A primary key allows a client
to be a particular entity instance. Every unique entity must be associated with
a primary key. To prove its uniqueness every entity may have either a simple or
a composite primary key.
To denote the primary key property or field Simple primary key use
javax.persistence.Id annotations.
Composite primary keys must be composed of either a
single persistent property or field or a set of single persistent properties or
fields. Composite primary keys uses javax.persistence.IdClass and
javax.persistence.EmbededId.
The primary key, or the fields of the composite primary
key (like property or field) must follow one of the following Java language
types.
- Java primitive types
- Java primitive wrapper types
- java.lang.String
- java.util.Date (the temporal type should be
DATE)
- java.sql.Date
Floating point types are not allowed to use in primary
keys.
Primary Key Classes: A primary class must follow
the certain rules:
- The class must have an access modifier as public.
- The class must include a public default constructor.
- Primary key must contain the properties of the type
public or protected if property-based access is used.
- The class must be serialized.
- The class must implement the equals(Other other) and
hashCode() methods.
- If the class has the mapping to multiple fields or
properties of the entity class then the names and types of the primary key
fields must match with those of the entity class.
The fields order_Id and itemId are combined together
to make the primary key to uniquely identify the composite key. The
code for managing composite key is shown as:
public final class ListItemKey implements Serializable{
public Interger order_Id;
public int item_Id;
public ListItemKey() {}
public ListItemKey(Integer order_Id, int item_Id){
this.order_Id = order_Id;
this.item_Id = item_Id;
}
public boolean equals(Object otherOb){
if(this == otherOb){
return true;
}
if(!otherOb instanceof ListItemKey){
return false;
}
ListItemKey other = (ListItemKey) otherOb;
return ((order_Id==null?other.order_Id==null:order_Id.equals(other.order_Id))
&&(item_Id == other.item_Id));
}
public int hashCode(){
return ((orderId==null?0:orderId.hashCode())^((int) itemId));
}
public String toString() {
return "" + orderId + "-" + itemId;
}
}
|
Multiplicity in Entity Relationships:
There are
four types of multiplicities defined for entity relationships like one-to-one,
one-to-many, many-to-one, and many-to-many.
One-to-one: When each entity instance is mapped
to a single instance of another entity, then the mapping is known as
one- to-one
mapping. One-to-one relationships use the javax.persistence.OneToOne annotation
on the corresponding persistent field or property.
For Example: A reference variable in
java contains the address of a single object so that there exists only one-to-one
mapping between the object of the reference variable.
One-to-many: When an entity instance is related
to many instances of other entities, then the relation is known as
one-to-many. These types of relationships use the javax.persistence.OneToMany
annotation on the corresponding field or property.
For Example: A sales order may contain the order
of multiple items so there is a one-to-many relationship between the sales order
and the items.
Many-to-many: When the multiple instances of an
entity have the mapping to the multiple instances of the other entity then the mapping is said to many-to-many mapping. Many-to-many mapping
relationships use the javax.persistence.ManyToMany annotation corresponding to
the field or property.
For Example: A college student have the
admission in several courses while each course may have many students. Therefore
there is many-to-many relationship between the students and the courses.
Direction in Entity Relationships: A
relationship can be either unidirectional or bi-directional.
Unidirectional Relationship: A
unidirectional relationship is a relationship in which only one of the two
entities have the owing side. In unidirectional relationship only one entity can
have the relationship property or field that may refer to the other.
Example: In the example given above, the
List_Item contains the relationship field that refers to the other entity named
as Product, while the Product doesn't have any knowledge about the List_Item that
refers to it.
Bi-directional
Relationships: A bi-directional relationship
is the relationship in which both the entities have the owing side. In bi-directional relationship each entity in the relation
have the relationship fields or property.
Example: Suppose the Order in the above example
have the knowledge about the List_Item instance it has and also suppose that the
List_Item have the knowledge about what the Order it belongs to, then the
relationship between them is said to be the bi-directional relation.
Rules: There are some rules that each bi-directional
relationship must follow:
- You must use its owing side simply using the mappedBy
element of the @OneToOne, @OneToMany, or @ManyToMany annotation of the
inverse side of a bi-directional relationship. mappedBy element is
used to designate the field or property in an entity.
- In a one-to-one bi-directional relationship, owing
side is the side that contains the corresponding foreign key.
- In a many-to-one bi-directional relationships the
many side is always the owing side of the relationship and must not define
the mappedBy element.
- In case of many-to-many bi-directional relationships
either side may be the owing side.
Queries and Relationship Direction:
Java
Persistence query language navigates queries across relationships. The direction
of the relationship can be determined by checking the navigation of a query from
one entity to another.
Example: In case of the
unidirectional relationship, in the above example a query can navigate from
List_Item to Product, but can not navigate from Product to List_Item.
In case of the
above Order and List_Item, a query can navigate in both the direction because both the entities have
the bi-directional relationship.
Cascade Deletes and Relationships:
Entities
having the relationships are dependent on other entities in the relationship.
Lets take the above example to clarify this: While deleting the order, the list
item is also deleted since it is the part of the order, this is known as cascade
delete relationship. Use the element cascade=REMOVE element to delete the
cascade relationships specified for @OneToOne and OneToMany relationship.
Example: OneToMany(cascade=REMOVE, mappedBy="customer")
public Set<Order>getOrders() {
return order; }
Entity Inheritance: Entities also
supports the various features like inheritance, polymorphic queries, and
polymorphic associations. Moreover they can also be the non-entity classes, while
the non-entity classes can also extend the entity classes. These entity classes
can be of the type either concrete or abstract.
Abstract Entities: An abstract
class can be defined as entity simply by declaring the class with the @Entity.
The difference between the abstract and the concrete entities is that the
concrete entities can be instantiated while the abstract entities can not.
Concrete entities are queried same as the
abstract entities. Suppose a query makes the target to an abstract entity then
the query operates on all the concrete subclasses of the abstract entity.
@Entity
public abstract class Student{
@Roll_no
protected Integer StudentRoll_no;
............
}
@Entity
public class FullTimeStudent extends
Student{
public Integer fee;
............
}
@Entity
public class PartTimeStudent extends
Student{
protected Float classTime;
}
|
Mapped Superclasses: We can inherit
the entities from their superclasses containing the persistence state and the
mapping information but are not entities. The super class does not need to
decorate with the @Entity annotation, and does not map as an entity by the
Java Persistence provider. These superclasses are used in most of the cases when
the multiple entity classes have the common state and mapping information.
Mapping superclasses are declared simply
by specifying the class with the javax.persistence.MappedSuperclass annotation.
@MappedSuperclass
public class Student{
@Roll_no
protected Integer StudentRoll_no;
............
}
@Entity
public class FullTimeStudent extends
Student{
protected Integer fee;
..................
}
@Entity
public class PartTimeStudent extends
Student{
protected Float classTime;
.............
}
|
We can not query the mapped
superclasses and can also neither be used in Query operations nor EntityManager.
But use the entity subclasses of the mapped superclasses to perform the
Query operations or EntityManager. Entity relationship can not target to the
mapped superclasses. Mapped superclass can be either of concrete or abstract
type and also don't have any corresponding table in the underlying
database. Entities inherited from the mapped superclasses define the table-mapping. For instance the above code snippet contains the underlying table
FULLTIMESTUDENT and PARTTIMESTUDENT but did not have any STUDENT table.
Non-Entity Superclasses: As
discussed above that the entities may have non-entity superclasses and these
superclasses can either be abstract or concrete. The state of the non-empty
superclasses and any state inherited from these superclasses are not persistent.
Non-entity superclasses can be used either in Query operations or in
EntityManager. While the non-entity superclasses ignore any mapping or
relationship annotations.
Entity Inheritance Mapping Strategies: There
is a way to configure the mapping between the underlying datastore and the
inherited entities simply by decorating the parent class in the hierarchy with
the javax.persistence.Inheritance annotation. Entities
uses three types of mapping strategies to map the entity data to the underlying
database.
-
A
table for each concrete entity class.
-
A
single table for each class hierarchy.
-
A
"join" strategy for the specific fields or properties to a
subclass are mapped to different tables rather than the fields that are
common to the parent class.
You can
configure the strategy simply by setting the "strategy" element
of @Inheritance to one of the options defined in the
javax.persistence.InheritanceType enumerated type:
public
enum InheritanceType{
SINGLE_TABLE,
JOINED, TABLE_PER_CLASS
};
InheritanceType.SINGLE_TABLE
is the default strategy value and is used in such situations where @Inheritance annotation
is not specified in the parent class of the hierarchy.
Single Table per Class Hierarchy Strategy: This strategy corresponds to the
default InheritanceType.SINGLE_TABLE, a single table in the database is mapped
to all the classes in the hierarchy. This table includes a column containing a
value to identify the subclass that belongs to the row represented by the
instance. This column is known as discriminator column and can be specified by
the javax.persistence.DiscriminatorColumn annotation at the root in the class hierarchy
of the entity. The javax.persistence.DiscriminatorType enumerated type is used to
set the type of the discriminator column in the database simply by setting the discriminatorTypeelement of @DiscriminatorColumn to one of the defined types. DiscriminatorTypeis defined as:
public enum DiscriminatorType{
STRING, CHAR, INTEGER
};
While @DiscriminatorColumn in not specified at the root of the entity hierarchy
and the discriminator column is required then the persistence provider assumes
the coulumn type as DiscriminatorTypeSTRING and column name as DTYPE by default.
Ads