JavaBeat

  • Home
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Privacy
  • Contact Us

PrimeFaces + EclipseLink / JPA + MongoDB Integration

April 22, 2014 by Amr Mohammed Leave a Comment

This tutorial explains the PrimeFaces + JPA + MongoDD integration. We are going to create a Pie Chart application using the PrimeFaces component library with the additional software JPA and MongoDB for the persistence mechanism. Before writing any snippet of code, you should have a proper installation and configuration for both the database (MongoDB) and the EclipseLink JPA/NOSQL persistence layer.

  • Also Read : PrimeFaces Tutorials

Tutorial Tools

  • Mongo Database 2.6
  • Eclipselink JPA/NOSQL 2.5.0
  • PrimeFaces 4.0
  • Apache Tomcat Server 7.0.35
  • Windows 7

MongoDB Installation & Configuration

In our previous article, we have explained How To Install MongoDB on Windows. If you have not installed MongoDB, please follow that article and setup the MongoDB in your system

See the below figures that shows you a proper running MongoDB and an open connection using the command line.

Running Mongo

  • The above figure shows you the result in of executing mongod.exe command.

Connect Mongo

  • The above screen shows you the result of executing monog.exe command.

Maven has provided the library for connecting the MONGODB by adding the following dependency. Add the maven for Mongo Java Driver dependency.

Maven For Mongo Database Java Driver

[code lang=”xml”]
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.11.4</version>
</dependency>
[/code]

EclipseLink JPA/NOSQL Installation & Configuration

We have discussed before EclipseLink library that responsible for connecting upon Relational Database at the EclipseLink – JPA Tutorial. But for connecting a non-relational databases such MongoDB – Document Based – you have to consider the EclipseLink JPA/NOSQL library.

The installation and configuration of that library needs Maven configurations, so It is worth for you to have a look at the EclipseLink – JPA Tutorial that mentioned above for seeing the way that how could maven being used for that purpose. The following coming few lines assumes that you are aware about installing and configuring the EclipseLink using maven.

For installing and configuring the EclipseLink – JPA/NOSQL you have to follow the below steps:

  • Add the required entries for EclipseLink – JPA/NOSQL maven repositories and dependencies.
  • Create your business domain (Classes).
  • Type the persistence.xml with the required domain classes and properties for the database being connected.

Maven EclipseLink – JPA/NoSQL Repositories

[code lang=”xml”]
<repositories>
<repository>
<id>oss.sonatype.org</id>
<name>OSS Sonatype Staging</name>
<url>https://oss.sonatype.org/content/groups/staging</url>
</repository>
<repository>
<id>EclipseLink</id>
<url>http://download.eclipse.org/rt/eclipselink/maven.repo</url>
</repository>
</repositories>
[/code]

Maven Eclipselink – JPA/NoSQL Dependencies

[code lang=”xml”]
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.0-RC1</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.persistence</groupId>
<artifactId>commonj.sdo</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.nosql</artifactId>
<version>2.4.2-SNAPSHOT</version>
</dependency>
[/code]

Business Domain

For being this tutorial have a high intensity of concepts and snippet of codes, we’ve introduced a simple business domain for good understanding. The suggested domain contains of two classes, User and Address represent the domain where the User class has an association for Address.
User.java

[code lang=”java”]
package net.javabeat.eclipselink.persistence.data;

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

import org.eclipse.persistence.nosql.annotations.DataFormatType;
import org.eclipse.persistence.nosql.annotations.Field;
import org.eclipse.persistence.nosql.annotations.NoSql;

@Entity
@NoSql(dataFormat=DataFormatType.MAPPED)
public class User {
@Id
@GeneratedValue
@Field(name="_id")
private String id;
@Field(name="USERID")
private String userId;
@Field(name="fullName")
private String fullName;
@Field(name="AGE")
private String age;
@Field(name="STATUS")
private String status;
@Embedded
private Address address = new Address();

public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}

public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
[/code]

Address.java

[code lang=”java”]
package net.javabeat.eclipselink.persistence.data;

import javax.persistence.Embeddable;

import org.eclipse.persistence.nosql.annotations.DataFormatType;
import org.eclipse.persistence.nosql.annotations.Field;
import org.eclipse.persistence.nosql.annotations.NoSql;

@Embeddable
@NoSql(dataFormat=DataFormatType.MAPPED)
public class Address {
@Field(name="addressId")
private String addressId = "";
@Field(name="addressValue")
private String addressValue = "";

public String getAddressId() {
return addressId;
}
public void setAddressId(String addressId) {
this.addressId = addressId;
}
public String getAddressValue() {
return addressValue;
}
public void setAddressValue(String addressValue) {
this.addressValue = addressValue;
}
}
[/code]

  • Note that we are using @NoSql annotation
  • Instead of @Column for binding a field with a column in a relational database, the @Field has been used
  • @Embedded is a persist strategy that used for embed document within the body of other document

PrimeFaces Pie Chart Component

Representation of data is one of the most challenges with JSF implementation vendor. Charts is one of the primary components that have been coming with the PrimeFaces distribution, one of them is the Pie chart. Pie chart displays category-data in a pie graphic.

Here is the PieChart tag information and attributes defined with the PieChart.

PieChart General Info

Pie Attributes

The View

index.xhtml

[code lang=”xml”]
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<script name="jquery/jquery.js" library="primefaces"></script>
</h:head>
<f:view>
<h:form prependId="false">
<h1>JavaBeat Primefaces Example</h1>
<h2>Primefaces – DataTable – User Registration </h2>
<h:panelGrid columns="2">
<h:outputText value="Enter Full Name:"/>
<p:inputText value="#{registerationBean.user.fullName}"/>
<h:outputText value="Enter Age:"/>
<p:inputText value="#{registerationBean.user.age}"/>
<h:outputText value="Enter Status [Example A, B, C or D]:"/>
<p:inputText value="#{registerationBean.user.status}"/>
<h:outputText value="Enter Address"/>
<p:inputText value="#{registerationBean.user.address.addressValue}"/>
</h:panelGrid>
<h:panelGrid columns="1">
<p:pieChart value="#{registerationBean.model}" legendPosition="w"></p:pieChart>
</h:panelGrid>
<h:commandButton value="Save User" action="#{registerationBean.saveUser}"/>
<br/>

</h:form>
</f:view>
</html>
[/code]

Managed Bean

RegistrationBean.java

[code lang=”java”]
package net.javabeat.primefaces.presenation;

import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import net.javabeat.eclipselink.persistence.data.User;

import org.primefaces.component.chart.pie.PieChart;
import org.primefaces.model.chart.PieChartModel;

@ManagedBean
@SessionScoped
public class RegisterationBean {
static EntityManagerFactory factory = null;
static EntityManager em = null;

static {
factory = Persistence.createEntityManagerFactory("mongoPU");
em = factory.createEntityManager();
}

private User user = new User();
private PieChartModel model = new PieChartModel();

int aCounter = 0;
int bCounter = 0;
int cCounter = 0;
int dCounter = 0;

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

@SuppressWarnings("unchecked")
public PieChartModel getModel() {

// At each rendering of data, a query has made upon mongo data.
Query query = em.createQuery("SELECT u FROM User u");
// Fetch the all users
List<User> users = query.getResultList();
// Categorize Users
for(User u : users){
if(u.getStatus().equals("A")){
aCounter++;
}
if(u.getStatus().equals("B")){
bCounter++;
}
if(u.getStatus().equals("C")){
cCounter++;
}
if(u.getStatus().equals("D")){
dCounter++;
}
}
this.model = new PieChartModel();
// Fill the model
model.set("A", aCounter);
model.set("B", bCounter);
model.set("C", cCounter);
model.set("D", dCounter);
return model;
}

public void setModel(PieChartModel model) {
this.model = model;
}

public String saveUser(){
em.getTransaction().begin();
em.persist(user);
em.getTransaction().commit();
this.user = new User();
return "";
}
}
[/code]

Persistence Context

persistence.xml

[code lang=”xml”]
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="mongoPU" transaction-type="RESOURCE_LOCAL">
<class>net.javabeat.eclipselink.persistence.data.User</class>
<class>net.javabeat.eclipselink.persistence.data.Address</class>
<properties>
<property name="eclipselink.target-database" value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
<property name="eclipselink.nosql.connection-spec" value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
<property name="eclipselink.nosql.property.mongo.port" value="27017"/>
<property name="eclipselink.nosql.property.mongo.host" value="localhost"/>
<property name="eclipselink.nosql.property.mongo.db" value="JavaBeat"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
</persistence>
[/code]

Primefaces + EclipseLink JPA / NOSQL + MongoDB Integration

The below snapshots show you the using of MongoDB for storing the users and retrieving them again for drawing the Pie Chart. Pie Chart is categorized based on the status that has the value among of set A, B, C and D.

At the same time, a find query db.USER.find() has been executed to ensure that the Pie Chart has executed a correct query into USER collections.

Pie Chart Used In Registration Form

  • Save user has invoked the saveUser method, that’s in turn the saving is being proceed.
  • GetModel will reset the Pie model for next coming filling.

Mongo Records

  • When the database is connected via mongo.exe, the user has the ability to inquiry the database.
  • The db implicit object represnts the connected database, which has the value of JavaBeat.
  • By using the command db.USER.find(), the user has the ability to see all of the registered users.

[wpdm_file id=77]

Filed Under: JSF Tagged With: EclipseLink, JPA, JSF 2.0, MongoDB, NOSQL, PrimeFaces

JPA – Java Persistence Query Language (JPQL) – PART II

March 21, 2014 by Amr Mohammed Leave a Comment

This tutorial is a complement for Java Persistence Query Language (JPQL) Part I, in which a new techniques of querying should be discovered and learned. Instead of depending on the entities that being retreived upon query for accessing their inner state/association fields, we’ve also would be querying those fields through an advanced techniques of query. This tutorial is intended to cover such these ways of inquiring. Whenever you’ve felt that you have to see the full examples that made before for covering the different associations of JPA you could refer to EclipseLink Tutorial.

Executing the Queries

To avoid code redundancy, we’ve listed a complete execution example that could be used for executing the provided queries that are listed. So, make sure that you are copying the provided query per each subsequent section and paste it in place of queryStr and execute the application to see the result of the suggested query.

[code lang=”java”]
package net.javabeat.eclipselink;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.Phone;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Define a string based query
String queryStr = "Put Examined Query Here";
// Create a Query Using of Entity Manager
Query query = em.createQuery(queryStr);
// Try to fetch single result
try {
Object object = query.getSingleResult();
if(object instanceof Employee){
System.out.println("EmployeeID :: "+((Employee)object).getEmployeeId());
}
else if(object instanceof Phone){
System.out.println("PhoneID :: "+((Phone)object).getPhoneId() + " Owned By the Employee :: " + ((Phone)object).getEmployee().getEmployeeId());
}
else if(object instanceof DriverLicense){
System.out.println("DriverLicenseID :: "+((DriverLicense)object).getLicenseId() + " Owned By the Employee " + ((DriverLicense)object).getEmployee().getEmployeeId());
}
else {
System.out.println("Value Queried Is :: "+object + " :: ");
}
}
catch(Exception e){
// Try to fetch the result list
List<Object> objects = query.getResultList();
// Loop over results
for(Object object : objects){
if(object instanceof Employee){
System.out.println("EmployeeID :: "+((Employee)object).getEmployeeId());
}
else if(object instanceof Phone){
System.out.println("PhoneID :: "+((Phone)object).getPhoneId() + " Owned By the Employee :: " + ((Phone)object).getEmployee().getEmployeeId());
}
else if(object instanceof DriverLicense){
System.out.println("DriverLicenseID :: "+((DriverLicense)object).getLicenseId() + " Owned By the Employee " + ((DriverLicense)object).getEmployee().getEmployeeId());
}
else if(object instanceof Object []){
// loop over the array of objects
Object [] arrayObjects = (Object [])object;

for(Object arrayObject : arrayObjects){
if(arrayObject instanceof Employee){
System.out.print("EmployeeID :: "+((Employee)arrayObject).getEmployeeId());
}
else if(arrayObject instanceof Phone){
System.out.print("PhoneID :: "+((Phone)arrayObject).getPhoneId() + " Owned By the Employee :: " + ((Phone)arrayObject).getEmployee().getEmployeeId() + " :: ");
}
else if(arrayObject instanceof DriverLicense){
System.out.print("DriverLicenseID :: "+((DriverLicense)arrayObject).getLicenseId() + " Owned By the Employee " + ((DriverLicense)arrayObject).getEmployee().getEmployeeId() + " ::");
}
else {
System.out.print("Value Queried Is :: "+arrayObject + " :: ");
}
}
System.out.println("");
}
else {
System.out.println("Value Queried Is :: "+object + " :: ");
}
}

}
}

}
[/code]

  • Some minor changes are happened per each executed query for making the messages more desirable in explanation the concept the query is about to clarify.

Using of Identification Variables

The identification variable is a key stone that the next coming topics need it for being clarified, look at the following fragment of code that shows the application of (identification variable) inside the query of JPQL:

[code lang=”java”]
SELECT employee FROM Employee employee
[/code]

  • The employee is an identification variable.
  • The identification variable is a valid identifier declared in the FROM clause.
  • An identification variable must not be reserved identifier or have the same name as any entity in the same persistent unit.
  • Identification variables are case sensitive, so the use of employee is differ from using Employee in case the Employee entity doesn’t defined in the same persistent unit.
  • An identification variable evaluates to a value of the type of the expression use in declaring the variable.
  • The employee evaluates into Employee instance.
  • The identification variable does support the composing of Path Expression.

Accessing State/Association Fields By Path Expression

An identification variable followed by the navigation operator (.) and a state field or association field compose a Path Expression.

[code lang=”java”]
SELECT employee.employeeId, phones.phoneNumber FROM Employee employee, employee.phones phones
[/code]

  • The employee and phones are two different identification variables.
  • The employee.employeeId, phones.phoneNumber compose a Path Expression.
  • The type of the path expression is the type computed as a result of navigation, so the type of the state field or association field to which the expression navigates.
  • The employee.employeeId computed to an integer value, cause the employeeId is of type int.
  • The phones.phoneNumber computed to a String value, cause the phoneNumber is of type String.
  • Depending on the navigability, a path expression that leads to an association field or field whose type is an embeddable class may be further composed.
  • Path Expression can be composed from other path expressions if the original path expression evaluates to a single-valued type (not a collection).
  • An implicit inner joins has been specified at the FROM clause (See Joins Section).

Let’s try navigate the employee identification variable for accessing the phones by using the statement employee.phones.

[code lang=”java”]

SELECT employee.employeeId,employee.phones, phones.phoneNumber FROM Employee employee, employee.phones phones

[/code]

If you’ve executed the previous snippet of code you are surely getting an exception.

Navigating Into Embeddable Class

Let’s try the following the that composed a navigation into Embeddable address field.

[code lang=”java”]
SELECT employee.employeeId,address.addressId.addressId,address.addressId.addressCityId FROM Employee employee, employee.address address
[/code]

  • The Path Expression that navigates the address field of Employee does again composed to access those fields inside the Embeddable AddressPK. (See EclipseLink Examples).

Inner Joins

An inner join may be implicitly specified by the use of a cartesian product on the FROM (As you’ve seen before) clause and a join condition in the where clause. In the absence of a join condition, this reduces to the cartesian product. Let’s see the difference between an implicit of inner join and explicit join. But before seeing the result of the samples, we’ve assumed that we have two employees and 3 phones. Employee with an id (1) references two phones and Employee with an id (2) references 1 phone.

Using Implicit JOIN

[code lang=”java”]
SELECT employee.employeeId,phone.phoneId FROM Employee employee, employee.phones phone
[/code]

Using Explicit JOIN

[code lang=”java”]
SELECT employee.employeeId,phone.phoneId FROM Employee employee JOIN employee.phones phone
[/code]

The result of two samples of query should be identical:

[code lang=”java”]
EmployeeID :: 1 :: PhoneID :: 1 ::
EmployeeID :: 1 :: PhoneID :: 2 ::
EmployeeID :: 2 :: PhoneID :: 3 ::
[/code]

  • The Java Persistence Query Language (JPQL) does provide an inner join in case the absence of JOIN keyword and if the JOINED entities does provide a foreign key that is mapped to an entity relationship.
  • The Implicit Inner Join called (Theta-Join).
  • If you’ve removed the JOIN keyword, you will get the same result, cause there is a foreign key between Employee and Phone entities, so an inner JOIN should be specified by the FROM clause and without need for WHERE clause.

Let’s look at the following example that does make a query between Employee and DriverLicense, in that the Employee entity doesn’t provide a direct association of DriverLicense.

[code lang=”java”]
SELECT employee,license FROM Employee employee, DriverLicense license
[/code]

The Result of the previous code is:

[code lang=”java”]
Employee ID :: 1 :: DriverLicense ID :: 26 :: License Owned By Employee :: 1
Employee ID :: 2 :: DriverLicense ID :: 26 :: License Owned By Employee :: 1
[/code]

  • Even the DriverLicense of id 26 doesn’t relate anymore to the Employee of ID 2, however the result shows a Cross Join that already made by the JPQL FROM clause.
  • The solution for such kind problem is by using the WHERE condition.
  • The using of Join condition that specified at the WHERE clause, when a join doesn’t involve a foreign key relationship that is mapped to an entity relationship.

Let’s look at the next coming fragment of code that does provide a WHERE condition.

[code lang=”java”]
SELECT employee,license FROM Employee employee, DriverLicense license
WHERE employee.employeeId = license.employee.employeeId
[/code]

The Result of the previoud code is:

[code lang=”java”]
Employee ID :: 1 :: DriverLicense ID :: 26 :: License Owned By Employee :: 1
[/code]

Left Outer Joins

The LEFT JOIN & LEFT OUTER JOIN are synonymous. They enable the retrieval of a set of entities where matching values in the join condition may be absent.

At the next following example, let we have a two different employees, one of them is associated with two phone objects. let’s querying the database using two different queries.

[code lang=”java”]
SELECT DISTINCT employee.employeeId FROM Employee employee, employee.phones phone
[/code]

The result of the query is

[code lang=”java”]
EmployeeID :: 1 ::
[/code]

  • By using the inner join as we have done in the previous query will not give us that employee that’s not associated with any instance of Phone.
  • The solution of such that problem is by querying the database by using the LEFT JOIN.

[code lang=”java”]
SELECT DISTINCT employee.employeeId FROM Employee employee LEFT JOIN employee.phones phone
[/code]

The result of the query is

[code lang=”java”]
EmployeeID :: 1 ::
EmployeeID :: 2 ::
[/code]

  • The result of the LEFT JOIN is the employees that have a phones and those employees that haven’t a phones.

Queries Using Input Parameters

The following query finds the employee whose ID is designated by an input parameters.

[code lang=”java”]
// Create a parameterized query string
String queryStr = "SELECT employee.employeeId FROM Employee employee WHERE employee.employeeId = ?1";
// Create a Query Using of Entity Manager
Query query = em.createQuery(queryStr);
// Set the parameter by specify the index of the parameter and the value
query.setParameter(1, 1);
[/code]

  • To specify a parameter in the query string you have to type a question suffixed by the index of the parameter.
  • The query above specify one parameter at the index 1.
  • When using a parametrized query, you have to specify the parameter index and parameter value by invoking the setParameter upon Query object.

ORDER BY Clause

We’ve the opportunity to order the result of the query by using ORDER BY reserved keyword. Order By reserved keyword is working in conjunction with ASC and DESC.

[code lang=”java”]
SELECT employee.employeeId,employee.employeeName FROM Employee employee ORDER BY employee.employeeName DESC
[/code]

The result of the query above

[code lang=”java”]
Employee ID Is :: 2 :: Employee Name :: Suza Smith ::
Employee ID Is :: 1 :: Employee Name :: Gilbert Samouel ::
[/code]

  • The ORDER BY clause allows objects or values that are returned by the query to be ordered.
  • The keyword ASC specifies that ascending ordering, while the DESC specifies that descending ordering.
  • Ascending order is the default ordering.

Summary

Java Persistence Query Language (JPQL), provides a lot of techniques for doing a query. Identification Variables, Path Expressions, Inner Joins, Left Joins and other concept are introduced at this tutorial.

Filed Under: Java EE Tagged With: EclipseLink, JPA

JPA – Java Persistence Query Language (JPQL) – PART I

March 18, 2014 by Amr Mohammed Leave a Comment

Java Persistence Query Language (JPQL) is a string-based query language used to define queries over entities and their persistent states. It enables the application developer to specify the semantics of queries in a portable way and independent of the particular database schema that in use.

Java Persistence Query Language (JPQL) is not only portable but also it does optimize the query methods by allowing the developers to compile their  query language direct into target language, in that the execution of queries will be shifted to the native language facilities provided by the database (or any other persistent store)  instead of requiring queries to be executed on the Runtime Representation of the entity state. This tutorial provides an explanation of how Java Persistence Query Language used according to Java Persistence API 2.1.

EclipseLink does support a Java Persistence Query Language (JPQL) as a one of the Java Persistence API (JPA) vendor, it provides many extensions to the standard JPA Persistence Query Language (JPQL), these extensions referred to as the Eclipselink Query Language.

At this tutorial, you should find a full coverage for what Java Persistence API has provided in the Java Persistence Query Language field as well the main extensions that been added by the Eclipselink under what called after that EclipseLink Query Langauge.

Required Terminologies

This tutorial and next upcoming ones could use one or more of the complex terms that should be understood for making the JPQL concept more easier.

  • Abstract Persistence Schema: This term refers to the persistent schema abstraction ( persistent entities, their states and their relationships) over which Java Persistence Queries operate. Queries over this persistent schema abstraction are translated into queries that are executed over the database schema to which entities are mapped.
  • A Persistence Unit: This terms defines the set of all classes that are related or grouped by the application and which must be calculated in their mapping to a single database.

Statement Types

A Java Persistence query language statement may be either a select statement, an update statement or a delete statement. Any Java Persistence query language statement may be constructed dynamically or may be statically defined in a metadata annotation or XML descriptor element.

Anatomy of Select Statement

A select statement is a string which consists of the following clauses:

  • a SELECT clause, which determines the type of the objects or values to be selected.
  • a FROM clause, which provides declarations that designate the domain to which the expressions specified in the other clauses of the query apply.
  • an optional WHERE clause, which may be used to restrict the results that are returned by the query.
  • an optional GROUP BY clause, which allows query results to be aggregated in terms of groups.
  • an optional HAVING clause, which allows filtering over aggregated groups.
  • an optional ORDER BY clause, which may be used to order the results that are returned by the query.
  • a select statement must always have SELECT and a FROM clause.

Classes Domain Anatomy

The classes anatomy section should provide a full picture for about those classes that forming the persistent domain over which the select statement operate. This tutorial will mostly depend on a previous persistent domain that already done in the EclipseLink – JPA examples. See Figure 1.0 shows you the classes domain.

Classes Design (Associations)

Figure 1.0

We’ve been clarifying the following points using the previous figure.

  • The Employee entity is in the middle of the entities.
  • The Employee has OneToOne (Bidirectional) association with an Address entity.
  • The Employee has OneToMany (Bidirectional) association with a Phone entity.
  • The Employee has ManyToMany (Bidirectional) association with a Project entity.
  • The License has ManyToOne (Unidirectional) association with an Employee entity (The Employee has no reference for License entity).

Querying using Select

The example that you would see is constantly use a static query instead of using dynamic one (See Dynamic vs Static) .

JPAImpl.java

[code lang=”java”]
package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.License;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Define a string based query
String selectQueryStr = "SELECT emp FROM Employee emp";

// SELECT STATEMENT

// Create a dynamic query
Query query = em.createQuery(selectQueryStr);
// Uses a query object retrieved from the entity manager for acquiring the results
List<Object> objects = query.getResultList();
// Looping Over fetched objects
for(Object obj : objects){
Employee emp = null;
if(obj instanceof Employee)
emp = (Employee) obj;
else if(obj instanceof Object []){
Object [] os = (Object [])obj;
for(Object o : os){
System.out.println(o);
}
}

if(emp != null){
System.out.println("Employee Id : "+ emp.getEmployeeId());
System.out.println("Employee Name : "+ emp.getEmployeeName());
System.out.println("Employee Period # : Start Date :: "+
emp.getEmployeePeriod().getStartDate() + " :: End Date " +
emp.getEmployeePeriod().getEndDate());
System.out.println("Employee’s Address : "+ emp.getAddress().getAddressId());
System.out.println("Employee’s Phones # : "+ emp.getPhones().size());
System.out.println("Employee’s Projects # : "+ emp.getProjects().size());
}
}
}
}

[/code]

  • Type of retrieved objects could be determined by using of SELECT statement.
  • By referencing an Employee entity, the application is capable of accessing all those entities that Employee refers to.
  • Although an Employee entity has a reference for DriverLicense, but it couldn’t be reached from an Employee.

The Result of JPAImpl.java

[code lang=”java”]
Employee Id : 1
Employee Name : John Smith
Employee Period # : Start Date :: Wed Mar 12 00:00:00 GMT+02:00 2014 :: End Date Wed Mar 12 00:00:00 GMT+02:00 2014
Employee’s Address : net.javabeat.eclipselink.data.AddressPK@109b2a51
Employee’s Phones # : 1
Employee’s Projects # : 2
[/code]

But what’s could happen if we’ve changed the select statement by making it doing a query for attributes (persistent fields) instead of types (Entities).

JPAImpl.java

[code lang=”java”]
package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.License;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Define a string based query
String selectQueryStr = "SELECT emp.employeeId,emp.employeeName FROM Employee emp";

// SELECT STATEMENT

// Create a dynamic query
Query query = em.createQuery(selectQueryStr);
// Uses a query object retrieved from the entity manager for acquiring the results
List<Object> objects = query.getResultList();
// Looping Over fetched objects
for(Object obj : objects){
Employee emp = null;
if(obj instanceof Employee)
emp = (Employee) obj;
else if(obj instanceof Object []){
Object [] os = (Object [])obj;
for(Object o : os){
System.out.println(o);
}
}

if(emp != null){
System.out.println("Employee Id : "+ emp.getEmployeeId());
System.out.println("Employee Name : "+ emp.getEmployeeName());
System.out.println("Employee Period # : Start Date :: "+
emp.getEmployeePeriod().getStartDate() + " :: End Date " +
emp.getEmployeePeriod().getEndDate());
System.out.println("Employee’s Address : "+ emp.getAddress().getAddressId());
System.out.println("Employee’s Phones # : "+ emp.getPhones().size());
System.out.println("Employee’s Projects # : "+ emp.getProjects().size());
}
}

}

}
[/code]

  • A SELECT can be used for defining retrieving attributes/types or both.

The Result of JPAImp.java

[code lang=”java”]
1
John Smith
[/code]

Updating and Deleting

The use of queries do not consider the SELECT statement only, but they also could be used for handling a wide range of modification and deletion statements.

Anatomy of Update Statement

  • The anatomy of update statement is identical to that defined in the SQL-database.
  • An UPDATE clause, which defines the entities over which the update statement affect.
  • A SET clause, which provides comma separated pairs (property, value) for those properties being changed.
  • A WHERE clause, which provides the conditions that based on the entities have updated.

JPAImpl.java

[code lang=”java”]
package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.License;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){

String updateQueryStr = "UPDATE Employee emp SET emp.employeeName = ‘Gilbert Samouel’ WHERE emp.employeeId = ‘1’";

// UPDATE STATEMENT
em.getTransaction().begin();
Query query = em.createQuery(updateQueryStr);
int rowsAffected = query.executeUpdate();
System.out.print("Number of rows affected Are : "+rowsAffected);
em.getTransaction().commit();

}

}
[/code]

The Result of Execution

[code lang=”java”]
1
John Smith
Number of rows affected Are : 1
[/code]

The Modification Inside the Database

Update Query

  • The update statement means a modification and that should be applied within a Transaction.

Anatomy of Delete Statement

  • The anatomy of delete statement is identical to that defined in the SQL-database.
  • A DELETE clause.
  • A FROM clause, which used for defining the entities that being removed.
  • A WHERE clause, which provides the conditions that based on the entities have removed.

JPAImpl.java

[code lang=”java”]
package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.License;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
String deleteQueryStr1 = "DELETE FROM DriverLicense lic WHERE lic.employee.employeeId = ‘1’";

// DELETE STATEMENT
em.getTransaction().begin();
// Remove the DriverLicense
Query query = em.createQuery(deleteQueryStr1);
int rowsAffected = query.executeUpdate();
System.out.print("Number of rows affected Are : "+rowsAffected);
em.getTransaction().commit();

}

}
[/code]

The Result of Execution

[code lang=”java”]
Number of rows affected Are : 1
[/code]

  • Don’t try removing the DriverLicense entity by mentioning the License entity, that’s because of License is mapped superclass and it is used for sharing mapping information and persistent states (See Mapped superclass).
  • Removing an entity does consider a Transaction.

Summary

One of the exciting parts inside the Java Persistence API is a Java Persistence Query Language that provides a (String Based Query) for querying the target persistent domain such as database. This tutorial provides you a basic elementary of how could be using of Java Persistence Query Language for the most common of SELECT, UPDATE & DELETE.

The next coming tutorials should cover more attractive parts that related to the JPQL and hence we’re talking about Eclipselink, it also, should provide an excellent tutorials and practices of what Eclipselink has added.

Filed Under: Java EE Tagged With: EclipseLink, JPA, JPQL

JPA – Lazy Loading and Eager Loading

March 13, 2014 by Amr Mohammed Leave a Comment

Eclipselink 2.1 is a persistence provider runtime of the Java Persistence API 2.1 specification. JPA  specification defines two major strategies of loading data (Lazy and Eager). The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first time accessed.

The Lazy loading is commonly used to defer the loading of the attributes or associations of an entity or entities until the point at which they are needed, meanwhile the eager loading is an opposite concept in which the attributes and associations of an entity or entities are fetched explicitly and without any need for pointing them.

Determine The Loading Strategy

EclipseLink 2.1 provides you different ways to mention your desired loading strategy.

  • Basic Annotation: It provides a fetchType attribute that can be used for determining the strategy to which the attribute(s) that should be loaded eagerly or lazily.
  • @OneToOne, @ManyToOne, @OneToMany and @ManyToMany: Every associations annotations provide fetchType attribute that can be used for determining the strategy to which the attributes(s) that should be loaded eagerly or lazily.

Lazy Fetch Type With @OneToOne and @ManyToOne

If you’ve noted before @OneToOne association example, you’ve absolutely seen the association between Employee and Address entities adhered a bidirectional OneToOne. It’s the time to give more attention about Eager and Lazy loading in that association. Let’s see what’s the role that can fetchType attribute play in this association when it used at the Employee side and at the Address side. (see EclipseLink Tutorials)

The default value of fetchType attribute within OneToOne annotation is an eager value, and whether the value of the field or property should be lazily loaded or must be eagerly fetched. The EAGER strategy is a requirement on the persistence provider runtime that the value must be eagerly fetched and the LAZILY is just a hint to the persistence provider runtime.

By default EclipseLink consider the OneToOne and ManyToOne associations as not lazily associations. So if we’ve set OneTOne or ManyToOne associations to lazy without using of EclipseLink weaving, we surely have an eager association. Let’s see Figure 1.0 that shows you an Employee entity associated with an Address entity in a OneToOne association.

Employee.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="EmployeeType")
@DiscriminatorValue(value="EMP")
@EntityListeners(value={PersistenceContextListener.class})
public class Employee {

@Id
private int employeeId;

@Basic(optional=false)
private String employeeName;

@Embedded
private EmployeePeriod employeePeriod;

@OneToMany(mappedBy="employee", cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private List phones;

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(
name="employee_project",
joinColumns={@JoinColumn(name="employeeId")},
inverseJoinColumns={
@JoinColumn(table="project",name="projectId"),
@JoinColumn(table="localproject",name="projectId"),
@JoinColumn(table="globalproject",name="projectId")}
)
private List projects;

@OneToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY,targetEntity=Address.class)
@JoinColumns({
@JoinColumn(name="AddressId",referencedColumnName="AddressId"),
@JoinColumn(name="EmployeeAddressCountryId",referencedColumnName="AddressCountryId"),
@JoinColumn(name="EmployeeAddressCityId",referencedColumnName="AddressCityId")}
)
private Address address; // Note: OneToOne annotation is configured as lazy loading

public Address getAddress() {
return address;
}

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

public int getEmployeeId() {
return employeeId;
}

public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getEmployeeName() {
return employeeName;
}

public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}

public List getPhones() {
return phones;
}

public void setPhones(List phones) {
this.phones = phones;
}

public List getProjects() {
return projects;
}

public void setProjects(List projects) {
this.projects = projects;
}

public EmployeePeriod getEmployeePeriod() {
return employeePeriod;
}

public void setEmployeePeriod(EmployeePeriod employeePeriod) {
this.employeePeriod = employeePeriod;
}

}

[/code]

Address.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.OneToOne;
import javax.persistence.PrePersist;

@Entity(name="address")
@EntityListeners(value={PersistenceContextListener.class})
public class Address {
@EmbeddedId
private AddressPK addressId;
private String addressCountry;
private String addressCity;

@OneToOne(cascade=CascadeType.ALL,mappedBy="address",fetch=FetchType.LAZY)
private Employee employee; // Note: The OneToOne association is configured as lazy loading

public Employee getEmployee() {
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
}

public String getAddressCountry() {
return addressCountry;
}
public void setAddressCountry(String addressCountry) {
this.addressCountry = addressCountry;
}
public String getAddressCity() {
return addressCity;
}
public void setAddressCity(String addressCity) {
this.addressCity = addressCity;
}

public AddressPK getAddressId() {
return addressId;
}

public void setAddressId(AddressPK addressId) {
this.addressId = addressId;
}

@PrePersist
public void prePersist(){
System.out.println("Address Entity :: Method PrePersist Invoked Upon Entity "+this);
}

}

[/code]

Let’s we execute the following snippet of code:

[code lang=”java”]

Employee emp = em.find(Employee.class, 1);

[/code]

  • The executed sample code assumed that an employee row instance has been persisted previously. (See OneToOne Association).
  • The Eclipselink implementation will discard the hint that you’ve set that the fetch type is lazy.
  • The Address OneToOne mapping will be fetched as an Eager loading. See Figure 1.0 that shows you the instance of Employee and its dependent objects.

Employee Instance Discard Lazy Loading

Figure 1.0

As you’ve noted in the Figure 1.0

  • The Address entity has fetched by the EclipseLink JPA, although the fetch type of Address is lazy.
  • By default, EclipseLink discard the fetch Type lazy in case we’ve used the @OneToOne and @ManyToOne.

Enforce EclipseLink To Consider Lazy Associations

To enforce EclipseLink considering the Lazy fetch type that passed in the previous Employee sample, we have to use what Eclipse named “Weaved Indirection”.

If we set OneToOne or ManyToOne associations are lazy, we enable weaving, the EclipseLink JPA persistence provider will use weaving to enable value holder indirection for these associations. Before any further next lines let’s see how could we enable weaving using Eclipse IDE and by using the same provided examples.

  • Determine the eclipselink.jar that contains the weaving required API (See EclipseLink Installation And Configuration Using Eclipse)
  • Open EclipseIDE.
  • Open EclipseLink – JPA-Installation package
  • Determine you executable class (At this example it will be JPAImpl.java).
  • Set a break point at that line code that fetched Employee instance from a database.
  • Click on the Run menu from the top main menu.
  • Select Debug Configuration.
  • From the window opened and from the left side select the Java Application that you would use for weaving.
  • From the same window, but at the right side select the titled tab (Arguments).
  • Inside the VM arguments box type (-javaagent:eclipselink.jar).
  • From the Working Directory beneath the VM arguments box select Other.
  • Specify the eclipselink.jar file by navigating into the installed EclipseLink Installation file. See Figure 1.1 that shows you the final image of what you should have on your local environment.

Final Weaving Configuration Image

Figure 1.1

  • Close the dialog by clicking on the Debug.
  • You should see the JPAImpl.java is executing and the debug stopped in at the break point that already defined.
  • Click F6 for proceed one step forward.
  • Let your mouse curser move over the emp instance.
  • The EclipseIDE must display the emp instance and all of its dependent objects, but that’s time with respective for those mapping that defined as LAZY LOADING. See Figure 1.2.

Lazy Load

Figure 1.2

  • Eclipselink uses the indirection; the indirection is likely that a graph of persistent objects that contain (UN triggered) indirection objects.
  • EclipseLink uses weaving to implement lazy fetching for OneToOne and ManyToOne associations.
  • If you’ve selected the value holder that represents the address instance that named  (_persistence_address_vh=UnitOfWorkQueryValueHolder) than you should see the following message shown below {UnitOfWorkQueryValueHolder: not instantiated}
  • Try to investigate the address value holder for seeing the other attributes such as isLazy (true), isInstantiated(false) and others.
  • Also, the address attribute that belongs to employee instance is referring to null. See Figure 1.3.

Address Is Null

Figure 1.3

  • Address instance that belongs to Employee is Null, cause the fetch type that has been selected is Lazy load for achieving such that association.The only way that permitted for accessing the address is by calling it directly. See Figure 1.4.

Access Lazy Load Association

Figure 1.4

  • As you’ve noted the address instance that belongs to Employee does respond now.

By Default EclipseLink Support Lazy Load for @OneToMany and @ManyToMany

Let’s look at the Employee entity and its dependent either objects (Projects and Phones), where the Employee does associate with the Projects as ManyToMany and it does associate with Phones as OneToMany. Let’s see how could be achieving lazy load easily as opposite of using it with OneToOne and ManyToOne.

Employee.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="EmployeeType")
@DiscriminatorValue(value="EMP")
@EntityListeners(value={PersistenceContextListener.class})
public class Employee {

@Id
private int employeeId;

@Basic(optional=false)
private String employeeName;

@Embedded
private EmployeePeriod employeePeriod;

@OneToMany(mappedBy="employee", cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private List phones; // OneToMany lazy Load Association

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
@JoinTable(
name="employee_project",
joinColumns={@JoinColumn(name="employeeId")},
inverseJoinColumns={
@JoinColumn(table="project",name="projectId"),
@JoinColumn(table="localproject",name="projectId"),
@JoinColumn(table="globalproject",name="projectId")}
)
private List projects; // ManyToMany Lazy Load Association

@OneToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY,targetEntity=Address.class)
@JoinColumns({
@JoinColumn(name="AddressId",referencedColumnName="AddressId"),
@JoinColumn(name="EmployeeAddressCountryId",referencedColumnName="AddressCountryId"),
@JoinColumn(name="EmployeeAddressCityId",referencedColumnName="AddressCityId")}
)
private Address address;

public Address getAddress() {
return address;
}

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

public int getEmployeeId() {
return employeeId;
}

public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getEmployeeName() {
return employeeName;
}

public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}

public List getPhones() {
return phones;
}

public void setPhones(List phones) {
this.phones = phones;
}

public List getProjects() {
return projects;
}

public void setProjects(List projects) {
this.projects = projects;
}

public EmployeePeriod getEmployeePeriod() {
return employeePeriod;
}

public void setEmployeePeriod(EmployeePeriod employeePeriod) {
this.employeePeriod = employeePeriod;
}

}

[/code]

  • Employee Entity does consider two additional associations one of type OneToMany with Phone entity and the second is ManyToMany with the Project entity.
  • By default EclipseLink does consider the lazy loading of such these associations, so no need for any further configuration as we’ve seen in the OneToOne and ManyToOne. See Figure 1.6 that shows you how can we achieve a lazy load easily.

ManyToMany And OneToMany Lazy Load

Figure 1.6

  • EclipseLink capable to lazy load either ManyToMany and OneToMany without any need for weaving.
  • The list of Phone entities does loaded lazily, cause it’s mapping marked as Lazy fetch type at the Employee entity.
  • The list of Project entities does loaded lazily, cause it’s mapping marked as Lazy fetch type at the Employee entity.
  • Each Lazy Loading mapping can be navigated by accessing the attribute for which the mapping belongs to.

Navigating ManyToMany and OneToMany Lazy Load

By executing the following code, you have a chance to navigate those lazily loaded mappings:

[code lang=”java”]

Employee employee = em.find(Employee.class, 1);
System.out.println("Phones Size :: "+ employee.getPhones().size());
System.out.println("Projects Size :: "+ employee.getProjects().size());

[/code]

  • Once you’ve been accessing the attribute that does relate to the mapping the EclipseLink will fetch the dependent objects directly.

The next coming fragment of output shows you the results in of executing the last code:

[code lang=”java”]

Phones Size :: 1
Projects Size :: 2

[/code]

Eager Loading

As we’ve mentioned previously, the Eager strategy is a requirement on the persistence provider runtime, in that the value must be eagerly fetched. Let’s look at the Employee entity in case the ManyToMany and OneToMany annotation have been changed to be fetched eagerly.

Employee.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="EmployeeType")
@DiscriminatorValue(value="EMP")
@EntityListeners(value={PersistenceContextListener.class})
public class Employee {

@Id
private int employeeId;

@Basic(optional=false)
private String employeeName;

@Embedded
private EmployeePeriod employeePeriod;

@OneToMany(mappedBy="employee", cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private List phones; // OneToMany Eager Load Association

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(
name="employee_project",
joinColumns={@JoinColumn(name="employeeId")},
inverseJoinColumns={
@JoinColumn(table="project",name="projectId"),
@JoinColumn(table="localproject",name="projectId"),
@JoinColumn(table="globalproject",name="projectId")}
)
private List projects; // ManyToMany EAGER Load Association

@OneToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY,targetEntity=Address.class)
@JoinColumns({
@JoinColumn(name="AddressId",referencedColumnName="AddressId"),
@JoinColumn(name="EmployeeAddressCountryId",referencedColumnName="AddressCountryId"),
@JoinColumn(name="EmployeeAddressCityId",referencedColumnName="AddressCityId")}
)
private Address address;

public Address getAddress() {
return address;
}

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

public int getEmployeeId() {
return employeeId;
}

public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getEmployeeName() {
return employeeName;
}

public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}

public List getPhones() {
return phones;
}

public void setPhones(List phones) {
this.phones = phones;
}

public List getProjects() {
return projects;
}

public void setProjects(List projects) {
this.projects = projects;
}

public EmployeePeriod getEmployeePeriod() {
return employeePeriod;
}

public void setEmployeePeriod(EmployeePeriod employeePeriod) {
this.employeePeriod = employeePeriod;
}

}

[/code]

See Figure 1.7 that shows you the impact of using Eager.

Impcat of Using Eager

Figure 1.7

  • Each dependent objects are fetched eagerly without need for accessing the attributes.
  • The Address is already fetched eagerly, cause we’ve removed the eclipselink weaving that could be used for enabling the OneToOne and ManyToOne lazy loading. Whenever such that Weaving is omitted, the Eclipselink persistence provider will load those assoications (OneToOne and ManyToOne) eagerly.

Using @Baisc To Provide Fetch Type

Typically, the using @Basic for providing a fetch type value is identical to what you’ve seen when it comes to provide such that value using one of the association annotations. But remember that @Basic couldn’t be used on a non-primitive data types (Also, other types is permitted to be used with the @Basic).

You can experienced using of @Basic on the employeeName and see the different if you’ve enabled the weaving. absolutely, you will get the same result as you did see.

Summary

The Lazy and Eager load are strategies considered by the Persistence Provider for optimizing the performance of the developed applications especially, those that could maintain a huge amount of objects and their associations. Lazy load strategy is a hint for persistence provider runtime to defer the fetching of associated objects until the accessing of the related attributes took place. At the other hand the Eager strategy, in that the associated objects are fetched directly. Java Persistence API provides you two different ways to determine the fetch type either @Basic or using of one of the association annotations (OneToOne, OneToMany, ManyToOne and ManyToMany).

Filed Under: Java EE Tagged With: EclipseLink, JPA

JPA Entity Listeners And Callback Methods

March 12, 2014 by Amr Mohammed Leave a Comment

Before JPA 2.1 the concept of Entity Listeners (Injectable EntityListeners) wasn’t defined until JPA 2.1 released. The entity listener concept allows the programmer to designate a methods as a lifecycle callback methods to receive notification of entity lifecycle events. A lifecycle callback methods can be defined on an entity class, a mapped superclass, or an entity listener class associated with an entity or mapped superclass.

Default entity listeners are entity listeners whose callback methods has been called by all entities that are defined in a certain persistence context (unit).  The lifecycle callback methods and entity listeners classes can be defined by using metadata annotations or by an XML descriptor.

Entity Listener (Default Listener) Using Entity Listener Class

If you’ve looked before for the introduction examples for eclipselink (See EclipseLink Tutorial), it’s time to listening about events that thrown by lifecycle of the entities. Let’s look at the first entity listener that would be listening for each defined entities in the persistence.xml.

PersistenceContextListener.java

[code lang=”java”]
package net.javabeat.eclipselink.data;

import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;

public class PersistenceContextListener {
@PrePersist
public void prePersist(Object object) {
System.out.println("PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: " + object);
}

@PostPersist
public void postPersist(Object object){
System.out.println("PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: " + object);
}

@PreRemove
public void PreRemove(Object object){
System.out.println("PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: " + object);
}

@PostRemove
public void PostRemove(Object object){
System.out.println("PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: " + object);
}

@PreUpdate
public void PreUpdate(Object object){
System.out.println("PersistenceContextListener :: Method PreUpdate Invoked Upon Entity :: " + object);
}

@PostUpdate
public void PostUpdate(Object object){
System.out.println("PersistenceContextListener :: Method PostUpdate Invoked Upon Entity :: " + object);
}

}
[/code]

  • Entity lifecycle callback methods can be defined on an entity listener class.
  • Lifecycle callback methods are annotated with annotation that specifying the callback events for which they are invoked.
  • Callback methods defined on an entity listener class should have the following signatures: void <METHOD> (Object), the object argument is the entity class for which the callback method is invoked.
  • The callback methods can have public, private, protected or package level access, but must not be static or final.
  • The following annotations designates lifecycle event callback methods of the corresponding types (entities).
  1. PrePersist: This callback method is invoked for a given entity before the respective Entity Manager executes persist operation for that entity.
  2. PostPersist: This callback method is invoked for a given entity after the respective Entity Manager executes persist operation for that entity.
  3. PreRemove: This callback method is invoked for a given entity before the respective Entity Manager executes remove operation for that entity. 
  4. PostRemove: This callback method is invoked for a given entity after the respective Entity Manager executes remove operation for that entity.
  5. PreUpdate: This callback method is invoked for a given entity before the respective Entity Manager executes merge operation for that entity.
  6. PostUpdate: This callback method is invoked for a given entity after the respective Entity Manager executes merge operation for that entity.
  7. PostLoad: The PostLoad method for an entity is invoked after the entity has been loaded into the current persistence context from the database or after the refresh operation has been applied to it.

The Entity & Mapped SuperClass With Listener

After we’ve seen a separate entity listener, let’s see a listener that could be defined at the entity itself.

Address.java

[code lang=”java”]
package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import javax.persistence.PrePersist;

@Entity(name="address")
public class Address {
@EmbeddedId
private AddressPK addressId;
private String addressCountry;
private String addressCity;

@OneToOne(cascade=CascadeType.ALL,mappedBy="address")
private Employee employee;

public Employee getEmployee() {
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
}

public String getAddressCountry() {
return addressCountry;
}
public void setAddressCountry(String addressCountry) {
this.addressCountry = addressCountry;
}
public String getAddressCity() {
return addressCity;
}
public void setAddressCity(String addressCity) {
this.addressCity = addressCity;
}

public AddressPK getAddressId() {
return addressId;
}

public void setAddressId(AddressPK addressId) {
this.addressId = addressId;
}

@PrePersist
public void prePersist(){
System.out.println("Address Entity :: Method PrePersist Invoked Upon Entity "+this);
}

}

[/code]

License.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.PostRemove;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.TableGenerator;

@MappedSuperclass
public abstract class License {

@Id
@GeneratedValue(generator="LICENSE_SEQ",strategy=GenerationType.SEQUENCE)
@TableGenerator(name="LICENSE_SEQ",pkColumnName="SEQ_NAME",valueColumnName="SEQ_NUMBER",pkColumnValue="LICENSE_ID",allocationSize=1,table="sequences")
protected int licenseId;

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "employeeId")
private Employee employee;

public Employee getEmployee() {
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
}

public int getLicenseId() {
return licenseId;
}

public void setLicenseId(int licenseId) {
this.licenseId = licenseId;
}

@PrePersist
public void prePersist(){
System.out.println("License Entity :: Method PrePersist Invoked Upon Entity "+this);
}

@PreRemove
public void peRemove(){
System.out.println("License Entity :: Method PreRemove Invoked Upon Entity "+this);
}

@PostRemove
public void postRemove(){
System.out.println("License Entity :: Method PostRemove Invoked Upon Entity "+this);
}
}

[/code]

  • Entity lifecycle callback methods can be defined on an entity class.
  • Lifecycle callback methods are annotated with annotation that specifying the callback events for which they are invoked within the defined entity.
  • Callback methods defined on an entity listener class should have the following signatures: void <METHOD> ().
  • The callback methods can have public, private, protected or package level access, but must not be static or final.
  • The annotations that designate for achieving the listening for the entity lifecycle events are the same for those defined in the entity listener class that defined above.
  • The definition of the lifecycle events callback methods are the same as defined in the mapped superclass as license mapped superclass depicted.

Persistence Configuration

[code lang=”xml”]
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="EclipseLink-JPA-Installation" transaction-type="RESOURCE_LOCAL">
<class>net.javabeat.eclipselink.data.Employee</class>
<class>net.javabeat.eclipselink.data.Address</class>
<class>net.javabeat.eclipselink.data.AddressPK</class>
<class>net.javabeat.eclipselink.data.License</class>
<class>net.javabeat.eclipselink.data.DriverLicense</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="OFF"/>
</properties>
</persistence-unit>
</persistence>
[/code]

Executable Application

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.License;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Begin a Transaction for creation
em.getTransaction().begin();
// Find the Employee
Employee employee = createEmployee();
// Find the Employee
License license = createDriverLicense(employee);
// Commit
em.getTransaction().commit();

// Begin a Transaction for Update an Employee
em.getTransaction().begin();
// Find the Employee
employee.setEmployeeName("Edward Halshmit");
em.merge(employee);
// Commit
em.getTransaction().commit();

// Begin a Transaction for removing an employee and driver license
em.getTransaction().begin();
// Remove License
em.remove(license);
// Find the Employee
em.remove(employee);
// Commit
em.getTransaction().commit();

}

public static Employee createEmployee(){
// Create an address entity
Address address = new Address();
AddressPK addressPk = new AddressPK();
addressPk.setAddressCountryId(1);
addressPk.setAddressId(1);
address.setAddressId(addressPk);
// Address Embeddable class (Type) instantiation
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Employee employee = new Employee();
employee.setEmployeeId(1);
employee.setEmployeeName("John Smith");

// Create an Employee Period Instance
EmployeePeriod period = new EmployeePeriod();
period.setStartDate(new Date());
period.setEndDate(new Date());

employee.setEmployeePeriod(period);

// Associate the address with the employee
employee.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
// PhoneId and PhoneCountryKeyId is now the primary key for the phone entity
firstPhone.setPhoneId(1);
firstPhone.setPhoneCountryKeyId("+441");
firstPhone.setPhoneNumber("4050 615");
firstPhone.setEmployee(employee);
// Create a list of phone
List phones = new ArrayList();
phones.add(firstPhone);

// Create a list of projects
List projects = new ArrayList();

// Set the project into employee
employee.setProjects(projects);
// Set the phones into your employee
employee.setPhones(phones);

// Persist the employee

em.persist(employee);

// return the persisted employee
return employee;
}

public static License createDriverLicense(Employee employee){
DriverLicense license = new DriverLicense(); // Create a driver license
license.setDriverLicenseName("All Vehicles License"); // Set License Name
license.setDriverLicenseIssueDate(new Date()); // Anonymous date
license.setDriverLicenseExpiryDate(new Date()); // Anonymous date
license.setEmployee(employee);
em.persist(license);
return license;
}

}

[/code]

The Rules Applied on the Lifecycle Callback Methods

The following rules apply to lifecycle callback methods:

  • Lifecycle callback methods may throw unchecked/runtime exceptions. A runtime exception thrown by a callback method that executes within a transaction causes that transaction to be marked for rollback if the persistence context is joined to the transaction.
  • Lifecycle callbacks can invoke JNDI, JDBC, JMS and enterprise beans.
  • In general, the lifecycle method of a portable application should not invoke EntityManager or query oprtations, access other instancesm or modify relationships within the same persistence context. A lifecycle callback methods may modify the non-relationship state of the entity on which it is invoked.

Precedence of Listeners Execution

The precedence of listeners execution are arranged as following:

  • Default Listener will be executed firstly, default listener apply to all entities in the persistence unit, so  if you’ve defined multiple listeners within @EntityListener as you’ve seen in the Employee entity, then the callback methods are invoked in the order as listener specified Unless explicitly excluded by means of the ExecludedDefaultListeners annotation.
  • The callback methods that are defined within the entity or mapped superclasses themselves should be executed after default listener and in the same order.
  • If multiple classes in an inheritance hierarchy (entity classes or mapped superclasses) define entity listeners, the listeners defined in the superclasses are invoked before the listeners defined for its sub-classes.

The Result of Executable Application

[code lang=”java”]

PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@d5d4de6
Address Entity :: Method PrePersist Invoked Upon Entity net.javabeat.eclipselink.data.Address@6e92b1a1
License Entity :: Method PrePersist Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@47f08ed8
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@d5d4de6
PersistenceContextListener :: Method PreUpdate Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@d5d4de6
PersistenceContextListener :: Method PostUpdate Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@d5d4de6
License Entity :: Method PreRemove Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@47f08ed8
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@d5d4de6
License Entity :: Method PostRemove Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@47f08ed8
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@d5d4de6

[/code]

What if we’ve changed the License and Address entities by allowing them defining an @EntityListener at their declaration to reference the PersistenceContextListener as you’ve seen at the Employee entity.

The Result of Executable Application After last changed

[code lang=”java”]

PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@343aff84
PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@301db5ec
Address Entity :: Method PrePersist Invoked Upon Entity net.javabeat.eclipselink.data.Address@301db5ec
PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@77546dbc
License Entity :: Method PrePersist Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@77546dbc
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@301db5ec
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@343aff84
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@77546dbc
PersistenceContextListener :: Method PreUpdate Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@343aff84
PersistenceContextListener :: Method PostUpdate Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@343aff84
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@77546dbc
License Entity :: Method PreRemove Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@77546dbc
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@343aff84
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@301db5ec
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@77546dbc
License Entity :: Method PostRemove Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@77546dbc
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@343aff84
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@301db5ec

[/code]

Inheritance of Callback Lifecycle Methods

The inheritance of callback lifecycle methods is applicable, so a lifecycle callback method for the same lifecycle event is also specified on the entity class or one or more of its entity or mapped superclasses, the callback methods on the entity class or superclasses are invoked first.

The sub-classes are permitted to override an inherited callback method of the same callback type (i.e. override the same method of superclass in the sub-class using the same annotation type), at this case the overridden method isn’t invoked. Let’s see the DriverLicense that override the prePersist method annotated with the same callback type (@PrePersist)

DriverLicense.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="driverlicenses")
public class DriverLicense extends License{

private String driverLicenseName;
@Temporal(TemporalType.DATE)
private Date driverLicenseExpiryDate;
@Temporal(TemporalType.DATE)
private Date driverLicenseIssueDate;

public String getDriverLicenseName() {
return driverLicenseName;
}
public void setDriverLicenseName(String driverLicenseName) {
this.driverLicenseName = driverLicenseName;
}
public Date getDriverLicenseExpiryDate() {
return driverLicenseExpiryDate;
}
public void setDriverLicenseExpiryDate(Date driverLicenseExpiryDate) {
this.driverLicenseExpiryDate = driverLicenseExpiryDate;
}
public Date getDriverLicenseIssueDate() {
return driverLicenseIssueDate;
}
public void setDriverLicenseIssueDate(Date driverLicenseIssueDate) {
this.driverLicenseIssueDate = driverLicenseIssueDate;
}

@PrePersist
public void prePersist(){
System.out.println("DriverLicense Entity :: Method PrePersist Invoked Upon Entity "+this);
}

}

[/code]

The Result is

[code lang=”java”]

PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@74b957ea
PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@edc86eb
Address Entity :: Method PrePersist Invoked Upon Entity net.javabeat.eclipselink.data.Address@edc86eb
PersistenceContextListener :: Method PrePersist Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@6f7918f0
DriverLicense Entity :: Method PrePersist Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@6f7918f0
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@edc86eb
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@74b957ea
PersistenceContextListener :: Method PostPersist Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@6f7918f0
PersistenceContextListener :: Method PreUpdate Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@74b957ea
PersistenceContextListener :: Method PostUpdate Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@74b957ea
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@6f7918f0
License Entity :: Method PreRemove Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@6f7918f0
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@74b957ea
PersistenceContextListener :: Method PreRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@edc86eb
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.DriverLicense@6f7918f0
License Entity :: Method PostRemove Invoked Upon Entity net.javabeat.eclipselink.data.DriverLicense@6f7918f0
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Employee@74b957ea
PersistenceContextListener :: Method PostRemove Invoked Upon Entity :: net.javabeat.eclipselink.data.Address@edc86eb

[/code]

  • If you’ve tried to override a method without mentioning the same method name and the same callback type, you’re probably about getting a new method that will not be count a callback method override.

Summary

The Entity callback lifecycle methods is one of the important subject when you are trying to go deep in the JPA. This tutorial provide you the required definition and counts for the callback methods that could help you debugging and traversing the different operations of JPA.

Filed Under: Java EE Tagged With: EclipseLink, JPA

EclipseLink – DDL Schema Generation in JPA 2.1

March 8, 2014 by Amr Mohammed Leave a Comment

If you’ve a good experience in the Java Persistence API, you can configure the JPA to generates the required schema. These are not part of the JPA implementation prior to the JPA 2.1 specification. These are considered as the extensions for the JPA provider. However, this has been standardized from the JPA 2.1 release. JPA 2.1 added a series of properties for database schema maintenance and generation. This tutorial explains how to use the EclipseLink for generating schema for the database tables.

EclipseLink provides you a eclipselink.dll- generation to specify how EclipseLink generates the DDL (Data Defintion Language) for the database schema (tables and constraints) on deployment.

EclipseLink DDL Valid Values

The property of eclipselink.ddl- generation has multiple valid values and these are:

  • create-tables: EclipseLink will attempt to execute a CREATE TABLE SQL for each table. If the table already exists, EclipseLink will follow the default behavior for your specific database and JDBC driver combination (When a CREATE TABLE SQL is issued for an already existing table). In most cases an exception is thrown and the table is not created; the existing table will be used. EclipseLink will then continue with the next statement.
  • create-or-extend-tables: EclipseLink will attempt to create tables. If the table exists, EclipseLink will add any missing columns.
  • drop-and-create-tables: EclipseLink will attempt to DROP all tables, then CREATE all tables. If any issues are encountered. EclipseLink will follow the default behavior for your specific database and specific JDBC driver combination, then continue with the next statement. This is useful in development if the schema frequently changes or during testing when an existing data needs to be cleared.
  • none: default, no ddl generated; no schema generated.

Generated EclipseLink Tutorial Schema

The examples that created for serving the EclipseLink Tutorial were depends on database schema that created before. The entities that are created now contains a different relationships and properties ranging from primary keys (Simple and composite) and associations (including OneTOne, OneToMany, ManyToOne and ManyToMany) to inheritance and identities generation. But what could happen if we are going to use the EclipseLink DDL generation; is it enough for creating identical schema for that manually created schema. Let’s see.

Figure 1.0 shows you the manually created schema contains the existing associations and properties for its tables.

EclipseLink - DDL Schema Generation in JPA 2.1

Figure 1.0

  • The model described the associations from a database perspective.

Figure 1.1 shows you the schema that’s created by using the EclipseLink -ddl-generation.

JavaBeat Schema Created By Using EclipseLink - Schema Generation

Figure 1.1

  • The JavaBeat schema that shown at the Figure 1.1 displays the generated schema by using EclipseLink-ddl-generation.
  • The model describe the schema from an Object-Oriented perspective.

The Required Persistence Configuration

[code lang=”xml”]

<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat-jpa-generate"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>

[/code]

  • The property eclipselink.ddl-generation will be used to configure the strategy that would be used for create the schema.

Export the Generated DDL Into External File

You’ve a choice to export the generated schema into external DDL, you’ve to add a new property into your persistence configuration.

[code lang=”xml”]

<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat-jpa-generate"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="sql-script"/>
</properties>

[/code]

  • The eclipselink.ddl-generation.output-mode property has three attributes that could be applied.
  1. both: DDL will be generated and written to both the database and a file.
  2. database: (Default) DDL will be generated and written to the database only.
  3. sql-script: DDL will be generated and written to a file only.
  • The ddl file will be generated and given a default name.

Assign a name to the files generated:

If you’ve desired to give a specific name for the generated files, you can use an additional eclipselink properties.

[code lang=”xml”]

<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat-jpa-generate"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="sql-script"/>
<property name="eclipselink.create-ddl-jdbc-file-name" value="sql-create-script"/>
// Created statements file name
<property name="eclipselink.drop-ddl-jdbc-file-name" value="sql-drop-script"/>// Dropped statements file name
</properties>

[/code]

Change the location of the created files:

If you’ve desired to change the location of the generated files, you can use an additional eclipselink property called eclipselink.application-location.

[code lang=”xml”]

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat-jpa-generate"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="sql-script"/>
<property name="eclipselink.create-ddl-jdbc-file-name" value="sql-create-script"/>
<property name="eclipselink.drop-ddl-jdbc-file-name" value="sql-drop-script"/>
<property name="eclipselink.application-location" value="c:/javabeat-database-files"/>

[/code]

Figure 1.2 shows you the files created under the specified folder.

Created Files Under Specific Folder

Figure 1.3

Deploy-On-Startup

If you’ve desired to generate the DDL schema upon that’s time the entity manager factory acquired not by creation of entity manager instance you have to provide a eclipselink deploy-on-startup property. That property accepting two values true or false, where the true means the DDL generation should started once the factory of entity manager instance has been created, meanwhile the false means the DDL generation should started once the entity manager instance has been created.

[code lang=”xml”]

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat-jpa-generate"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="sql-script"/>
<property name="eclipselink.create-ddl-jdbc-file-name" value="sql-create-script"/>
<property name="eclipselink.drop-ddl-jdbc-file-name" value="sql-drop-script"/>
<property name="eclipselink.application-location" value="c:/javabeat-database-files"/>
<property name="eclipselink.deploy-on-startup" value="false"/>

[/code]

  • This property is important if you’ve worked in a huge application, in that the database creation might take a while or in case the factory creation take place at the initialization of the application and the entity manager not created yet.

Summary

Eclipselink provides much extension properties that can be stated at the persistence.xml file which can be used to configure the EclipseLink JPA framework. This tutorial mentioned properties that can be used to generate a database schema based on the created objects.

This is not only the properties that could be provided by the eclipse for such that configuration, but also it contains other additional properties might be discussed on later tutorial for handling eclipselink exception, for accessing eclipselink descriptor and mapping API.

Filed Under: Java EE Tagged With: EclipseLink, JPA

JPA Annotations – @GeneratedValue, @SequenceGenerator and @TableGenerator

March 7, 2014 by Amr Mohammed Leave a Comment

We’ve already discussed a different kind of primary keys, either simple or composite primary keys have assigned an inline values in the executable applications that were made. by looking into @Id, @IdClass or @EmbeddedId examples you could see that. But what if we would have some generator to generate these primary values. This tutorial explains the ID generator concept in details. The Java Persistence API including the EclipseLink distribution provides several types of primary key generation annotations.

@GeneratedValue

The @GeneratedValue consider the entry point for primary key generation, it provides the specification of generation strategies for the values of primary keys. The GeneratedValue annotation may be applied to a primary key property of field of an entity or mapped superclass  in a conjunction with the Id annotation. The values that can be used with the @GeneratedValue are those values defined inside the enum GenerationType. GenerationType.java

[code lang=”java”]
public enum GenerationType {TABLE,SEQUENCE,IDENTITY,AUTO};
[/code]

  • TABLE: Is a generator type value indicates that the must assign primary keys for the entity using a Database Table to ensure uniqueness.
  • SEQUENCE & IDENTITY: Are a generator types that specify the use of a database sequence or identity column respectively.
  • AUTO: Is a generator type indicates that the persistence provider should select an appropriate strategy for the particular database.

Anatomy of @GeneratedValue

  • Target: Field and Method
  • Uses:@GeneratedValue
  • Argument:
    1. strategy(Optional): The primary key generation strategy that the persistence provider must use to generate the annotated entity primary key.
    2. generator (Optional): The name of the primary generator to use as specified in the SequenceGenerator or TableGenerator.

Let’s see the implementation of different strategies using the same entity. As you’ve noted before in the EclipseLink Tutorial, we’ve created a mapped superclass previously, so this tutorial should clarify all strategies using License class example.

License Entity

The following class shows you the License entity without using the @GeneratedValue.

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class License {

@Id
protected int licenseId; // This primary key field has no generator

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "employeeId")
private Employee employee;

public Employee getEmployee() {
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
}

public int getLicenseId() {
return licenseId;
}

public void setLicenseId(int licenseId) {
this.licenseId = licenseId;
}
}

[/code]

  • The License mapped superclass provide an identity named licenseId.
  • The licenseId has no primary key generator
  • In case we’ve not used a generator and not provided a primary key value, the JPA will consider the default value for int primitive types (the default value is zero) and the persist will success for the first time. But when it comes into the second persist the JPA will throw an exception indicate that (Duplicate entry ‘0’ for key primary key).

Primary Key Generation Using Sequence Generator

At this example, you would be seeing a database sequence for generating a primary keys.

Anatomy of @SequenceGenerator

The @SequenceGenerator annotation defines a primary key generator that may be referenced by name when a generator element is specified for the GeneratedValue annotation.A sequence generator may be specified on the entity class or on the primary key field or property.

  • Target: Type, Method and Field
  • Uses:@SequenceGenerator
  • Argument:
    1. name (Required): A unique generator name that can be referenced by one or more classes to be the generator for primary key values.
    2. sequenceName (Optional): The name of the database sequence object from which to obtain primary key values.
    3. initialValue (Optional): The value from which the sequence object is to start generating.
    4. allocationSize (Optional): The amount to increment by when allocating sequence numbers from the sequence.

Database Sequence Creation

This sample of sequence creation should use the Oracle database, cause MySQL support auto increment which is not consider as a sequence. Figure 1.0 and 1.1 shows you the DriverLicense Table and sequence that created on the Oracle database. Note that the DriverLicense Table doesn’t consider any further relations as you’ve seen in the previous examples. Driver License Table

Figure 1.0

Driver License Sequence

Figure 1.1

License Entity Uses a Sequence Generator

The following License entity does use the sequence generator for generating the primary keys for the entities that created from the License (in case the license isn’t mapped superclass) and from any entity belongs to the License inheritance. License.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.SequenceGenerator;

@MappedSuperclass
public abstract class License {

@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="LICENSE_SEQ")
@SequenceGenerator(name="LICENSE_SEQ",sequenceName="LICENSE_SEQ",allocationSize=1)
protected int licenseId;

public int getLicenseId() {
return licenseId;
}

public void setLicenseId(int licenseId) {
this.licenseId = licenseId;
}
}

[/code]

DriverLicense.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="driverlicenses")
public class DriverLicense extends License{

private String driverLicenseName;
@Temporal(TemporalType.DATE)
private Date driverLicenseExpiryDate;
@Temporal(TemporalType.DATE)
private Date driverLicenseIssueDate;

public String getDriverLicenseName() {
return driverLicenseName;
}
public void setDriverLicenseName(String driverLicenseName) {
this.driverLicenseName = driverLicenseName;
}
public Date getDriverLicenseExpiryDate() {
return driverLicenseExpiryDate;
}
public void setDriverLicenseExpiryDate(Date driverLicenseExpiryDate) {
this.driverLicenseExpiryDate = driverLicenseExpiryDate;
}
public Date getDriverLicenseIssueDate() {
return driverLicenseIssueDate;
}
public void setDriverLicenseIssueDate(Date driverLicenseIssueDate) {
this.driverLicenseIssueDate = driverLicenseIssueDate;
}
}

[/code]

  • The License entity uses the @GeneratedValue for providing a both of generator type and name.
  • The generator type is SEQUENCE and the name is LICENSE_SEQ.
  • The License entity uses the @SequenceGenerator for providing the name of the sequence that’s would be consumed by the @GeneratedValue, the name of the database sequence and the allocation size.

Required Persistence Configuration

persistence.xml

[code lang=”java”]
<persistence-unit name="EclipseLink-JPA-OracleDS" transaction-type="RESOURCE_LOCAL">
<!– Entities Created Before –>
<class>net.javabeat.eclipselink.data.License</class>
<class>net.javabeat.eclipselink.data.DriverLicense</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="javax.persistence.jdbc.user" value="ucm"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="javax.persistence.jdbc.password" value="ucm"/>
</properties>
</persistence-unit>
[/code]

Required Libraries

As you’ve noted in the persistence.xml above, the database that’s being used for achieving a sequence generator is an Oracle database, so that you’ve had installed a new library in your project classpath that’s JAR is called ojdbc14.jar. for installing a new library you have to follow the below steps:

  • Right click on the project that you would be adding the JAR in its classpath.
  • Select Java Build Path from the left pane.
  • From the Java Build Path Area click on Add External JARs.
  • Add the JAR by navigating into its JAR location.

Executable Application for Generating a Primary keys using Sequence Generator

JPAImpl.java

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-OracleDS");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Begin a Transaction
em.getTransaction().begin();
// Create a Driver License
createDriverLicense();
// Commit
em.getTransaction().commit();
}

public static void createDriverLicense(){
DriverLicense license = new DriverLicense(); // Create a driver license
license.setDriverLicenseName("All Vehicles License"); // Set License Name
license.setDriverLicenseIssueDate(new Date()); // Anonymous date
license.setDriverLicenseExpiryDate(new Date()); // Anonymous date
em.persist(license);
}

}

[/code]

  • The DriverLicense entity doesn’t provide a primary key as you’ve noted in the provided examples at the EclipseTutorial.
  • The primary keys are generated automatically using a SequenceGenetator that defined in the License mapped superclass.

The Persisted Records Using Sequence Generator

Figure 1.2 shows you the records that persisted into the Oracle database using a sequence generator. License Records Using a Sequence Generator

Figure 1.2

Primary Key Generation Using Table Generator

At this example, you would be seeing a database table for generating a primary keys.

Anatomy of @TableGenerator

The @TableGenerator annotation defines a primary key generator that may be referenced by name when a generator element is specified  for the @GeneratedValue. A Table generator may be specified on the entity class or on the primary key field or property.

  • Target: Type, Method and Field
  • Uses:@TableGenerator
  • Argument:
    1. name (Required): A unique generator name that can be referenced by one or more classes to be the generator for id values.
    2. table (Optional): Name of table that stores the generated for id values.
    3. catalog (Optional): The catalog of the table.
    4. schema (Optional): The schema of the table.
    5. pKColumnName (Optional): Name of the primary key column in the table.
    6. valueColumnName (Optional): Name of the column that stores the last value generated.
    7. pKColumnValue (Optional): The primary key value in the generator table that distinguishes this set of generated values from others that may be stored in the table.
    8. initialValue (Optional): The value used to initialize the column that stores the last value generated.
    9. allocationSize (Optional): The amount to increment by when allocating id numbers from the generator.
    10. uniqueConstraints (Optional): Unique constraints that are to be placed on the table.

Database Table Sequence Creation

MySQL database is capable to create table sequence, so at this section of primary key generation we would return back into the previous examples that already made using the MySQL database. Figure 1.0 and 1.1 shows you the  Table sequence and DriverLicense Table that created on the MySQL database respectively.

Table Sequence

Figure 1.0

Previous Created Driver License

Figure 1.1

  • The Table sequence that created contains two columns one for sequence name and the other for sequence number.
  • Nothing changed on drive licenses table.

License Entity Uses a Table Sequence Generator

The following License entity does use the Table sequence generator for generating the primary keys for the entities that created from the License (in case the license isn’t mapped superclass) and from any entity belongs to the License inheritance. License.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.TableGenerator;

@MappedSuperclass
public abstract class License {

@Id
@GeneratedValue(generator="LICENSE_TABLE_SEQ",strategy=GenerationType.TABLE)
@TableGenerator(name="LICENSE_TABLE_SEQ",
table="sequences",
pkColumnName="SEQ_NAME", // Specify the name of the column of the primary key
valueColumnName="SEQ_NUMBER", // Specify the name of the column that stores the last value generated
pkColumnValue="LICENSE_ID", // Specify the primary key column value that would be considered as a primary key generator
allocationSize=1)
protected int licenseId;

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "employeeId")
private Employee employee;

public Employee getEmployee() {
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
}

public int getLicenseId() {
return licenseId;
}

public void setLicenseId(int licenseId) {
this.licenseId = licenseId;
}
}

[/code]

DriverLicense.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="driverlicenses")
public class DriverLicense extends License{

private String driverLicenseName;
@Temporal(TemporalType.DATE)
private Date driverLicenseExpiryDate;
@Temporal(TemporalType.DATE)
private Date driverLicenseIssueDate;

public String getDriverLicenseName() {
return driverLicenseName;
}
public void setDriverLicenseName(String driverLicenseName) {
this.driverLicenseName = driverLicenseName;
}
public Date getDriverLicenseExpiryDate() {
return driverLicenseExpiryDate;
}
public void setDriverLicenseExpiryDate(Date driverLicenseExpiryDate) {
this.driverLicenseExpiryDate = driverLicenseExpiryDate;
}
public Date getDriverLicenseIssueDate() {
return driverLicenseIssueDate;
}
public void setDriverLicenseIssueDate(Date driverLicenseIssueDate) {
this.driverLicenseIssueDate = driverLicenseIssueDate;
}
}

[/code]

Required Persistence Configuration

[code lang=”java”]
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="EclipseLink-JPA-Installation" transaction-type="RESOURCE_LOCAL">

<!– Some Entities have omit intentionally –>

<class>net.javabeat.eclipselink.data.License</class>
<class>net.javabeat.eclipselink.data.DriverLicense</class>
<class>net.javabeat.eclipselink.data.Employee</class>
<class>net.javabeat.eclipselink.data.ICDLComputerLicense</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="" value=""/>
</properties>
</persistence-unit>
[/code]

  • If you’ve never ever see the previous entities before and you would learn more about it, refer to the EclipseLink Tutorial.
  • The DriverLicense is mentioned in the persistence.xml
  • The License mapped superclass is mentioned in the persistence.xml
  • No need to mention the generator of the primary keys.

Executable Application for Generating a Primary keys using Table Sequence Generator

JPAImpl.java

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Begin a Transaction
em.getTransaction().begin();
// Find the Employee
Employee employee = em.find(Employee.class, 1);
// Create a Driver License
createDriverLicense(employee);
// Commit
em.getTransaction().commit();
}

public static void createDriverLicense(Employee employee){
DriverLicense license = new DriverLicense(); // Create a driver license
license.setDriverLicenseName("All Vehicles License"); // Set License Name
license.setDriverLicenseIssueDate(new Date()); // Anonymous date
license.setDriverLicenseExpiryDate(new Date()); // Anonymous date
license.setEmployee(employee);
em.persist(license);
}

}

[/code]

The Persisted Records Using Table Sequence Generator

Figure 1.2 shows you the records that persisted into the Oracle database using a Table sequence generator. Records Persisted Using Table Sequence

Figure 1.2

The impact of adding three records of driver license on the Table sequence is shown at the Figure 1.3

Impact of adding DriverLicenses on Table Sequence

Figure 1.3

  • If you’ve noted about the SEQ_NUMBER, it’s value is 3 cause this is the last number that has been generated.

IDENTITY & AUTO Generators

The IDENTITY value specify the use of an identify column, so if you’ve noted the License mapped superclass, you should be able see the licenseId as an identified property. The IDENTITY strategy is one of the most simple strategy that could be applied. Let’s look at the License entity if we’ve decided to use the IDENTITY strategy. License.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class License {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
protected int licenseId;

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "employeeId")
private Employee employee;

public Employee getEmployee() {
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
}

public int getLicenseId() {
return licenseId;
}

public void setLicenseId(int licenseId) {
this.licenseId = licenseId;
}
}

[/code]

  • The primary key of the License entity should be annotated using @GeneratedValue, but this time with an IDENTITY as generator.

Also, your database engine should support the AUTO_INCREMENT principle. Figure 1.4 shows you the updated licenseId column. Auto Increment Selected

Figure 1.4

  • The licenseId primary key is updated to be Auto Increment.

That’s what you have to do if you’ve selected and Identity as a primary key generator. Now let’s execute the previous executable JPAImpl. The JPAImpl will execute smoothly without change, that’s because the IDENTITY needs no more that an auto incremental primary key column. See Figure 1.5 that shows you an additional records that persisted using IDENTITY. Persisted Records Using Identity

Figure 1.5

AUTO value indicates that the persistence provider should pick an appropriate strategy for the particular database, in case we’ve used a MySQL and annotate the License entity using Auto, we almost probably getting such that exception.

[code lang=”java”]

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table ‘javabeat.sequence’ doesn’t exist
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2375)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2359)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:890)
… 32 more

[/code]

It’s clear that the JPA select sequence as a primary key strategy for generating a primary keys. In general Auto generation may expect a database resource to exist, or it may attempt to create one. A vendor may provide dcoumention on how to create such resources in the event that it doesn’t support schema generation or cannot create schema resource at runtime.

Summary

This tutorial is intended to explain the different ways of generating a primary keys. We’ve already clarified the using of @GeneratedValue annotation and the different possible values that could occurred within it. The JPA provides a lot of generator that ranging from simple to complex. The most simple generators that could be used are IDENTITY and AUTO, meanwhile the most complex generators that are used a little more work to achieve are SEQUENCE and TABLE SEQUENCE.

Filed Under: Eclipse, Java, Java EE Tagged With: EclipseLink, JPA

JPA Entity Primary Key Using @Id and @IdClass

March 7, 2014 by Amr Mohammed Leave a Comment

At this tutorial we’ve explained the concept of entity identification. Entity identification is the process in which the Java Persistence Implementation identify an entity uniquely from set of entities that belong to the same type on a memory level or a database level. Each entity that located in the persistence context must has a unique identifier called Primary Key.

The primary key must be defined on the entity that is form the root of the entity hierarchy or on mapped superclass of the entity hierarchy. The primary key must be defined once in an entity hierarchy, so if you’ve ever tried to create an entity without mentioning of its primary key (Entity Identifier), you are always getting a compiler error as you would be seeing in the following fragment  below.

Missing Identity

This fragment of code was extracted from a previous code that made before for Employee Entity (See EclipseLink Tutorial Examples). The identifier is only defined inside Employee entity; Employee is the root of the entity hierarchy that contains a Developer, ContractorDeveloper and FreelanceDeveloper as a sub-classes (entities).

A simple (i.e non-composite) primary key must correspond to a single entity persistent field or property of the entity class. The @Id annotation is used to denote a simple primary key. A composite primary key must correspond to a either a single persistent field or property or to a set of fields or properties.

The primary key (or field or property of a composite primary key) should be one of the following types:

  • Java primitive types
  • Java primitive wrapper types
  • java.lang.String
  • java.util.Date (note that the Temporal Type should be specified as DATE)
  • java.sql.Date

No rules for simple primary key and few rules applied to composite primary key. The following are the rules applied to the composite primary key:

  • The primary key class must be public and must have no-arg constructor.
  • The primary key class must be serializable
  • The primary key class must define the equals and hashCode methods.
  • The composite primary key must either be represented and mapped as embeddable class or must be represented and mapped to multiple fields or properties of the entity class as you would be seeing in this tutorial.
  • If the composite primary key class is mapped to multiple fields or properties of the entity class, the names of primary key field or properties in the primary class and those of the entity class must correspond and their types must be the same.
  • If the property-access based is used, the properties of the primary key class must be public or protected.

@Id

The Id annotation specifies the primary key property or field of an entity. The Id annotation may be applied in an entity or mapped superclass. See the following fragment of code that shows you the Project entity. Project entity is the root of the entity inheritance.

Project.java

[code lang=”java”]
package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToMany;

@Entity(name="Project")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Project {
@Id
private int projectId;

private String projectName;

@ManyToMany(mappedBy="projects",cascade=CascadeType.ALL)
private List employees;

public int getProjectId() {
return projectId;
}

public void setProjectId(int projectId) {
this.projectId = projectId;
}

public String getProjectName() {
return projectName;
}

public void setProjectName(String projectName) {
this.projectName = projectName;
}

public List getEmployees() {
return employees;
}

public void setEmployees(List employees) {
this.employees = employees;
}
}
[/code]

  • The Project entity defines the entity identifier, so no need for defining it again the sub-classes that inherit from it.

Let’s see a GlobalProject entity that inherit the Project.

GlobalProject.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.math.BigDecimal;

import javax.persistence.Entity;

@Entity
public class GlobalProject extends Project {
private String projectCountry;
private BigDecimal projectBudget;
public String getProjectCountry() {
return projectCountry;
}
public void setProjectCountry(String projectCountry) {
this.projectCountry = projectCountry;
}
public BigDecimal getProjectBudget() {
return projectBudget;
}
public void setProjectBudget(BigDecimal projectBudget) {
this.projectBudget = projectBudget;
}
}

[/code]

  • No entity identifier has been defined, cause it’s already defined in the Project.

Anatomy of @Id

  • Target: Field or Methods
  • Uses: @Id
  • Argument: No argument provided

[code lang=”java”]

@Target({METHOD, FIELD}) @Retention(RUNTIME)

public @interface Id {}

[/code]

@IdClass

The IdClass annotation is applied to an entity class or mapped superclass to specify a composite primary key class that’s mapped to multiple fields or properties of the entity.The names of primary key field or properties in the primary class and those of the entity class must correspond and their types must be the same. The Id annotation must also be applied to the corresponding fields or properties of the entity. The next coming lines will show you how to use the IdClass annotation.

Anatomy of @IdClass

  • Target: Type
  • Uses: @IdClass
  • Argument: value that’s must be a class instance

[code lang=”java”]

@Target({TYPE}) @Retention(RUNTIME)

public @interface IdClass {
Class value;
}

[/code]

Database Phone Table

Figure 1.0 shows you the changes that happened at the Phone Table.

Phone Table Uses composite primary key

Figure 1.0

As you’ve noted in the Figure 1.0, the Phone entity now uses a composite primary key. Let’s see the primary key class.

Implementation of PhonePK

PhonePK.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.io.Serializable;

import javax.persistence.IdClass;

// IdClass annotation used  for composite primary key creation

@IdClass(PhonePK.class)

public class PhonePK implements Serializable{
private String phoneCountryKeyId;
private int phoneId;
public String getPhoneCountryKeyId() {
return phoneCountryKeyId;
}
public void setPhoneCountryKeyId(String phoneCountryKeyId) {
this.phoneCountryKeyId = phoneCountryKeyId;
}
public int getPhoneId() {
return phoneId;
}
public void setPhoneId(int phoneId) {
this.phoneId = phoneId;
}
// The override of equals, see the rules mentioned above for creating a composite primary key
public boolean equals(Object obj){
if(obj instanceof PhonePK){
PhonePK phonePK = (PhonePK)obj;
if(this.phoneId == phonePK.getPhoneId() && this.phoneCountryKeyId.equals(phonePK.getPhoneCountryKeyId())){
return true;
}
}
else {
return false;
}
return false;
}
// The override of hashCode, see the rules mentioned above for creating a composite primary key
public int hashCode(){
return super.hashCode();
}

}

[/code]

Implementation of Phone Entity

Phone.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity(name="Phones")
// If you’ve removed the @IdClass, you’ve got a compiler error
@IdClass(PhonePK.class)
public class Phone {
// By defining two @Id, the JPA assumes that you’ve defined a composite primary key
/* The properties defined inside the Phone entity and annotated with the @Id have the same name and type
of those properties defined in the PhonePK primary key
*/
@Id private int phoneId;
@Id private String phoneCountryKeyId;
private String phoneNumber;

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="employeeId")
private Employee employee;

public int getPhoneId() {
return phoneId;
}
public void setPhoneId(int phoneId) {
this.phoneId = phoneId;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public String getPhoneCountryKeyId() {
return phoneCountryKeyId;
}
public void setPhoneCountryKeyId(String phoneCountryKeyId) {
this.phoneCountryKeyId = phoneCountryKeyId;
}

}

[/code]

Executable Application

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.PhonePK;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){

// Begin a Transaction
em.getTransaction().begin();
createEmployee();
// Commit
em.getTransaction().commit();
// Inquiry about Phone Using the PhonePK
inquiryUsingPhonePK();

}

public static void createEmployee(){
// Create an address entity
Address address = new Address();

// Address Embeddable class (Type) instantiation
AddressPK addressPK = new AddressPK();
addressPK.setAddressId(1);
addressPK.setAddressCountryId(1);
// addressPK.setAddressCityId(1);
address.setAddressId(addressPK);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Employee employee = new Employee();
employee.setEmployeeId(2);
employee.setEmployeeName("John Smith");

// Create an Employee Period Instance
EmployeePeriod period = new EmployeePeriod();
period.setStartDate(new Date());
period.setEndDate(new Date());

employee.setEmployeePeriod(period);

// Associate the address with the employee
employee.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
// PhoneId and PhoneCountryKeyId is now the primary key for the phone entity
firstPhone.setPhoneId(3);
firstPhone.setPhoneCountryKeyId("+441");
firstPhone.setPhoneNumber("4050 615");
firstPhone.setEmployee(employee);
// Create a list of phone
List phones = new ArrayList();
phones.add(firstPhone);

// Create a list of projects
List projects = new ArrayList();

// Set the project into employee
employee.setProjects(projects);
// Set the phones into your employee
employee.setPhones(phones);

// Persist the employee

em.persist(employee);
}

public static void inquiryUsingPhonePK(){
PhonePK pk = new PhonePK();
pk.setPhoneId(3);
pk.setPhoneCountryKeyId("+441");
Object obj = em.find(Phone.class, pk);
if(obj instanceof Phone){
Phone phone = (Phone)obj;
System.out.println(phone.getPhoneId());
System.out.println(phone.getPhoneCountryKeyId());
System.out.println(phone.getPhoneNumber());
}
System.out.println(obj);
}

}

[/code]

  • The Phone entity has a composite primary key
  • The phone entity has been created successfully with its new primary key
  • The PhonePK primary key used later for inquiring the Phone persisted instance.

@EmbeddedId

The @EmbeddedId is the second way that already used before for creating a primary key. See @Embeddable, Embeeded and @EmbeddedId example.

Summary

Java Persistence API provides you a various kind of primary keys. Primary key used to identify the entity that’s being persisted either in the memory or inside the database. @Id used to define a simple primary key, while the @IdClass and @EmbeddedId for composite.

Filed Under: Java EE Tagged With: EclipseLink, JPA

EclipseLink / JPA Annotations – @Embeddable, @Embedded and @EmbeddedId

March 5, 2014 by Amr Mohammed Leave a Comment

We’ve been providing several examples so far, most of the examples are being provided weren’t use complex persistent entity states; we are using a primitive data types such (int, String, BigDecimal, Date and etc ..).

But what’s happened if you we’ve created an entity whose persistent states are other types (classes). No doubt that it should make the developed applications more easier rather enclose the entity states to be only primitive types. Such that situation is happened frequently, so the JPA specifier takes in its consideration in that cases.

This tutorial will cover @Embeddable, @Embedded and @EmbeddedId, in that the @Embeddable annotation is used to specify a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Also, @Embedded is used to specify a persistent field or property of an entity whose value is an instance of an embeddable class. And finally the @EmbeddedId is applied to a persistent field or property of an entity class or mapped superclass to denote the composite primary key that is an embeddable class.

Let’s start discussing the @Embeddable, cause it’s the entry point for understanding the new concept.

@Embeddable

As we’ve mentioned before and from the definition of the @Embeddable, it is used to specify or define a class (Type) whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. So the @Embeddable annotation has never been used with the properties or attributes.

Anatomy of @Embeddable Annoation

The specification of the @Embeddable is:

[code lang=”java”]
@Target({TYPE}) @Retention (Runtime)
public @interface Embeddable {}
[/code]

  • Target: Types
  • Uses: @Embeddable
  • Arguments: No argument provided

Classes Design

If you’ve read through the previous examples that provided before (See EclipseLink – JPA Tutorial), you’ll find an Employee entity, by adding a new property (not an association or relation; just a property) into Employee entity called (employeePeriod) which contains startDate and endDate as a primitive types. See Figure 1.0 that depict what should Employee and EmployeePeriod entities looks like.

JPA Annotation Class Design

Figure 1.0

  • Employee entity does composite an EmployeePeriod type.
  • EmployeePeriod type is used to declare the employeePeriod property within an Employee.

Employee Table

See Figure 1.2 that shows you the impact of adding an EmployeePeriod into Employee Table.

EmployeeTable

Figure 1.2

  • A new EmployeeStartDate and EmployeeEndDate columns are added into Employee Table.
  • The new columns are added into Employee Table, because of the Embeddable class (Type) persistent states are persisted into the owning entity.

EmployeePeriod Class (Type)

As you’ve noted at the classes design, the EmployeePeriod is an attribute defined within an Employee entity, so when Entity Manager comes to persist an Employee, it should take care of EmployeePeriod.

EmployeePeriod.java

[code lang=”java”]
package net.javabeat.eclipselink.data;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Embeddable
public class EmployeePeriod {
@Column(name="EmployeeStartDate")
@Temporal(TemporalType.DATE)
private Date startDate;

@Column(name="EmployeeEndDate")
@Temporal(TemporalType.DATE)
private Date endDate;

public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}

}
[/code]

  • The @Embeddable class (type) isn’t specify a Table, cause the the Embeddable class (type) should depends on the owning entity when it comes to persist.
  • The properties that defined in the EmployeePeriod embeddable class (type) defines their mapping information and the columns that should be referred to using @Column.
  • As defined properties are Date, so it is important to specify the @Temporal annotation.

Employee Entity With @Embedded

Employee.java

[code lang=”java”]
package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="EmployeeType")
@DiscriminatorValue(value="EMP")
public class Employee {

@Id
private int employeeId;

@Basic(optional=false)
private String employeeName;

@Embedded
private EmployeePeriod employeePeriod;

@OneToMany(mappedBy="employee", cascade=CascadeType.ALL)
private List<Phone> phones;

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(
joinColumns={@JoinColumn(name="employeeId")},
inverseJoinColumns={@JoinColumn(table="project",name="projectId"),@JoinColumn(table="localproject",name="projectId"),@JoinColumn(table="globalproject",name="projectId")}
)
private List<Project> projects;

@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="AddressId")
private Address address;

public Address getAddress() {
return address;
}

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

public int getEmployeeId() {
return employeeId;
}

public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getEmployeeName() {
return employeeName;
}

public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}

public List<Phone> getPhones() {
return phones;
}

public void setPhones(List<Phone> phones) {
this.phones = phones;
}

public List<Project> getProjects() {
return projects;
}

public void setProjects(List<Project> projects) {
this.projects = projects;
}

public EmployeePeriod getEmployeePeriod() {
return employeePeriod;
}

public void setEmployeePeriod(EmployeePeriod employeePeriod) {
this.employeePeriod = employeePeriod;
}

}
[/code]

  • The Employee defines a new property named (employeePeriod) that’s embeddable type.
  • The properties of employeePeriod depend on Employee entity for specifying the table that they are going to persist into.
  • The JPA doesn’t know if you were using an Embeddable class (type) or not, except if you were specifying the @Embedded.
  • The Embedded notify the JPA implementation that, it has an Embeddable class (Type), so consider the mapping information in the Embeddable class in the context of the owning (Employee) entity.

Persistence Configuration Changes Required

Nothing needs a change, except the adding of new EmployeePeriod class (type) in the Persistence Context. For the detailed configuration, please read our previous tutorials.

[code lang=”xml”]
<class>net.javabeat.eclipselink.data.EmployeePeriod</class>
[/code]

Executable Application

JPAImpl.java

[code lang=”java”]
package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Begin a Transaction
em.getTransaction().begin();
createEmployee();
// Commit
em.getTransaction().commit();
}

public static void createEmployee(){
// Create an address entity
Address address = new Address();
address.setAddressId(2);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Employee employee = new Employee();
employee.setEmployeeId(2);
employee.setEmployeeName("John Smith");

// Create an Employee Period Instance
EmployeePeriod period = new EmployeePeriod();
period.setStartDate(new Date());
period.setEndDate(new Date());

employee.setEmployeePeriod(period);

// Associate the address with the employee
employee.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
firstPhone.setPhoneId(3);
firstPhone.setPhoneNumber("+221 4050 615");
firstPhone.setEmployee(employee);
// Create a new phone entity
Phone secondPhone = new Phone();
secondPhone.setPhoneId(4);
secondPhone.setPhoneNumber("+221 4050 619");
// Use the old employee entity
secondPhone.setEmployee(employee);
// Create a list of phone
List<Phone> phones = new ArrayList<Phone>();
phones.add(firstPhone);
phones.add(secondPhone);

// Create a list of projects
List<Project> projects = new ArrayList<Project>();

// Set the project into employee
employee.setProjects(projects);
// Set the phones into your employee
employee.setPhones(phones);

// Persist the employee

em.persist(employee);
}

}
[/code]

  • If the Embeddable class (Type) is used within an Employee, so no overrides required on the mapping information that provided by the EmployeePeriod properties. But in case you’ve needed to use the EmployeePeriod in an entities rather Employee and these entities reference a different column names, so you should use an @OverrideAttributes annotation.
  • Let’s assume that we’ve considered a columns that differ from the mapping information that’s provided in the EmplyeePeriod Embeddable class (type), in that you have to consider the @OverrideAttributes change the take place inside Employee entity. See the following snippet of code.

[code lang=”java”]
@Embedded
@AttributesOverride({
@AttributeOverride(name="startDate",column=@Column(name="EMP_START")),
@AttributeOverride(name="endDate",column=@Column(name="EMP_END"))
})
private EmployeePeriod employeePeriod; // employeePeriod property
[/code]

@EmbeddedId

  • The EmbeddedId isn’t vary differs as a concept from the previous concepts that discussed before about Embedded and Embeddable, except it is covering a composite primary key point.
  • The EmbeddedId annotation is applied to a persistent field or property of an entity class or mapped superclass to denote a composite primary key that is an embeddable class.
  • Let’s assume that we’ve a new Embeddable class (Type) named (AddressPK), that’s should determine the primary key of the Address entity.(See previous examples that depict the Address entity by referring the eclipselink jpa tutorial).

AddressPK.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class AddressPK implements Serializable{
@Column(name="AddressCountryId")
private int addressCountryId;
@Column(name="AddressCityId")
private int addressCityId;
@Column(name="AddressId")
private int addressId;
public int getAddressCountryId() {
return addressCountryId;
}
public void setAddressCountryId(int addressCountryId) {
this.addressCountryId = addressCountryId;
}
public int getAddressCityId() {
return addressCityId;
}
public void setAddressCityId(int addressCityId) {
this.addressCityId = addressCityId;
}
public int getAddressId() {
return addressId;
}
public void setAddressId(int addressId) {
this.addressId = addressId;
}

public boolean equals(Object obj){
if(obj instanceof AddressPK){
AddressPK addPK = (AddressPK) obj;
if(this.addressId == addPK.getAddressId() &&
this.addressCountryId == addPK.getAddressCountryId() &&
this.addressCityId == addPK.getAddressCityId()){
return true;
}
}
else {
return false;
}
return false;
}

public int hashCode(){
return super.hashCode();
}

}

[/code]

  • The AddressPK Embeddable class (Type) defines three properties and they are addressId, addressCountryId and addressCityId, so the Adress entities should be identified by the group of properties rather one addressId property.
  • When the developer uses the Embeddable class (Type) for primary key, he should override equals and hashCode(). The JPA itself doesn’t accept the Embeddable class if it was used as primary key unless it ensure that the two methods are overridden.
  • The AddressPK should implement the Serializable.
  • By using AddressPK, we have been using a new version of primary key that could depend on to identify the Address entities. But if you’ve reviewed the eclipselink jpa previous examples, you should be realized that the Employee entity related to the Address entity by OneToOne association. Let’s see the required changes that should take place once the primary key of the Address has been changed.

Employee.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="EmployeeType")
@DiscriminatorValue(value="EMP")
public class Employee {

@Id
private int employeeId;

@Basic(optional=false)
private String employeeName;

@Embedded
private EmployeePeriod employeePeriod;

@OneToMany(mappedBy="employee", cascade=CascadeType.ALL)
private List<Phone> phones;

@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(
joinColumns={@JoinColumn(name="employeeId")},
inverseJoinColumns={@JoinColumn(table="project",name="projectId"),@JoinColumn(table="localproject",name="projectId"),@JoinColumn(table="globalproject",name="projectId")}
)
private List<Project> projects;

// Updated Mapping information that took a consideration for changing the Address’s primary key

@OneToOne(cascade=CascadeType.ALL)
@JoinColumns({
@JoinColumn(name="AddressId",referencedColumnName="AddressId"),
@JoinColumn(name="EmployeeAddressCountryId",referencedColumnName="AddressCountryId"),
@JoinColumn(name="EmployeeAddressCityId",referencedColumnName="AddressCityId")}
)
private Address address;

public Address getAddress() {
return address;
}

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

public int getEmployeeId() {
return employeeId;
}

public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}

public String getEmployeeName() {
return employeeName;
}

public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}

public List<Phone> getPhones() {
return phones;
}

public void setPhones(List<Phone> phones) {
this.phones = phones;
}

public List<Project> getProjects() {
return projects;
}

public void setProjects(List<Project> projects) {
this.projects = projects;
}

public EmployeePeriod getEmployeePeriod() {
return employeePeriod;
}

public void setEmployeePeriod(EmployeePeriod employeePeriod) {
this.employeePeriod = employeePeriod;
}

}

[/code]

  • The Employee defines a new mapping information cause the Address entity primary key has been changed.
  • The Employee references three columns at the Address Table. (In the next section, you could see the Employee Table is also has been changed by adding a new two columns).
  • The referencedColumnName isn’t mandatory when we are going to use the @JoinColumns.It does define the name of the column referenced by the foreign keys column defined in the Employee table. Employee Table has (AddressId, AddressCountryId, AddressCityId) as foreign keys.

Database Design

Figure 1.3 shows you the changes that made on the Employee and Address Table.

EmbeddedIdEmployeeTable

EmbeddedIdAddressTable

Figure 1.3

  • Address Table add a new two columns (AddressCountryId and AddressCityId).
  • Employee Table does reference the new columns that was added into Address Table.

Executable Application

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.AddressPK;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.EmployeePeriod;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}

public static void main(String [] args){
// Begin a Transaction
em.getTransaction().begin();
createEmployee();
// Commit
em.getTransaction().commit();
}

public static void createEmployee(){
// Create an address entity
Address address = new Address();

// Address Embeddable class (Type) instantiation
AddressPK addressPK = new AddressPK();
addressPK.setAddressId(1);
addressPK.setAddressCountryId(1);
addressPK.setAddressCityId(1);
address.setAddressId(addressPK);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Employee employee = new Employee();
employee.setEmployeeId(2);
employee.setEmployeeName("John Smith");

// Create an Employee Period Instance
EmployeePeriod period = new EmployeePeriod();
period.setStartDate(new Date());
period.setEndDate(new Date());

employee.setEmployeePeriod(period);

// Associate the address with the employee
employee.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
firstPhone.setPhoneId(3);
firstPhone.setPhoneNumber("+221 4050 615");
firstPhone.setEmployee(employee);
// Create a new phone entity
Phone secondPhone = new Phone();
secondPhone.setPhoneId(4);
secondPhone.setPhoneNumber("+221 4050 619");
// Use the old employee entity
secondPhone.setEmployee(employee);
// Create a list of phone
List<Phone> phones = new ArrayList<Phone>();
phones.add(firstPhone);
phones.add(secondPhone);

// Create a list of projects
List<Project> projects = new ArrayList<Project>();

// Set the project into employee
employee.setProjects(projects);
// Set the phones into your employee
employee.setPhones(phones);

// Persist the employee

em.persist(employee);
}

}

[/code]

Database Records That Are Persisted Using a New Primary Key

Figure 1.4 shows the results in of the executable application.

EmployeeRecords

AddressRecords

Summary

This tutorial experiment using of Embeddedable, Embedded and EmbeddedId annotations. In general the Embeddable annotation should define a new class (Type) that’s going to be persisted with the owning entity. The JPA implementation requires the developer to mention those properties that considered as an Embeddable class (Type). The EmbeddedId works at the same kind as the Embedded except the EmbeddedId defines an Embeddable primary key.

Filed Under: Java EE Tagged With: EclipseLink, JPA

Eclipselink / JPA – Abstract Entity And Non-Entity Classes In The Entity Inheritance

March 4, 2014 by Amr Mohammed Leave a Comment

When we’ve discussed the inheritance and mapped superclasses concepts in the previous tutorials, we are avoiding concepts that could confuse the readers or makes misunderstanding for them.

Most of the clarified examples didn’t provide an Abstract Entity as a target entities that can be managed by the entity manager. On the contrary an Abstract Entity was only used in the tutorial of mapped superclass (See MappedSuperclass tutorial) in that the mapped superclass provides its children capability to inherit both of persistent entity states and the mapping information that belongs to. However, this isn’t the only concept that we would to discuss at this tutorial, but also we are going to discuss a non-entity class lies at the middle of the inheritance hierarchy for managed entities.

These relations might cause a confusion if they were coming in the middle of explanation. In this tutorial concepts like Abstract Entity, non-Entity class and Entity class will be used intensively.

Managed Entity

A managed entity instance is an instance with a persistent identity that’s currently associated with a persistent context. Meaning of managed entity is the contrary of Detached Entity, detached entity instance is an instance with a persistent identity that’s not (or no longer) associated with the persistent context. It is the basic term often used with the persistence technologies.

When an entity is being managed ?

In a brief we can define that, an entity is being managed by entity manager when it’s persisted to the database via an EntityManager’s persist method, which must be invoked within an active transaction. Also Entity objects retrieved from the database by an entity manager are also in the managed state, and if a managed entity instance is modified within an active transaction the changes that’s happened at that instance will be persisted into database once the transaction has been committed. for more information follow this link EntityManager.

Abstract Entity

An abstract entity can be specified as an entity, an abstract entity differs from a concrete entity only in that it cannot be directly instantiated. An abstract entity is mapped as an entity and can be the target of the queries (which will operate over and/or retrieve of its concrete sub-classes).

By returning to previous inheritance examples that implemented before, and by changing the Project entity from a normal entity into Abstract Entity. See Figure 1.1 that shows you the classes design for the whole system that’s being implemented.

Note : The examples in this tutorials are continued from the previous tutorials. For the better understanding of whole code, please read the previous tutorials (EclipseLink Tutorials).

ClassesDesign

Figure 1.1

  • The Project class displayed in an italic form. UML Design shows a class name by using an italic form if it was an abstract.
  • The GlobalProject and LocalProject are classes inherit from Project abstract entity.
  • Project is an abstract class, so it cannot be instantiated anymore.
  • The database can contains two types of Project instances, one for GlobalProject and the second for LocalProject. So no way to have a managed entity instance of type Project and consequently, the Project instance couldn’t be used for query results.

Anatomy of Project Abstract Entities Inheritance Hierarchy

Project.java

[code lang=”java”]
package net.javabeat.eclipselink.data;

import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToMany;

@Entity(name="Project")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) // The same inheritance strategy that is used
public abstract class Project {
@Id
private int projectId;

private String projectName;

@ManyToMany(mappedBy="projects",cascade=CascadeType.ALL)
private List<Employee> employees;

public int getProjectId() {
return projectId;
}

public void setProjectId(int projectId) {
this.projectId = projectId;
}

public String getProjectName() {
return projectName;
}

public void setProjectName(String projectName) {
this.projectName = projectName;
}

public List<Employee> getEmployees() {
return employees;
}

public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
[/code]

GlobalProject.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.math.BigDecimal;

import javax.persistence.Entity;

@Entity
public class GlobalProject extends Project {
private String projectCountry;
private BigDecimal projectBudget;
public String getProjectCountry() {
return projectCountry;
}
public void setProjectCountry(String projectCountry) {
this.projectCountry = projectCountry;
}
public BigDecimal getProjectBudget() {
return projectBudget;
}
public void setProjectBudget(BigDecimal projectBudget) {
this.projectBudget = projectBudget;
}
}

[/code]

LocalProject.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import java.math.BigDecimal;

import javax.persistence.Entity;

@Entity
public class LocalProject extends Project {
private BigDecimal projectBudget;

public BigDecimal getProjectBudget() {
return projectBudget;
}

public void setProjectBudget(BigDecimal projectBudget) {
this.projectBudget = projectBudget;
}

}

[/code]

  • Although Project class is an abstract entity, but it contains an persistent entity states and mapping information.
  • The LocalPorject and GlobalProject are sub-classes from Project and they are inherit the persistent entity states and mapping information.
  • The strategy used for achieving the inheritance is Table Per Concrete Strategy.

Required Persistence Configuration

[code lang=”xml”]

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="EclipseLink-JPA-Installation" transaction-type="RESOURCE_LOCAL">
<class>net.javabeat.eclipselink.data.Employee</class>
<class>net.javabeat.eclipselink.data.Developer</class>
<class>net.javabeat.eclipselink.data.Address</class>
<class>net.javabeat.eclipselink.data.Phone</class>

<!– Project Inheritance Hierarchy Entities–>
<class>net.javabeat.eclipselink.data.Project</class>
<class>net.javabeat.eclipselink.data.GlobalProject</class>
<class>net.javabeat.eclipselink.data.LocalProject</class>

<!– End –>
<class>net.javabeat.eclipselink.data.License</class>
<class>net.javabeat.eclipselink.data.DriverLicense</class>
<class>net.javabeat.eclipselink.data.ICDLComputerLicense</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
</persistence>

[/code]

Executable Application

The following JPAImpl class should show you how can we achieve a persistent operation for Project inheritance hierarchy.

JPAImp.java

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}
public static void main(String [] args){
// Begin a Transaction
em.getTransaction().begin();
// Create Employee
createDeveloper();
// Commit
em.getTransaction().commit();

}</pre>
public static void createDeveloper(){
// Create an address entity
Address address = new Address();
address.setAddressId(1);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Developer developer = new Developer();
developer.setEmployeeId(1);
developer.setEmployeeName("John Smith");
developer.setTitle("Senior Java Developer");
// Associate the address with the employee
developer.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
firstPhone.setPhoneId(1);
firstPhone.setPhoneNumber("+221 4050 615");
firstPhone.setEmployee(developer);

// Create a list of phone
List<Phone> phones = new ArrayList<Phone>();
phones.add(firstPhone);

// Project is an abstract entity class, no way to instantiate it
// Project project = new Project(); // That’s getting compiler error

// Create a Global Project
GlobalProject globalProject = new GlobalProject();
globalProject.setProjectId(2);
globalProject.setProjectName("Global Project");
globalProject.setProjectCountry("Brazil");
globalProject.setProjectBudget(new BigDecimal(150000));

// Create a Local Project
LocalProject localProject = new LocalProject();
localProject.setProjectId(3);
localProject.setProjectName("Local Project");
localProject.setProjectBudget(new BigDecimal(50000));

// Create a list of projects
List<Project> projects = new ArrayList<Project>();

projects.add(globalProject);
projects.add(localProject);

// Set the project into employee
developer.setProjects(projects);
// Set the phones into your employee
developer.setPhones(phones);

// Persist the employee
em.persist(developer);

}

}

[/code]

Database Persisted Records

The Figure 1.2 shows you, that how the project abstract entity sub-classes are persisted at the database, although the Project itself isn’t persisted.

Project

GlobalProject

LocalProject

Figure 1.2

  • The Project abstract entity does provides a persistent entity states and mapping information and it’s capable of inherit them into its sub-classes.
  • No records has been persisted for project abstract entity into database, although the GlobalProject and localProject are inserted.
  • The Table Per Concrete Strategy provide separate table for every sub-class of Project.
  • In case, we are using Single Table Strategy or Joined Table, the project database will contains those common attributes that shared between Project and its sub-classes.

Non-Entity Inherit from Entity & Entity Inherit from Non-Entity

Let’s have the a new additional classes added to our classes design listed above, in that the Employee is a root of inheritance tree. A Developer is a direct sub-class for Employee. Meanwhile the Developer has two sub-classes (ContractDeveloper and FreelanceDeveloper).

Employee is an entity, but Developer isn’t, the Developer is a mapped superclass (Not managed at all). ContractDeveloper and FreelanceDeveloper are another entities.

Developer.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.MappedSuperclass;

// Developer extends Employee entity, but it’s annotated using @MappedSuperclass
@MappedSuperclass
public class Developer extends Employee{

private String title;

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

}

[/code]

ContractDeveloper.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue(value="CDEV")
public class ContractDeveloper extends Developer {

}

[/code]

FreelanceDeveloper.java

[code lang=”java”]

package net.javabeat.eclipselink.data;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue(value="FDEV")
public class FreelanceDeveloper extends Developer {

}

[/code]

  • You should add the ContractDeveloper and FreelanceDeveloper into above persistence.xml file.
  • The Developer is a mappedSuperclass, so it’s just a way to share the persistent entity states and mapping information that inherit them from the Employee plus those added inside it to its sub-classes.

Executable Application for persisting new Sub-classes

[code lang=”java”]

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.ContractDeveloper;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.FreelanceDeveloper;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.ICDLComputerLicense;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
static EntityManagerFactory factory = null;
static EntityManager em = null;
static {
factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
em = factory.createEntityManager();
}
public static void main(String [] args){
// Begin a Transaction
em.getTransaction().begin();
// Create Freelance Developer
createFreelanceDeveloper();
// create Contract Developer
createContractDeveloper();
// Commit
em.getTransaction().commit();

}

public static void createFreelanceDeveloper(){
// Create an address entity
Address address = new Address();
address.setAddressId(1);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Developer developer = new FreelanceDeveloper();
developer.setEmployeeId(1);
developer.setEmployeeName("John Smith");
developer.setTitle("Senior Java Developer");
// Associate the address with the employee
developer.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
firstPhone.setPhoneId(1);
firstPhone.setPhoneNumber("+221 4050 615");
firstPhone.setEmployee(developer);

// Create a list of phone
List<Phone> phones = new ArrayList<Phone>();
phones.add(firstPhone);

// Create a Global Project
GlobalProject globalProject = new GlobalProject();
globalProject.setProjectId(1);
globalProject.setProjectName("Global Project");
globalProject.setProjectCountry("Brazil");
globalProject.setProjectBudget(new BigDecimal(150000));

// Create a Local Project
LocalProject localProject = new LocalProject();
localProject.setProjectId(2);
localProject.setProjectName("Local Project");
localProject.setProjectBudget(new BigDecimal(50000));

// Create a list of projects
List<Project> projects = new ArrayList<Project>();

projects.add(globalProject);
projects.add(localProject);

// Set the project into employee
developer.setProjects(projects);
// Set the phones into your employee
developer.setPhones(phones);

// Persist the employee
em.persist(developer);

}

public static void createContractDeveloper(){
// Create an address entity
Address address = new Address();
address.setAddressId(2);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
// Create an employee entity
Developer developer = new ContractDeveloper();
developer.setEmployeeId(2);
developer.setEmployeeName("John Smith");
developer.setTitle("Senior Java Developer");
// Associate the address with the employee
developer.setAddress(address);
// Create a Phone entity
Phone firstPhone = new Phone();
firstPhone.setPhoneId(2);
firstPhone.setPhoneNumber("+221 4050 615");
firstPhone.setEmployee(developer);

// Create a list of phone
List<Phone> phones = new ArrayList<Phone>();
phones.add(firstPhone);

// Create a Global Project
GlobalProject globalProject = new GlobalProject();
globalProject.setProjectId(3);
globalProject.setProjectName("Global Project");
globalProject.setProjectCountry("Brazil");
globalProject.setProjectBudget(new BigDecimal(150000));

// Create a Local Project
LocalProject localProject = new LocalProject();
localProject.setProjectId(4);
localProject.setProjectName("Local Project");
localProject.setProjectBudget(new BigDecimal(50000));

// Create a list of projects
List<Project> projects = new ArrayList<Project>();

projects.add(globalProject);
projects.add(localProject);

// Set the project into employee
developer.setProjects(projects);
// Set the phones into your employee
developer.setPhones(phones);

// Persist the employee
em.persist(developer);

}

}

[/code]

  • If you’ve been trying to persist a Developer instance, you are almost getting an exception tells you that the Developer isn’t a known entity even it’s not an abstract.
  • The ContractDeveloper and FreelanceDeveloper is the only developer instances that could persisted.
  • The ContractorDeveloper and FreelanceDeveloper should provide their discriminator values.

Database Persisted Records

Figure 1.3 depicts you the records that inserted.

Employees

Figure 1.3

  • The Freelance and contractor developer has been inserted by using the persistent entity states which inherited from the Developer. However, the Developer mapped superclass by its turn inherit some persistent states and mapping information from the Employee.

What’s happened if we’ve created a Simple Developer class?

Let’s create a simple Developer class (i.e. not mapped superclass).

Developer.java

[code lang=”java”]

package net.javabeat.eclipselink.data;
public class Developer extends Employee{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

[/code]

  • The executable application mentioned above executes successfully.

Impact of using Entity and non-Entity on The Entity Manager for Querying

What’s heppened if you’ve used a sample query code like

[code lang=”java”]
em.createQuery("select d from Developer d"); // Developer non-entity
em.createQuery("select p from Project p"); // Project Entity
[/code]

  • The first query that used in the sample would be thrown an exception, cause the Developer isn’t an entity even if we’ve replaced the normal class to be mapped superclass. The Developer isn’t queryable and cannot be passed as an argument to EntityManager, also it couldn’t be a target of a persistent relationship.
  • The second query should executed successfully cause the Project is an entity, so it’s queryable and can be passed into EntityManager and it could be a target for persistent relationship.

Summary

What we should do if we have different type of classes in the same inheritance hierarchy? is JPA support that’s illusion between those entities and non-entities? This tutorial summarizes a different scenarios that could happen in the inheritance hierarchy, you’ve seen how can non-entity class inherit from an entity and vice versa. Also if you’ve decided to avoid the mapped superclass you are able to complete your inheritance hierarchy. Also, this tutorial gives you an examples of how we could differentiate between entity and non-entity once we are coming to make a query. The entity is queryable rather using of mappedsuper class or normal class.

Filed Under: Java EE Tagged With: EclipseLink, JPA

  • 1
  • 2
  • 3
  • Next Page »

Follow Us

  • Facebook
  • Pinterest

As a participant in the Amazon Services LLC Associates Program, this site may earn from qualifying purchases. We may also earn commissions on purchases from other retail websites.

JavaBeat

FEATURED TUTORIALS

Answered: Using Java to Convert Int to String

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Copyright © by JavaBeat · All rights reserved