GlassFish Project - Java Persistence Example 

New to GlassFish | Community Guidelines | Downloads | FAQ | How-Tos

Overview

This is a very simple example that uses only 2 entities - a Customer and an Order, with OneToMany relationships between them. The Customer and the Order classes are Plain Old Java Classes (POJOs). These classes, as well as the code that manipulates POJO instances, can be used without any changes in Java SE or Java EE environment.

Accessing an EntityManagerFactory and an EntityManager depends on the environment and is described in more details below.

We will create a customer and two related orders, find the customer, and navigate from the customer to its orders, and then merge and remove all the objects. All these operation will be performed using Java Persistence API and require JDK 5.0.

Click here to get the ZIP file with the complete Java SE example as a netbeans project. This example works with Java DB or with Oracle.

Click here to get the ZIP file with the complete Java SE example. This example works with Oracle.

Click here to get the ZIP file with the complete Java EE example.

Refer to Java Persistence API document of JSR-220: Enterprise JavaBeansTM 3.0 Specification for further details on annotations and APIs.

Check example sources for the necessary import statements.

Mapping to Existing Tables

In the first example we will use only two tables:

CUSTOMER
ID
NAME


ORDER_TABLE
ORDER_ID
SHIPPING_ADDRESS
CUSTOMER_ID


CUSTOMER_ID column in the ORDER_TABLE is the Foreign Key (FK) to the ID column from the CUSTOMER table. The files sql/tables_oracle.sql and sql/tables_derby.sql in the example contains DDL to create both tables for Oracle and Apache Derby.

POJO Classes

Now let's look at the corresponding persistence classes. Both entities in this example use property based persistence. There is no access annotation element on the entity, so it defaults to access=PROPERTY. This is the reason why @Column annotation is specified for the get methods and not for the fields. The classes that are used as an argument or a return type between a  remote client and a container must implement java.io.Serializable interface.
The POJO classes in the examples belong to an entity package.

Customer

The Customer entity is mapped to the CUSTOMER table, and looks like this:

@Entity
public class Customer {

    private int id;
    private String name;
    private Collection
<Order> orders;

    @Id
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public
String getName() {
        return name;
    }

    public void setName(String
name) {
        this.
name = name;
    }


    @OneToMany(cascade=ALL, mappedBy="customer")
    public Collection<Order> getOrders() {
        return orders;
    }

    public void setOrders(Collection<Order> newValue) {
        this.orders = newValue;
    }

}

Note that there are no @Table and @Column annotations. This is possible because the persistence provider will use the default rules to calculate those values for you. See chapter 9 of the Java Persistence API Specification for detailed rules of the mapping annotations.

Order

The Order entity is mapped to the ORDER_TABLE table. It requires both @Table and @Column mapping annotations because table and column names do not match class and properties names exactly. @Column annotations are specified for the corresponding get methods:

@Entity
@Table(name="ORDER_TABLE")

public class Order {

    private int id;
    private String address;
    private Customer customer;

    @Id
   
@Column(name="ORDER_ID")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

   
@Column(name="SHIPPING_ADDRESS")
    public String getAddress() {
        return
address;
    }

    public void set
Address(String address) {
        this.
address = address;
    }


    @ManyToOne()
    @JoinColumn(name="CUSTOMER_ID")
    public Customer getCustomer
() {
        return
customer;
    }

    public void setCustomer
(Customer customer) {
        this.
customer = customer;
    }

}

Note that Customer and Order have bidirectional relationships between the entities.

Persisting POJO Entities

Now, let's create new instances, set up the relationships and persist all of them together using the CASCADE option that we set on the Customer entity. This code must be executed in a context of an active transaction.

    // Create new customer
    Customer customer0 = new Customer();
    customer0.setId(1);
    customer0.setName("Joe Smith");

    // Persist the customer
    em.persist(customer0);

    // Create 2 orders
    Order order1 = new Order();
    order1.setId(100);
    order1.setAddress("123 Main St. Anytown, USA");

    Order order2 = new Order();
    order2.setId(200);
    order2.setAddress("567 1st St. Random City, USA");

    // Associate orders with the customer.

Note that the association must be set on both sides of the relationship: on the customer side for the orders to be persisted when transaction commits, and on the order side because it is the owning side:

    customer0.getOrders().add(order1);
    order1.setCustomer(customer0);
 
    customer0.getOrders().add(order2);
    order2.setCustomer(customer0);

When this transaction commits, all three entities will be persisted in the database.

Query and Navigation

We'll use a new EntityManager to do the query, but will execute the query without an active transaction:

    // Create new EntityManager
    em = emf.createEntityManager();

    Query q = em.createQuery("select c from Customer c where c.name = :name");
    q.setParameter("name", "Joe Smith");
   
Our query is supposed to return a single customer, so we will use the Query method getSingleResult() to execute the query. This method would throw an exception if there is no or more than one matching customers.

    Customer c = (Customer)q.getSingleResult();


Now let's verify that the orders were also created by navigating from the Customer.
You can print the orders, but we'll just check the size:
   
      Collection<Order> orders = c.getOrders();
    if (orders == null || orders.size() != 2) {
        throw new RuntimeException("Unexpected number of orders: "
                + ((orders == null)? "null" : "" + orders.size()));
    }

Merge and Removal of Persistent Instances

To remove an instance, it must be managed by this EntityManager. The code below uses a customer 'c' that had been detached from its persistence context. Removal of the Customer also removes related orders because of the CASCADE option set on the corresponding relationship. This code must be executed in a context of an active transaction.

    // Merge the customer to the new persistence context
    Customer c0 = em.merge(c);

Note that merge() is not a void operation. It returns back a managed copy of the argument (and its related objects). Only this copy can be used for EntityManager operations.

    // Delete all records
    em.remove(c0);

Putting It All Together

Using in Java SE

First, we need to create an EntityManagerFactory that we will use in the example. An EntityManagerFactory is created once for each PersistentUnit. Persistent unit in this example is called "pu1".

   // Create EntityManagerFactory for persistent unit named "pu1"
   // to be used in this test
   emf = Persistence.createEntityManagerFactory("pu1");


For each business method in the example, a new EntityManager is created:

    // Create new EntityManager
    em = emf.createEntityManager();

If a transaction required, it is started:

    // Begin transaction
    em.getTransaction().begin();

And then the business logic is executed in a separate business method:

        // Business logic
        mybusinessmethod(...);

If transaction has been started it must be committed:

    // Commit the transaction
    em.getTransaction().commit();

And EntityManager should always be closed if it won't be used again:

    // Close this EntityManager
    em.close();

Java SE client code in this example is located in the class client.Client.

To run the test, you need to create META-INF/persistence.xml file in the classpath. Copy META-INF/persistence.xml.template file from the classes directory in the example to META-INF/persistence.xml and populate the values of the corresponding properties with the database settings that you are using. Note that persistence-unit name is set to "pu1" and all entity classes are explicitly listed.

Add your database driver and classes directory from the unzipped example to the classpath, load the tables into the database, then run:

java -javaagent:${glassfish.home}/lib/toplink-essentials-agent.jar client.Client

 

Using the Java SE Example in Netbeans

Configuring the JDBC driver

To configure the JDBC driver to be used when running the project, right-click on the project, select properties. Click on the libraries and then click on the 'Add JAR/Folder' button to add the jars for the JDBC driver being used. In the example below, the Java DB/Derby JDBC Client Driver is added.

Creating the tables

Scripts are provided to create the tables needed for the example for either Java DB/Derby or Oracle.

Note:If you are using Oracle, go to the runtime tab, click databases and then right click drivers to add the Oracle driver so that it can be used with the SQL Editor.

Configuring the persistence unit

To configure the persistence unit for the sample, click on source packages and then click on META-INF. Double click on persistence.xml. Your configuration should look like the following if you are using Java DB/Derby:

Running the project:

To run the the sample application. Right click on the project and select 'Run Project'.

 

Using in Java EE

In a Java EE container, the client code will not create an EntityManagerFactory - it is done by the container.

There are several option to get a hold of an EntityManager:
Transaction boundaries depend on the EntityManager type:
In our example a JTA EntityManager is injected by the container into the Session Bean:

    @PersistenceContext(unitName="pu1")
    private EntityManager em;


Transaction boundaries set to container-managed defaults.

The client code from the Java SE example is now divided between a Stateless Session Bean ejb.TestBean (implements ejb.Test remote business interface), which contains the business logic (i.e. exactly the same business methods as the Java SE client), and an application client client.AppClient that calls the corresponding methods and prints the output:

    // Persist all entities
    System.out.println("Inserting Customer and Orders... " + sb.testInsert());
 
    // Test query and navigation
    System.out.println("Verifying that all are inserted... " + sb.verifyInsert());
 
    // Get a detached instance
    Customer c = sb.findCustomer("Joe Smith");
 
    // Remove all entities
    System.out.println("Removing all... " + sb.testDelete(c));
 
    // Query the results
    System.out.println("Verifying that all are removed... " + sb.verifyDelete());



In the Java EE environment META-INF/persistence.xml does not need to list persistence classes, or the <provider> (if you use the default persistence provider). It should specify <jta-data-source>, if it does not use the default DataSource provided by the container. The example specifies jdbc/__default, which is the default for the Derby database, so that it is easy to replace with another name. Java EE example uses automatic table generation feature in GlassFish by setting required properties in the META-INF/persistence.xml.

To test the example, unzip it and deploy ex1-ee.ear file:

    ${glassfish.home}/bin/asadmin deploy --retrieve . ex1-ee.ear

Then execute the appclient script:

    ${glassfish.home}/bin/appclient -client ./ex1-eeClient.jar -mainclass client.AppClient

The Result

This is the output (after several extra log messages) that will be printed:

Inserting Customer and Orders... OK
Verifying that all are inserted... OK
Removing all... OK
Verifying that all are removed... OK


Read the packaging rules and other useful information on the Entity Persistence page for the next steps.