JPA for Enterprise(JPA with example) and ORM

Java Persitance API vs ORM-


Any enterprise application performs database operation for storing and retrieving data. Developers either use lot of code (i.e plain JDBC call) or any kind of framework to perform this task, which is very cost effective and not efficient. JPA address this issue, it forms a bridge between Object Model(java program) and relational model(database program).

JPA is a source to store business entities as relational entities.

EntityManagerFactory: It’s a factory of EntityManager, it create and manage multiple EntityManager instances.

EntityManagerFactory factory = Persistence.createEntityManagerFactory("nameOfPersitenceFromXml");

EntityManager: It represents the connection to database. It is an interface, manages the persistence on an object. It also works like a factory for Query Instances.

EntityManager manager = factory.createEntityManager();

EntityTransaction: It modify the database content. It has one-to-one relationship for entitymanager, for each entitymanger operations are maintained by entitytransaction class.

EntityTransaction transaction = manager.getTransaction();
Query:It is an interface, it obtain relational object that meets the criteria.
Query query = manager.createQuery("select count(t) from employee p");
int count = query.getFirstResult();//query.getSingleResult();

TypedQuery: It is an sub interface of Query interface, introduced in JPA 2, and it’s used for typed safe.


TypedQuery<Employee> query = manager.createQuery("select *From employee");


List<Employee> empList = query.getResultList();

Persistence: This class contains static methods, to obtain entitymanagerfactory instance.


EntityManagerFactory factory = Persistence.createManagerFactory("persistenceUnitNameFromXml");
The above classes and interfaces are used for storing entities into database as record, this helps programmer in reducing database code and focusing on service layer and mapping of entity classes…

ORM: It is a programming ability to convert data from object type to relational type and vice versa.

The main feature of ORM is mapping/binding of data to a database, while conversion one must consider a data, datatype, relationship of data and entities/sub entities.

First phase has pojo’s, service layer, dao layer…

Second phase has Object Grid, JPA Loader, ORM.xml file, JPA provider

Third phase has Relational database.

Object Grid: It is cache memory(temporary location) which stores a copy of relational data. Whenever we perform any transaction through code, before commit, data will be stored in Object Grid, once we perform commit it will be stored in the database.

JPA Provider: It’s a flavour of JPA(javax.persistence), which comes with a predefined set of classes and interfaces like (EntityManagerFactory, EntiryManger, Entity, Query & Persistence).

ORM.xml : it’s an xml file, which doesn’t require any compilation. It contains mapping configuration between data in a pojo class and data in relational database.

JPA Loader :Used for loading a relational data grid.

The mechanism of the programatic interaction between above three phase is call as ORM (Object Relational Mapping).

Note: As mapping file has to compared with POJO properties, which can be replaced with Annotations(‘@’).

‘@Entity used to define a POJO class as entity class(table), also call as Persistable User defined class.

@Basic is used to make a field to be persisted, it is available by default

‘@Embedable used to declare a class as embedable class, which is a part of another entity class. Embedable classes can’t be used as Entity class.

‘@Embeded used to call embadable class, this will be returned as a filed in entity class.

‘@EmbededId used to call other class field .

‘@AttributeOverrides(name={@AttributeOverride(name=”columnName”, ‘@column=(name=”new columnname”)}); //this is used for overriding existing column with new name, it is used in combination with ‘@Embeded annotation.

‘@ElementCollection is used for collection type fields, when collection of data is needed. It will not store in same entity class, instead of that it will create separate table and store records in that. It will add primary key in new created table. It will create primaryKey column , by taking entity classname_pk.


Input in entity class.

@ElementCollection

private Set<Address> listOfAddress = new HashSet<Address>();

Output

CREATE TABLE Person_LISTOFADDRESS (`city` VARCHAR(255), `state` VARCHAR(255), `street` VARCHAR(255), `zip` VARCHAR(255), Person_ID INTEGER)

ALTER TABLE Person_LISTOFADDRESS ADD CONSTRAINT FK_Person_LISTOFADDRESS_Person_ID FOREIGN KEY (Person_ID) REFERENCES dbhybrid_transcription.person (ID)

INSERT INTO dbhybrid_transcription.person (`name`) VALUES (?)

INSERT INTO Person_LISTOFADDRESS (Person_ID, `city`, `state`, `street`, `zip`) VALUES (?, ?, ?, ?, ?)

INSERT INTO Person_LISTOFADDRESS (Person_ID, `city`, `state`, `street`, `zip`) VALUES (?, ?, ?, ?, ?)

@JoinTable in the above example, using @ElementCollection is creating a new table, with field name marked with @Elementcollection. In order to give proper name to the table, we use @JoinTabel(name=’table_name’)

@JoinColmn in the above example, we are getting default column in new table w.r.t collectionField with default column like EntityClass_PrimaryKey column, to control on default column name create, we have


@JoinTable(joinColumns=@JoinColumn(name='user_id'))

@Transient It makes a filed as Transient.(read below note for more details).

@Version is used for maintaining a version on entity manually. This is marked on field type.

‘@Join

‘@Table used to define a table name

‘@Id use to define afield as primary key.

‘@Column use to define a field as column name.

‘@GeneratedValue is use to auto-generate value for primary key, this can be done in several ways.

1)GenerationType=’AUTO’ it will pick the random number and add it to primary key.


@Id

@GeneratedValue(strategy=GenerationType.AUTO)

@Column(name="id")


private int empId;

2)GenerationType=’Sequence’ it has two parts, part one is @GeneratedValue is used for declaring sequence, and part two is used for using declared sequence.


@SequenceGenerator(name="someName" sequence="actualSequenceName")


@GeneratedValue(strategy=GenerationType.SEQUENCE name="someName")

‘@Temporal used to store DATE/TIMESTAMP/TIME in database table.

‘@OneToMany/ManyToOne(Multi value association) defines one-to-many relationship between join tables.

‘@OneToOne(Single value association) defines one-to-one relationship between join tables.

‘@ManyToMany defines many-to-many relationship between join tables.

@NamedQuery: used to add a static query on entity class,

OneToOne annotation: consider class A has reference to class B, and class B has no reference to class A, such scenario’s are call as OneToOne Unidirectional.

Consider A has reference to B, and B has reference to A, then it is call as OneToOne Bidirectional.

OneToOne Unidirectional example.


public class Employee {
@Id
private String empId;

private String empDesig, empProject, empReporting;

@OneToOne(cascade=CascadeType.ALL)

@JoinColumn(name="employeeId")

private EmployeeDetail empDetail;




//getters and setters.

}



public class EmployeeDetail{

@Entity

@Table(name = "employee_detail")

public class EmployeeDetail implements Serializable{

private static final long serialVersionUID = 1L;

private String empId, empFirstName, empLastName, empMiddleName, empAddress, empManager, empHired, empDOJ, empExpiry;

@Id

@Column(name="empId")

public String getEmpId() {

return empId;

}

//getters and setters

}


--------------


OneToOne Bidirectional example: mappedBy attribute is used for achieving Bidirectional with OneToOne mapping.

In this case, Employee class will not change, but EmployeeDetail class will get change.


@Entity(name="empDetail")

@Table(name = "employee_detail")

public class EmployeeDetail implements Serializable{

private static final long serialVersionUID = 1L;

@Id

@Column(name="empId")

private String empId;

private String empFirstName, empLastName, empMiddleName, empAddress, empManager, empHired, empDOJ, empExpiry;

public String getEmpId() {

return empId;

}

@OneToOne(cascade=CascadeType.ALL, mappedBy="empDetail")

private Employee employee;




‘@OneToMany/ ManyToOne : In this one entity class will have multiple references of another entity class, vice-versa.
Let’s add Phone number entity class, in this one Employee class will have multiple Phone number references.

Phone.java





@Entity

@Table(name="person", schema="xxxx")

@NamedQuery(name="findResult", query="select *from Person")

public class Person{

....

}
Main.java


TypedQuery<Person> query = manager.createNamedQuery("findResult",Person.class);

@NamedQueries we can add multiple named queries, on a single entity class.


@NamedQueries({


@NamedQuery(name="countResults", query="select count(*) from Persons), @NamedQuery(name="findList", query="select *from persons")})

@Inheritence(strategy=InheritenceType.SINGLE_TABLE)

@DiscriminatorColumn(name=”columName”, discriminatorType=DiscriminatorType.String);

Note:

User defined persistant class(Entity, Embedable & Mapped classes) can have following list of fields.

1)Transient Field : Doesn’t allow field to participate in persistent, and values are not stored in DB.

static, final, transient and ‘@Transient is used to make field as Transient.

2)Persistent Field: every non-static,non-final and non-tranisent fields are persistent by default.

Every Persistent Field can be marked with following annotation

@OneToOne , @OneToMany, @ManyToMany & @Basic.

3)Inverse(Mapped By) Field: It is used to retrieve entity from database, but this entry will not effect the database, it’s used for fetching data from database.


@Entity


public class Employee {


String name;


@ManyToOne Department department;


}




@Entity


public class Department {


@OneToMany(mappedBy="department") Set<Employee> employees;


}

tracing an inversion field is quite easy, just we need to follow, where mappedBy is used to specify the employee field is an inverse field, rather than persistence field.

4)Primary Fields: Every entity will have a unique primary key, which is represented by ‘@Id.

Composite Primary key: Collections of more than one primary key is call as composite primary key. It is defined by (‘@IdClass annotation).


@Entity @IdClass(ProjectId.class)


public class Project {


@Id int departmentId;


@Id long projectId;


......


}

================================

Class ProjectId {


int departmentId;


long projectId;


}

5)Version Fields: It’s a field which will be available by default as 1, every entity object has numeric version value as 1, for every entity transaction this version will be modified.

However last two fields could not be a part of Embeded & Mapped class, it will be a part of Entity Class.

Let’s work on one example.

Before that let’s learn about some basic methods in JPA

1)persist() //allows to store new entity object in database(it’s like saving data)

2)find(Employee.class,123(pk)); finds record with pk=123, returns null(not found)

3)getReference(Employee.class,123(pk)) like find(), but returns hollow object(not found)

4)createQuery() allows to write a custom query.


Query query = manager.createQuery("select count(t) from eployee_details t");


int count = query.getFirstResult();

5)remove(); In order to perform remove on manager, first we need to get managed object from database, and then perform remove()


//get managed object


Employee emp = manager.find(Employee.class,123);


transaction.begin(); //active transaction


manager.remove(emp);


transaction.commit();

6)update there is not direct method update, this is quite similar to remove(), the only difference is, we must update the entity object and perform commit().


transaction.begin();


emp.setDesignation("Testing Engineer"); //here it will be updated


transaction.commit();

7)contains(“classname”) to check, if entity exist in persistence declaration or not.

8)clear() clears all from managed entity.

9)

10)isLoaded(“employee”);

isLoaded(“employee”,”persistenceField”);


PersistenceUtil util = Persistence.getPersistenceUtil();


boolean isObjectLoaded = util.isLoaded(employee);


boolean isFieldLoaded = util.isLoaded(employee, "address");

It is used to check, the entity class is present in EntityManager. It has two methods first is to check entity- class, and second to check entity class + persistence field.


——————————————Example on JPA———————————————-

In order to start working on this , first we need to list jars needed.

Below is the list of dependencies, which you can include in pom.


<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->

<dependency>

<groupId>javax.persistence</groupId>

<artifactId>javax.persistence-api</artifactId>

<version>2.2</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.eclipse.persistence/javax.persistence -->

<dependency>

<groupId>org.eclipse.persistence</groupId>

<artifactId>javax.persistence</artifactId>

<version>2.1.0</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.eclipse.persistence/eclipselink -->

<dependency>

<groupId>org.eclipse.persistence</groupId>

<artifactId>eclipselink</artifactId>

<version>2.5.0</version>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.36</version>

</dependency>

Next is persistence.xml

This xml must be defined in META-INF folder.

It can have one more persitence-unit tags, each has name and propertery fields.

class elements specify the list of persistable classes.

property elements specify databases configuration details.


<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"

version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

<persistence-unit name="persistanceUnit" transaction-type="RESOURCE_LOCAL">

<class>main.pojo.Employee</class>

<properties>

<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>

<property name="javax.persistence.jdbc.url" value="abc"/>

<property name="javax.persistence.jdbc.user" value="abc"/>

<property name="javax.persistence.jdbc.password" value="abc"/>

<property name="eclipselink.ddl-generation" value="create-tables"/>

</properties>

</persistence-unit>

</persistence>


Entity class

package main.pojo;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.Table;

@Entity

@Table(name="employee_details", schema="dbhybrid_transcription")

public class Employee {

@Id

@Column(name="id")

private int empId;

@Column(name="\"emp_name\"")

private String empName;

@Column(name="\"emp_desig\"")

private String empDesig;

@Column(name="\"emp-sal\"")

private double empSal;

public Employee(){}

public Employee(int empId, String empName, String empDesig, double empSal) {

super();

this.empId = empId;

this.empName = empName;

this.empDesig = empDesig;

this.empSal = empSal;

}

public int getEmpId() {

return empId;

}

public void setEmpId(int empId) {

this.empId = empId;

}

public String getEmpName() {

return empName;

}

public void setEmpName(String empName) {

this.empName = empName;

}

public String getEmpDesig() {

return empDesig;

}

public void setEmpDesig(String empDesig) {

this.empDesig = empDesig;

}

public double getEmpSal() {

return empSal;

}

public void setEmpSal(double empSal) {

this.empSal = empSal;

}

}
MainClass.java

public static void main(String arg[]){

Employee employee = new Employee(124,"Muhammed Younus Attari","Software Engineer",123.4);

EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistanceUnit");

EntityManager manager = factory.createEntityManager();

EntityTransaction transaction = manager.getTransaction();

transaction.begin();

manager.persist(employee);

transaction.commit();

}
for more easy go, please clone above code from github.

Fetch data on primaryKey(id)


//find() will throw null-pointer-exception, if id not found in db


Employee emp = manager.find(Employee.class, 123);


System.out.println(emp.getEmpName()+"......"+emp.getEmpId()+"......."+emp.getEmpDesig()+"......"+emp.getEmpSal());

second way


//getReference() will throw entity not found exception,id not in db


Employee emp = manager.getReference(Employee.class,123);


System.out.println(emp.getEmpName()+"......"+emp.getEmpId()+"......."+emp.getEmpDesig()+"......"+emp.getEmpSal());

Storing JPA entity object in database

1)Explicit Persist

2)Referenced Embedded Objects

3)Referenced Entity Objects

4)Cascading Persist

5)Global Cascading Persist

6)Batch Store

Explicit Persist : It is quite simple, in this an entity object will be call as a parameter to persist method


//here just replace your main class code


manager.persist(employee);

Referenced Embedded Objects: In this Person instance is referenced as with address instance



Finally person table will have (id,name,city,state,zip,street) as columns.

Let’s write the code for this.


Person.java


package main.pojo;



import java.io.Serializable;



import javax.persistence.AttributeOverride;

import javax.persistence.AttributeOverrides;

import javax.persistence.Basic;

import javax.persistence.Column;

import javax.persistence.Embedded;

import javax.persistence.Entity;

import javax.persistence.FetchType;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;



@Entity

@Table(name = "person", schema = "db")

public class Person implements Serializable {



@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Integer id;



@Column(name = "\"name\"")

private String name;



@Embedded

private Address address;



public Integer getId() {

return id;

}



public void setId(Integer id) {

this.id = id;

}



public String getName() {

return name;

}



public void setName(String name) {

this.name = name;

}



public Address getAddress() {

return address;

}



public void setAddress(Address address) {

this.address = address;

}




}





Address.java



package main.pojo;



import java.io.Serializable;



import javax.persistence.Column;

import javax.persistence.Embeddable;

import javax.persistence.Id;



@Embeddable

public class Address implements Serializable {



@Column(name="\"street\"")

private String street;




@Column(name="\"city\"")

private String city;




@Column(name="\"zip\"")

private String zip;




@Column(name="\"state\"")

private String state;



public Address(){




}




public String getStreet() {

return street;

}



public void setStreet(String street) {

this.street = street;

}



public String getCity() {

return city;

}



public void setCity(String city) {

this.city = city;

}



public String getZip() {

return zip;

}



public void setZip(String zip) {

this.zip = zip;

}



public String getState() {

return state;

}



public void setState(String state) {

this.state = state;

}



}


Main.java


public static void main(String[] args) {

EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistenceUnit");

EntityManager manager = factory.createEntityManager();

EntityTransaction trans = manager.getTransaction();

Address address = new Address();

address.setCity("Hyd");

address.setState("TG");

address.setZip("123");

address.setStreet("XYZ");

Person person = new Person();

person.setAddress(address);

person.setId(12);

person.setName("Hello Hi");

trans.begin();

manager.persist(person);

trans.commit();

}


persistence.xml

above xml can be used here.
output


INSERT INTO dbhybrid_transcription.person (`name`, `city`, `state`, `street`, `zip`) VALUES (?, ?, ?, ?, ?)

3)Referenced Entity Objects: Consider above example, in which Both Person and Address are Entity classes, in this case when we perform operation on person class, it will throw IllegaleStateException, because here both entities are referenced with each other.

To avoid this confusion, we have CASCADING concept.

4)CASCADING allows to store two different entities sequentialy, even they are referenced with each other. It is used in combination of mappings(onetoone,onetomany and manytomany)

Below are different methods which will be call, on demand. Like persist(), merge(), detach() and respective cascading can be set on that.

CASCADING.ALL //cascades all operations

CASCADING.PERSIST //cascades persist operation

CASCADING.MERGE //cascade merge operation

CASCADING.DETACH //cascade detach operation

5)Global Cascading : can be applied, by setting cascading-default in persistence.xml


<persistence-unit-defaults>

<cascade-persist/>

</persistence-unit-defaults>
6)Batch Store: Inorder to store huge record of data, calling clear and flush method can save huge amount of memory.

em.getTransaction().begin();

for (int i = 1; i <= 1000000; i++) {

Point point = new Point(i, i);

em.persist(point);

if ((i % 10000) == 0) {

em.flush();

em.clear();

}

}

em.getTransaction().commit();
Retrieving JPA entity Objects: We don’t require entity transaction in case of retrieving an object from database, as retrieving doesn’t do any content change in database.

Persistence context served as a cache of retrieved entity, if the object is not found in context, then it will create a new object and store it context.

There are several ways to retrieve entity using JPA

1)Retrieval by Classname with Primary key

2)Retrieval by Eager Fetch

3)Retrieval by Navigation and access

4)Retrieval by Query

5)Retrieval by Refresh

6)Cascading by Refresh

Retrieval by class and primary key: In this approach, find or getReference method is used for accessing record’s from database.


Employee emp = manager.find(Employee.class, 123);


or


Employee emp = manager.getReference(Employee.class,123);

Note: difference between find and getReference is in above notes.

Retrieval by Eager Fetch : Consider one entity class is connected with other entity classes, fetching result of this type will take long time, because they are connected. To address this we have EAGER and LAZY loading concept.


@ElementCollection(fetch=FetchType.LAZY)


set<Address> listOfAddress=new HashSet<Address>();

or

@ElementCollection

@OneToMany(cascade=CascadeType.EAGER)

Set<Address> listOfAddress= new HashSet<Address>();

Above code is for lazy loading, in this a proxy user class is created and the fields are set on that. When we request getListOfAddress() then that time, a loading will be done. In case of eager loading, the call will be made directly, which impacts on memory, and time consumption. LAZY loading is a preferable way.

Retrieval by Query : There are two ways to form a query using JPA

Static //here query is added to the entity class, using @NamedQuery annotation

Dynamic //here queries are formed using EntityManager.

Static Query: adding a query to an Entity, by using @NamedQuery annotation.


@Entity


@Table(name = "person", schema = "dbhybrid_transcription")


@NamedQuery(name="getAllRecords", query="select c from Person c")


public class Person implements Serializable {

Dynamic Query are formed by using JPA-Criteria :

It helps to check the query formation, at compile time.

It is useful, when we have to build a dynamic query, example a form with multiple options, query need to build query dynamically like on selected fields from forms. Instead of adding lot of string concatenation, JPA does it easily.

JP-QL(Java Persistence Query Language) is an JPA specification, which is used for forming a Queries w.r.t Entities. It is used to store/retrieve data from database.

There are many approaches

1) calling find() or getReference() or getResultList() or getFirstResult()…

2) calling createQuery(“select p from persons p”) query directly.

3) calling createNamedQuery(“nameOfQuery”,Enity.class);

Difference between JPQL vs JPA-Criteria

JPQL queries are defined as String, similar to SQL.

JPA-Criteria queries are defined using entity objects, whose structure will be determined at run-time.

Errors are detected at run-time.

As Query is passed as string, whose error are detected at run-time.

For simple static queries, JPQL is preferred.

For dynamic , which are need to be build at runtime, Criteria-API preferred

JPA-Criteria API.

consider you have a simple query


select *From person;
this can be written using JPA-Criteria-API

CriteriaBuilder builder = manager.getCriteriaBuilder();

CriteriaQuery<Person> query = builder.createQuery(Person.class);

Root<Person> list = query.from(Person.class);

query.select(list);

Comments