analytics

Wednesday, April 13, 2011

EJB 3 Persistence

EJB 3 Persistence


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.

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:





The Basics of EJB3 JPA and O-R Mapping Framework:

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 retrieving the entities from the database and spares you from writing the SQL SELECT statements.


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 define 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 cannot 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. Let’s 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 getPhoneNumber() {}
void setPhoneNumbers(Set) {}

The O-R mapping annotations must be applied to the getter methods. Note here that mapping annotations cannot 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.

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.OneToManyannotation 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 has 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.


Let’s have an Example now

Create the Entity Class

In the Simple EJB Project, within the com.webage.ejbs package, create a new class called Customer.
In the Customer class, add the following import statement.

import javax.persistence.*;

Many of the annotations and classes for the persistence API will come from this package.

First, we must designate this class as an Entity. This is done using the @Entity annotation. Add this annotation at the class level as shown below.

@Entity

public class Customer {

Next, we will make the Customer class implement java.io.Serializable. Doing so will allow us to use this class are parameters to a remote business interface method. Add the code shown in bold face.

public class Customer implements Serializable {


Add the following two member variables. They will form the attributes (or database columns) for the entity.

private int id;
private String name;

Generate getter and setter methods for these fields (right click on the editor and select Source->Generate Getters and Setters).


The id field will act as the primary key column of the Customer. Declare that fact using the @Id annotation as shown below.

@Id
private int id;

Save changes. That's it, the Entity class is now complete.

Create the persistence.xml File


The persistence.xml file must be created within the META-INF directory of the EJB module. This file defines persistence units. Each unit is basically a reference to the data source that will be used to access the database. The unit can also contain configuration such as the type of database (Oracle, MySQL etc.) and if database tables should be automatically created by the persistence engine.

Within Simple EJB Project, create a folder called META-INF. Within this folder, create a new file called persistence.xml. In that file, add the following content.




jdbc/__default









Note the following aspects of this file:


1. The name of the unit is my_persistence_ctx. We will use this name to look it up from the code.

2. The unit will use a data source with JNDI name jdbc/__default. This data source is automatically defined when Glassfish is installed. In real life, you will probably use a database such as MySQL, Oracle or DB2. In that case, you must first define a data source using the Glassfish administration console.

3. We configure the persistence engine to automatically drop and create tables when the EJB JAR is deployed. This is a good choice during heavy development when the Entity classes are changing rapidly. If you do not wish the system to create tables, you can set the value of the toplink.ddl-generation property to none.

4. We set the SQL dialect to be specific to Derby. Examples of other platform classes are "oracle.toplink.essentials.platform.database.DB2Platform" for DB2 and "oracle.toplink.essentials.platform.database.oracle.OraclePlatform" for Oracle.

Save and close the persistence.xml file.

Use the Entity from a Session EJB


We will use the Customer Entity from the SimpleBean session bean created in the first tutorial. First, we will insert a few customers to the database.

Open the business interface SimpleBean.java. Add a new method as follows:

public void createCustomers();

Save and close the file.

Now, open the implementation class SimpleBeanImpl.java. Add a new member variable to obtain reference to the persistence unit as follows:

@PersistenceContext(name="my_persistence_ctx")

EntityManager em;

Note, how we use the name of the persistence unit here.

Add this method:

public void createCustomers() {

Customer c1 = new Customer();
c1.setId(1);
c1.setName("XYZ");
em.persist(c1);
}

The call to the EntityManager.persist() method will result in a SQL INSERT statement.


Save and close the file.

Deploy the EJB JAR

Deploy the EJB JAR file by exporting Simple EJB Project into the autodeploy folder as already mentioned in the previous tutorial.

Write the Client

In the Simple Client Project, open TestClient.java. Below this line:

SimpleBean bean = (SimpleBean) ctx.lookup("ejb/SimpleBeanJNDI");

Add:

bean.createCustomers();
Save the file.


Run the Client


Run the TestClient class as already described in the previous tutorial.

Note, you can run the client only once. Running it again will cause primary key collision and the customer cannot be added.


Inspect the Database

select * from customer;

 
Add More Database Access Feature


Now, we will add the ability to retrieve a Customer, update and delete it. This can be done entirely using the session EJB. We don't have to change the Entity class.

First, add the following methods to the business interface SimpleBean.java.

public Customer getCustomer(int id);
public void updateCustomer(Customer c);
public void deleteCustomer(Customer c);


Save and close the file.

Implement these new methods in SimpleBeanImpl.java as follows.

public Customer getCustomer(int id) {
Customer c = em.find(Customer.class, new Integer(id));
return c;
}

public void updateCustomer(Customer c) {
em.merge(c);
}


public void deleteCustomer(Customer c) {
c = em.merge(c); //Must do this
em.remove(c);
}

 
The EntityManager.merge() call will flag the Customer instance so that the data is used to update the underlying row. The updateCustomer() method relies on this behavior. The actual SQL UPDATE statement is issued at a later time, before the transaction is completed. The EntityManager.remove() call, results in a SQL DELETE statement to be executed. Note: To remove an entity, we must use a managed instance. The Customer object instance passed to the deleteCustomer() method is called detached as it is not currently managed by the EntityManager in any way. Merging will make the instance managed. A managed instance is always associated with the underlying row in the table. That means, the merge call will implicitly do a SELECT SQL call (if the instance is currently detached).


Save and close the file. Re-deploy the EJB JAR file.

Update the Client

Open TestClient.java.

Below the line:

bean.createCustomers();

Add:

Customer c = bean.getCustomer(1);
System.out.println("Retrieved customer: " + c.getName());
bean.deleteCustomer(c);

Save changes.

Make sure that you have re-deployed the EJB JAR file. Now, run the client. The Console view should show the message:

Retrieved customer: XYZ

Also, now you can run the client repeatedly as we delete the customer data.

No comments:

Post a Comment