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

Spring Data JPA Tutorial

April 24, 2014 by Amr Mohammed Leave a Comment

Persistence API (JPA) provides POJO (Plain Old Java Object) standard and object relational mapping (OR mapping) for data persistence among applications. Persistence, which deals with storing and retrieving of application data, can now be programmed with Java Persistence API starting from EJB 3.0 as a result of JSR 220. This API has borrowed many of the concepts and standards from leading persistence frameworks like Toplink (from Oracle) and Hibernate (from JBoss). One of the great benefits of JPA is that it is an independent API and can nicely integrate with JEE as well as J2SE applications.

The addition that is coming with Spring Data is the offering of sophisticated support for JPA by providing an easily defined Repository. Repository is the central part of abstraction for the Spring Data layer. This repository just takes the user defined repository and the type of the repository and generates the run time implementation. Developer need not write any implementation for the database operations.

Spring Data provides such a sophisticated type of abstraction, however, it also, provides you a standard mechanism to setup the EntityManagerFactory or to integrate with Spring Transaction and translate JPA-specific exceptions into Spring’s DataAccessException hierarchy.

Spring Data JPA module implements the Spring Data commons repository abstraction to ease the repository implementations even more, making a manual implementation of a repository obsolete in most cases.

Business Domain

We are using the Employee and Address entities for this tutorial. These entities are associated with a relation of @OneToOne. Take in to your consideration that the Spring Data – JPA is a layer acted on mostly low level layer that could be used for defining the entities and the relations between entities. If you are looking for more details about the complex relations, please read our previous tutorials EclipseLink – JPA.

Employee.java

[code lang=”java”]
package net.javabeat.springdata.jpa.data;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
public class Employee {
@Id
private Integer employeeId;
@Basic(optional=false)
private String employeeName;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="AddressId")
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Integer getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
}
[/code]

Address.java

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

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity(name="address")
public class Address {
@Id
private int 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 int getAddressId() {
return addressId;
}
public void setAddressId(int addressId) {
this.addressId = addressId;
}
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;
}
}
[/code]

Configure Spring Container

Spring Data JPA can be configured through either Declaratively or Programmatically. Declarative configuration requires defining a XML-based document, whereas the Programmatic configuration does involve defining Java Class annotated with those required Spring annotation. Configuration of Spring Container used the Spring container bootstrapping and the required user defined Repositories, Spring Beans, DataSources, TransactionManager, and different assets for Spring Container.

SpringContext.xml

[code lang=”xml”]
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

<!– For consider the using of annotations foe defining Spring Bean –>
<context:annotation-config />

<!– For defining Spring Bean –>
<context:component-scan base-package="net.javabeat.springdata.beans" />

<!– For bootstrapping the Spring Repository –>
<jpa:repositories base-package="net.javabeat.springdata.repo" />

<!– Necessary to get the entity manager injected into the factory bean –>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<!– Define EclipseLink JPA Vendor Adapter –>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="databasePlatform"
value="org.eclipse.persistence.platform.database.MySQLPlatform" />
<property name="generateDdl" value="false" />
<property name="showSql" value="true" />
</bean>

<!– Entity Manager Factory –>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SpringData"></property>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>

<!– Transaction Manager –>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<!– Enable Transactional Manner –>
<tx:annotation-driven transaction-manager="transactionManager" />

</beans>
[/code]

Spring Data Repository

When it comes for saving, updating, reading and deleting the entities from the store, you have to define a Repository for achieving that. So, the Repository that you are going for use for achieving CRUD operations is as follow.

If you look at the user defined repository below, it extend the CrudRepository which is the abstract layer for the CRUD operations. By extending this interface, your repository just need declare the required operations. The actual implementations will be done by the spring container at run time.

EmployeeRepository.java

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

import net.javabeat.springdata.jpa.data.Employee;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>{
public Employee findByEmployeeId(Integer id);
}
[/code]

  • For defining your Repository, you have to implement one of the pre defined repositories like CrudeRepository or PagingAndSortingRepository.
  • Annotate the repository using @Repository.

Injecting User Repository Into User Defined Bean

For accessing your repository, you have to define your Spring Bean and annotate the bean with @Component, after that you can inject your Repository through using of @Autowired.

RegistrationBean.java

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

import net.javabeat.springdata.repo.EmployeeRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class RegistrationBean {
@Autowired
private EmployeeRepository employeeReposigtory;

public RegistrationBean(){

}

public EmployeeRepository getEmployeeReposigtory() {
return employeeReposigtory;
}

public void setEmployeeReposigtory(EmployeeRepository employeeReposigtory) {
this.employeeReposigtory = employeeReposigtory;
}
}
[/code]

Run Spring Data JPA Example Application

Spring container can be obtained through different way, one of the most easy way for obtaining it is by using the ClassPathApplicationContext that accept the name of the XML based document that you’ve used for defining the different assets of Spring container. After that you have the ability to locate the bean that you’ve defined for injecting your repository within it. In fact, you have not created the implementation of the Repository, that’s created by the Spring Container. By calling the different operations of our Repository, you should be able to do all of the CRUD operations.

Executable.java

[code lang=”java”]
package net.javabeat.springdata.executable;
import net.javabeat.springdata.beans.RegistrationBean;
import net.javabeat.springdata.jpa.data.Address;
import net.javabeat.springdata.jpa.data.Employee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Executable {
public static void main(String [] args){
// Acquire Context
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("SpringContext.xml");
// Get RegistrationBean That Defined
RegistrationBean registrationBean = (RegistrationBean)context.getBean("registrationBean");
// Create Employee
Employee employee = new Employee();
employee.setEmployeeId(1);
employee.setEmployeeName("Susa Hurbert");
// Create Address
Address address = new Address();
address.setAddressId(1);
address.setAddressCountry("United Kingdom");
address.setAddressCity("London");
address.setEmployee(employee);
employee.setAddress(address);
// Persist Using EmployeeRepository
registrationBean.getEmployeeReposigtory().save(employee);
// Find By Employee Id
Employee emp = registrationBean.getEmployeeReposigtory().findByEmployeeId(1);
// Close context
context.close();
}
}
[/code]

Persisted Records

Once you’ve executed the Executable application that listed above, you are getting two records persisted inside the database, one for Employee and the second for Address.

Spring Data JPA Employee Record

Address Record

Maven Dependencies

As we’ve mentioned previously, that this tutorial is built on created maven project, so for adding the libraries for Spring Data, all what you have to do is by providing your pom.xml with the following dependencies:

pom.xml

[code lang=”xml”]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.javabeat.springdata</groupId>
<artifactId>SpringData-JPA</artifactId>
<version>1.0</version>
<packaging>jar</packaging>

<name>Spring Data</name>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<!– Querydsl dependencies –>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>2.8.0</version>
</dependency>
<!– SLF4J dependency –>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<!– Dependencies for Eclipse JPA Persistence API –>
<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>
<!– Spring Data Dependency –>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
<!– Dependency for MySql Java connector –>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>

</dependencies>

</project>
[/code]

Inquiry By Method Declaration

If you’ve defined method inside you repository such as findByEmployeeId, without any implementation. Spring Data is capable of determining the proper query and implementation for your defined method. Look at the new form of EmployeeRepository.java.

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

import net.javabeat.springdata.jpa.data.Employee;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer>{
public Employee findByEmployeeId(Integer id);
}
[/code]

  • EmployeeRepository is capable of providing the basic CRUD.
  • EmployeeRepsotiory  has provided a newly added method named findByEmployeeId. Note that the Employee entity does provide attribute named EmployeeId.
  • Spring Data is capable of providing the created proxy from your repository the proper implementation.

Inquiry Result

If you’ve executed the following snippet of code at the Executable application, you’ve probably got a reference of Employee entity by calling the method findByEmployeeId.

Spring Data Employee Entity

  • The method had called didn’t provide any segment of code.
  • Spring Data has determined the proper Query that must be executed based on the name of the defined method.

Summary

Spring Data is one of the latest technology that provided recently from SpringSource. Spring Data provides a high level of abstraction that used for implementing full-fledged application. By using of Spring Data, no need for writing a code of CRUD operations, just you have to define your own Repository with/without your custom inquiry for achieving the required operations.

[wpdm_file id=79]

Filed Under: Spring Framework Tagged With: JPA, Spring Data, Spring Data JPA

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

JPA Annotations – @Temporal

March 6, 2014 by Krishna Srinivasan Leave a Comment

@Temporal annotation in JPA implementation can only be used with the fields and property get methods. Also, this annotation can be specified for the persistent fields or properties java.util.Data or java.util.Calendar. This annotation is available since the release of JPA 1.0. @Temporal solves the one of the major issue of converting the date and time values from Java object to compatible database type and retrieving back to the application. When Java class declares the fields java.sql.Date or java.sql.Time, then it is compatible with the database types and will not have any issues. But, when we are using the java.util.Date or java.util.Calendar, then we have to specify Temporal types to map the appropriate database types when persisting to the database.

@Temporal Syntax

It can be declared with the following syntax,

[code lang=”java”]
@Temporal(value)</span>
[/code]

The valid values are,

  • TemporalType.DATE
  • TemporalType.TIME
  • TemporalType.TIMESTAMP

@Temporal Example

For example,

[code lang=”java”]
@Temporal(TemporalType.DATE)
@Column(name = "DATE_COL")
private java.util.Date dateCol;
[/code]

The corresponding XML declaration is:

[code]
<entity class="Country">
<attributes>
<basic name="submitDate">
<temporal>DATE</temporal>
</basic>
</attributes>
</entity>
[/code]

It is equivalent of

  • DATE – equivalent of java.sql.Date
  • TIME – equivalent of java.sql.Time
  • TIMESTAMP – equivalent of java.sql.Timestamp

Filed Under: Java EE Tagged With: JPA, JPA 2 Tutorials

  • 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