vogella.de

Follow me on twitter
About Lars Vogel
Flattr this

Java Persistence API (JPA) with EclipseLink - Tutorial

Lars Vogel

Version 1.0

18.10.2010

Revision History
Revision 0.103.02.2008Lars Vogel
Created
Revision 0.2 - 1.029.09.2008 - 18.08.2010Lars Vogel
bug fixes and enhancementss

JPA with Eclipselink

This article explains how to use EclipseLink, the reference implementation for the Java Persistence API (JPA). The usage of EclipseLink is demonstrated for stand-aloneJava applications (outside the Java EE environment).


Table of Contents

1. JPA
1.1. Overview
1.2. Entity
1.3. Persistence of fields
1.4. Relationship Mapping
1.5. Entity Manager
1.6. Persistence Units
2. Installation
2.1. EclipseLink
2.2. Derby Database
3. Example
3.1. Data model
3.2. Persistence Unit
3.3. Entity Manager
4. Thank you
5. Questions and Discussion
6. Appendix: Using JPA with XML metadata
6.1. XML Metadata
6.2. Example
7. Links and Literature
7.1. Java Persistence API Resources

1. JPA

1.1. Overview

The process of mapping Java Objects to database tables and vice versa is called "Object-relational mapping"" (ORM). The Java Persistence API (JPA) is one approach to ORM. Via JPA the developer can map, store, update and retrieve data from relational databases to Java Objects and vice versa, JPA permits the developer to work directly with objects rather then with SQL statements. JPA is a specification and several implementations are available. This tutorial will use EclipseLink as JPA implementation. The JPA implementation is typically called persistence provider. JPA can be used in Java-EE and Java-SE applications.

The mapping between Java objects and database tables is defined via persistence metadata, JPA defines the metadata via annotations in the Java class. Alternatively the metadata can be defined via XML or a combination of both. A XML configuration overwrites the annotations. The JPA provider will use the persistence metadata information to perform the correct database operations.

JPA also defines a SQL-like Query language for static and dynamic queries.

Most JPA persistence provider offer the option to create automatically the database schema based on the metadata.

The following description will be based on the usage of annotations.

1.2. Entity

To allow that a class can be persisted it must be annotated with "javax.persistence.Entity"". JPA will create a table for the entity in your relational database, e.g. every entity class will be mapped to at least one table. Instances of the class will be a row in the table.

All entities must have a primary key. Keys can be a single field or a combination of fields. JPA allows to auto-generate the primary key in the database via the @GeneratedValue annotation.

By default, the table name corresponds to the class name. You can change this with the addition to the annotation @Table(name="NEWTABLENAME").

1.3. Persistence of fields

The fields of the Entity will be saved in the database. JPA can use either your instance variables (fields) or the corresponding getters and setters to access the fields. You are not allowed to mix both methods. If you want to use the setter and getter methods the Java class must follow the Java Bean naming conventions. JPA persists per default all fields of an Entity, if fields should not be saved they must be marked with @Transient.

By default each field is mapped to a column with the name of the field. You can change the default name via @Column(name="newColumnName").

The following annotations can be used.

Table 1.  Annotations for fields / getter and setter

@Id Identifies the unique ID of the database entry
@GeneratedValue Together with ID defines that this value is generated automatically.
@Transient Field will not be saved in database

1.4. Relationship Mapping

JPA allows to define relationships between classes, e.g. it can be defined that a class is part of another class (containment). Classes can have one to one, one to many, many to one, and many to many relationships with other classes.

A relationship can be bidirectional or unidirectional, e.g. in a bidirectional relationship both classes store a reference to each other while in an unidirectional case only one class has a reference to the other class. Within a bidirectional relationship you need to specify the owning side of this relationship in the other class with the attribute "mappedBy", e.g. @ManyToMany(mappedBy="attributeOfTheOwningClass".

Table 2. Relationship annotations

@OneToOne
@OneToMany
@ManyToOne
@ManyToMany

1.5. Entity Manager

The entity manager "javax.persistence.EntityManager" provides the operations from and to the database, e.g. find objects, persists them, remove objects from the database, etc. In a JavaEE application the entity manager is automatically inserted in the web application. Outside JavaEE you need to manage the entity manager yourself.

Entities which are managed by an Entity Manager will automatically propagate these changes to the database (if this happens within a commit statement). If the Entity Manager is closed (via close()) then the managed entities are in a detached state. If synchronize them again with the database a Entity Manager provides the merge() method.

The persistence context describes all Entities of one Entity manager.

1.6. Persistence Units

The EntityManager is created by the EntitiyManagerFactory which is configured by the persistence unit. A set of entities which are logical connected will be grouped via a persistence unit. These persistence units are described via the file "persistence.xml" in the directory META-INF in the source folder. "persistence.xml" defines the connection data to the database, e.g. the driver, the user and the password,

2. Installation

2.1. EclipseLink

Download the EclipseLink implementation from http://www.eclipse.org/eclipselink/downloads/ . The download contains several jars. We need the following jars:

  • eclipselink.jar

  • persistence.jar

2.2. Derby Database

The example later will be using Derby as a database. Download Derby from http://db.apache.org/derby/ From this tutorial we will need the "derby.jar".

For a tutorial on Derby (which is not required for this tutorial) please see Apache Derby .

3. Example

3.1. Data model

The following will demonstrate the usage of JPA.

Create a Java project "de.vogella.jpa.eclipselink". Create a folder lib, place the required JPA jars into this folder and add them to the classpath as described earlier. Also add the derby.jar to the folder lib and add it to the classpath .

Create a package "de.vogella.jpa.eclipselink.model" and create the following classes.

				
package de.vogella.jpa.eclipselink.model;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Family {
	@Id
	@GeneratedValue(strategy = GenerationType.TABLE)
	private int id;
	private String description;

	@OneToMany(mappedBy = "family")
	private final List<Person> members = new ArrayList<Person>();

	public int getId() {
		return id;
	}

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

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public List<Person> getMembers() {
		return members;
	}

}

			

				
package de.vogella.jpa.eclipselink.model;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

@Entity
public class Person {
	@Id
	@GeneratedValue(strategy = GenerationType.TABLE)
	private String id;
	private String firstName;
	private String lastName;

	private Family family;

	private String nonsenseField = "";

	private List<Job> jobList = new ArrayList<Job>();

	public String getId() {
		return id;
	}

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

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	// Leave the standard column name of the table
	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@ManyToOne
	public Family getFamily() {
		return family;
	}

	public void setFamily(Family family) {
		this.family = family;
	}

	@Transient
	public String getNonsenseField() {
		return nonsenseField;
	}

	public void setNonsenseField(String nonsenseField) {
		this.nonsenseField = nonsenseField;
	}

	@OneToMany
	public List<Job> getJobList() {
		return this.jobList;
	}

	public void setJobList(List<Job> nickName) {
		this.jobList = nickName;
	}

}
			

				
package de.vogella.jpa.eclipselink.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Job {
	@Id
	@GeneratedValue(strategy = GenerationType.TABLE)
	private int id;
	private double salery;
	private String jobDescr;

	public int getId() {
		return id;
	}

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

	public double getSalery() {
		return salery;
	}

	public void setSalery(double salery) {
		this.salery = salery;
	}

	public String getJobDescr() {
		return jobDescr;
	}

	public void setJobDescr(String jobDescr) {
		this.jobDescr = jobDescr;
	}

}

			

3.2. Persistence Unit

Create a directory META-INF in your src folder and create the following file persistence.xml.

Each JPA provider is free to define its own parameter values for the database connection, user, password, etc. Some the parameters in this examples are therefore EclipseLink specific.

Please adjust the path of your database. This database will be created automatically.

				
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
	xmlns="http://java.sun.com/xml/ns/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_1_0.xsd">
	<persistence-unit name="people">
	
		<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

		<class>de.vogella.jpa.eclipselink.model.Family</class>
		<class>de.vogella.jpa.eclipselink.model.Person</class>
		<class>de.vogella.jpa.eclipselink.model.Job</class>
		<properties>
			<property name="eclipselink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
			<property name="eclipselink.jdbc.url" value="jdbc:derby:C:/DerbyDatabases/hellojpa-database8;create=true" />
			<!-- I work in this example without user / password.-->
			<property name="eclipselink.jdbc.user" value="" />
			<property name="eclipselink.jdbc.password" value="" />

			<!-- EclipseLink should create the database schema automatically -->

			<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
			<property name="eclipselink.ddl-generation.output-mode" value="database" />
		</properties>

	</persistence-unit>
</persistence>
			

Tip

Via the parameter "eclipselink.ddl-generation" you specify that the database scheme will be automatically dropped and created.

Tip

To see the SQL generated for the the databases set eclipselink.ddl-generation.output-mode value from "database" to "sql-script" or "both". Two files will get generated 'createDDL.jdbc' and 'dropDDL.jdbc'

3.3. Entity Manager

The following is implemented as a Junit Test. See JUnit Introduction. for more information on JUnit testing.

Tip

If you don't like testing I assume you are able to translate the JUnit tests into a normal main method.

The setup() method will create a few test entries. After the test entries are created, they will be read and the one field of the entries is changed and saved to the database.

				
package de.vogella.jpa.eclipselink.main;

import static org.junit.Assert.assertTrue;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import org.junit.Before;
import org.junit.Test;

import de.vogella.jpa.eclipselink.model.Family;
import de.vogella.jpa.eclipselink.model.Person;

public class JpaTest {

	private static final String PERSISTENCE_UNIT_NAME = "people";
	private EntityManagerFactory factory;

	@Before
	public void setUp() throws Exception {
		factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
		EntityManager em = factory.createEntityManager();

		// Begin a new local transaction so that we can persist a new entity
		em.getTransaction().begin();

		// Read the existing entries
		Query q = em.createQuery("select m from Person m");
		// Persons should be empty

		// Do we have entries?
		boolean createNewEntries = (q.getResultList().size() == 0);

		// No, so lets create new entries
		if (createNewEntries) {
			assertTrue(q.getResultList().size() == 0);
			Family family = new Family();
			family.setDescription("Family for the Knopfs");
			em.persist(family);
			for (int i = 0; i < 40; i++) {
				Person person = new Person();
				person.setFirstName("Jim_" + i);
				person.setLastName("Knopf_" + i);
				em.persist(person);
				// First we have to persists the job
				// Now persists the new person
				family.getMembers().add(person);
				em.persist(person);
				em.persist(family);
			}
		}

		// Commit the transaction, which will cause the entity to
		// be stored in the database
		em.getTransaction().commit();

		// It is always good practice to close the EntityManager so that
		// resources are conserved.
		em.close();

	}

	@Test
	public void checkAvailablePeople() {

		// Now lets check the database and see if the created entries are there
		// Create a fresh, new EntityManager
		EntityManager em = factory.createEntityManager();

		// Perform a simple query for all the Message entities
		Query q = em.createQuery("select m from Person m");

		// We should have 40 Persons in the database
		assertTrue(q.getResultList().size() == 40);

		em.close();
	}

	@Test
	public void checkFamily() {
		EntityManager em = factory.createEntityManager();
		// Go through each of the entities and print out each of their
		// messages, as well as the date on which it was created
		Query q = em.createQuery("select f from Family f");

		// We should have one family with 40 persons
		assertTrue(q.getResultList().size() == 1);
		assertTrue(((Family) q.getSingleResult()).getMembers().size() == 40);
		em.close();
	}

	@Test(expected = javax.persistence.NoResultException.class)
	public void deletePerson() {
		EntityManager em = factory.createEntityManager();
		// Begin a new local transaction so that we can persist a new entity
		em.getTransaction().begin();
		Query q = em
				.createQuery("SELECT p FROM Person p WHERE p.firstName = :firstName AND p.lastName = :lastName");
		q.setParameter("firstName", "Jim_1");
		q.setParameter("lastName", "Knopf_!");
		Person user = (Person) q.getSingleResult();
		em.remove(user);
		em.getTransaction().commit();
		Person person = (Person) q.getSingleResult();
		// Begin a new local transaction so that we can persist a new entity

		em.close();
	}
}

			

The project should now look like the following.

You should be able to run the JUnit tests sucessfully .

4. Thank you

Thank you for practicing with this tutorial.

I maintain this tutorial in my private time. If you like the information please help me by using flattr or donating or by recommending this tutorial to other people.

Flattr this

5. Questions and Discussion

Before posting questions, please see the vogella FAQ . If you have questions or find an error in this article please use the www.vogella.de Google Group . I have created a short list how to create good questions which might also help you. .

6. Appendix: Using JPA with XML metadata

6.1. XML Metadata

Alternative to the annotations you can also use XML metadata to define the persistence metadata.

You can create a file orm.xml within the META-INF directory to describes this data.

6.2. Example

The following file describes the persistence data in an external file orm.xml. No annotations are required in Person.java. We use for illustration a simplified example of person.

				
package datamodel;

import javax.persistence.*;

@Entity 
@Table(name="MYAPPLICATION.PEOPLETABLE")

public class Person implements IPerson {
	private String id;
	private String firstName;
	private String lastName;
	private String nonsenseField=""; 

	@Id
	public String getId() {
		return id;
	}
	
	public void setId(String Id) {
		this.id = Id;
	}
	
	// Name the column to "MYFIRST"
	@Column(name="MYFIRST")
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	// Leave the standard column name of the table
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	
	@Transient
	public String getNonsenseField() {
		return nonsenseField;
	}

	public void setNonsenseField(String nonsenseField) {
		this.nonsenseField = nonsenseField;
	}
}

			

This is required orm.xml for this mapping.

				
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd" version="1.0">
    <package>
        datamodel
    </package>
    <access>
        PROPERTY
    </access>
    <entity class="Person">
        <table schema="MYAPPLICATION" name="PEOPLETABLE"/>
        <attributes>
            <id name="id">
                <column name="ID"/>
            </id>
            <basic name="lastName">
                <column name="LASTNAME"/>
            </basic>
            <basic name="firstName">
                <column name="MYFIRST"/>
            </basic>
            <transient name="nonsenseField" />
        </attributes>
    </entity>
</entity-mappings>
			

7. Links and Literature

7.1. Java Persistence API Resources

http://www.eclipse.org/eclipselink/ EclipseLink

http://java.sun.com/developer/technicalArticles/J2SE/Desktop/persistenceapi/ Using the Java Persistence API in Desktop Applications

http://www.ibm.com/developerworks/java/library/j-typesafejpa/index.html Dynamic, typesafe queries in JPA 2.0 using the Criteria API