When we work with Java web development, we have to implement with database. Normally, we will use JDBC or JDBC template for doing this problem. But to make it easier, we will use the new technology called ORM - Object Relational Mapping. The standard version of ORM is JPA. JPA will help us to map POJO to each record in table of database. We will do not take care all queries to access database. This action will be sent to the JPA.
So, in this article, we will talk about how to configure an entity class with JPA in Spring Boot, specially these are annotations in JPA.
Table of contents
- Introduction to JPA
- JPA Providers
- JPA Entity class
- Data types of Persistent Fields and Persistent Properties
- Persistent Fields
- Persistent Properties
- Relationship Mappings
- Direction in Entity relationships
- Cascade Opeartions and Relationships
- Orphan Removal in relationships
- Embeddable Classes in Entity
- Wrapping up
Introduction to JPA
JPA - Java Persistence API is the Java standard for mapping Java objects to a relational database. Mapping Java objects to database tables and vice versa is called Object-relational mapping (ORM). The Java Persistence API (JPA) is one possible approach to ORM. Via JPA, the developer can map, store, update and retrieve data from relational databases to Java objects and vice versa. JPA can be used in Java-EE and Java-SE applications.
JPA defines only specifications, it does not provide an implementation.
JPA implementation is provided as a reference implementation by the vendors developing O/R Mapper such as Hibernate, EclipseLink and Apache OpenJPA.
JPA permits the developer to work directly with objects rather than with SQL statements. The JPA implementation is typically called persistence provider
.
JPA Providers
JPA is an open source API, therefore various enterprise vendors such as Oracle, Redhat, Eclipse, etc. provide new products by adding the JPA persistence flavor in them.
Some of these products include:
- Hibernate
- EclipseLink
- TopLink
- Spring Data JPA
- …
JPA Entity class
A JPA Entity class is a POJO (Plain Old Java Object) class that is annotated as having the ability to represent objects in the database.
To be able to store Person
objects in the database using JPA, we need to define an entity classs.
The below is source code for JPA entity class.
@Entity
@Table(name = "PERSONS")
@Data
public class Person {
@Id
@Column(name = "NAME")
private String name;
@Size(max = 50)
@Column(name = "EMAIL")
private String email;
@Size(max = 12)
@Column(name = "PHONE")
private String phone;
@Id
@Size(max = 200)
@Column(name = "ADDRESS")
private String address;
public Person(String name, String email, String phone, String address) {
this.name = name;
this.email = email;
this.phone = phone;
this.address = address;
}
}
With the above code, an entity is an ordinary Java class. But this Person class has @Entity
annotation, which marks the class as an entity class.
Some rules of requirements to create a JPA entity class:
-
The class must be annotated with the
javax.persistence.Entity
annotation. -
The class must have a public or protected, no-argument constructor. The class may have other constructors.
-
The class must not be declared
final
. No methods or persistent instance variables must be declaredfinal
. -
If an entity instance is passed by value as a detached object, such as through a session bean’s remote business interface, the class must implement the
Serializable
interface. -
Entities may extend both entity and non-entity classes, and non-entity classes may extend entity classes.
-
Persistent instance variables must be declared private, protected, or package-private and can be accessed directly only by the entity class’s methods. Clients must access the entity’s state through accessor or business methods.
Data types of Persistent Fields and Persistent Properties
- Java primitive types
java.lang.String
- Other serializable types including
- Wrapper of Java primitive types
java.math.BigInteger
java.math.BigDecimal
java.util.Date
java.util.Calendar
java.sql.Date
java.sql.Time
java.sql.TimeStamp
- User-defined serializable types
- byte[]
- Byte[]
- char[]
- Character[]
- Enumerated types
- Other entities and/or collections of entities
java.util.Collection
java.util.Set
java.util.List
java.util.Map
- Embeddable classes
Entities may use persistent fields
, persistent properties
, or a combination of both.
If the mapping annotations are applied to the entity’s instance variables, the entity uses persistent fields
.
If the mapping annotations are applied to the entity’s getter methods
for JavaBeans-style properties, the entity uses persistent properties
.
For collection-valued persistent fields and properties:
-
If a field or property of an entity consists of a collection of basic types or embeddable classes, use the
javax.persistence.ElementCollection
annotation on the field or property. -
@ElementCollection
has two attributes:targetClass
andfetch
.- The
targetClass
attribute specifies the class name of the basic or embeddable class, and is optional if the field or property is defined using Java programming language generics. - The optional
fetch
attribute is used to specify whether the collection should be retrieve or eagerly, using thejavax.persistence.FetchType
constants or eithLAZY
orEAGER
, respectively. Be default, the collection will be fetched lazily.
- The
@Entity
public class Person {
...
@ElementCollection(fetch = EAGER)
protected Set<String> nickname = new HashSet();
...
}
Persistent Fields
- We have a field in the class. This can be
public
,protected
,private
or package access but cannot be static or final. - The field Java type defines whether it is, by default, persitable.
- If the entity class uses persistent fields, the Persistent runtime accesses entity class instance variables directly.
-
All fields not annotated
javax.persistence.Transient
or not marked as Javatransient
, will be persisted to the data store.@Entity public class Student { @Basic Date birthday @Transient String otherFields; }
So, the field
birthday
is considered as persistent, whereas fieldotherFields
is not persisted.
Persistent Properties
-
Getter/Setter methods is considered as
properties
. In this situation, we want to persist the output fromgetXXX
to the database, and use thesetXXX
to load up the value into the object when extracting it from the database. -
We have a property in the class with Java Bean getter/setter methods. These methods can be
public
,protected
,private
or package access, but cannot bestatic
. The class must have BOTHgetter
ANDsetter
methods.@Entity public class Student { @Basic public Date getBirthday() { ... } public void setBirthday(Date date) { ... } }
Using some annotations, we have marked this class as persistent, and the getter method is marked as persistent. By default, a property is non-persistent, so we have no need in specifying the
otherFields
as transisent. -
If the property is a boolean, we can use
isProperty
instead ofgetProperty
. -
The method signature for single -valued persistent properties are as follows:
Type getProperty(); void setProperty(Type type);
-
The object/relational mapping annotations for persistent properties must be applied to the getter methods.
Primary Key in Entity class
Every entity has a unique object identifier. The unique identifier, or primary key, enables clients to locate a particular entity instance. Every entity must have a primary key. An entity may have either a simple or a composite primary key.
Use javax.persistence.Id
annotation to denote the primary key property or field.
Composite primary key are used when a primary key consists of more than one attribute, which corresponds to a set of single persistent properties or fields.
Composite primary keys must be defined in a primary key class. Composite primary keys are denoted using the javax.persistence.EmbeddedId
and javax.persistence.IdClass
annotations.
Some data types of primary key:
- Java primitive types
- Java primitive wrapper classes
java.lang.String
java.util.Date
(the temporal type should be DATE)java.sql.Date
java.math.BigDecimal
java.math.BigInteger
Floating point types should never used in primary keys.
Some requirements for primary key:
- The access control modifier of the class must be
public
. - The properties of the primary key class must be
public
orprotected
if property-based access is used. - The class must have a public default constructor.
- The class must implement the
hashCode()
andequals(Object other)
methods. - The class must be serializable.
- A composite primary key msut be represented and mapped to multiple fields or properties of the entity class, or must be represented and mapped as an embeddable class.
- If the class is mapped to multiple fields or properties of the entity class, the names and types of the primary key fields or properties in the many key class must match those of the entity class.
Relationship Mappings
There are four types of multiplicities: one-to-one
, one-to-many
, many-to-one
, and many-to-many
.
-
One-to-one
Each entity instance is related to a single instance of another entity. For example, to model a physical warehouse in which each storage bin contains a single widget, StorageBin and Widget would have a one-to-one relationship.
One-to-one relationships use the
javax.persistence.OneToOne
annotation on the corresponding persistent property or field. -
One-to-many
An entity instance can be related to multiple instance.
A sales order, for example, can have multiple line items. In the order application, Order would have a one-to-many relationship with LineItem.
One-to-many relationships
use the javax.persistence.OneToMany
annotation on the corresponding persistent property or field. -
Many-to-One
Multiple instances of an entity can be related to a single instance of the other entity. This multiplicity is the opposite of a one-to-many relationship.
In the example, from the perspective of LineItem, the relationship to Order is many-to-one.
Many-to-one relationships use the
javax.persistence.ManyToOne
annotation on the corresponding persistent property or field. -
Many-to-Many
The entity instances can be related to multiple instances of each other.
For example, in college, each course has many students, and every student may take several courses. Therefore, in an enrollment application, Course and Student would have a many-to-many relationship.
Many-to-many relationships use the
javax.persistence.ManyToMany
annotation on the corresponding persistent property or field.
Direction in Entity relationships
There are two directions of a relationship, bidirectional and unidirectional.
- A bidirectional relationship has both an owning side and inverse side.
- A unidirectional relationship has only an owning side. The owning side of a relationship determines how the Persistent runtime makes updates to the relationship in the database.
-
Bidirectional
Each entity has a relationship field or property that refers to the other entity. Through the relationship field or property, and entity class’s code can access its related object. If an entity has a related field, then the entity is said to know about its related object.
For example, if Order know what LineItem instances it has and if LineItem knows what Order it belongs to, then they have a bidirectional relationship.
Bidirectional relationships must follow these rules:
-
The inverse side of a bidirectional relationship must refer to its owning side by using the
mappedBy
element of the@OneToOne
,@OneToMany
, or@ManyToMany
annotation. ThemappedBy
element designates the property or field in the entity that is the owner of the relationship, it means that themappedBy
attribute contains the name of the association-field on the owning side. -
The owning side has to have the
inversedBy
attribute of the@OneToOne
,@ManyToOne
, or@ManyToMany
mapping declarations. TheinversedBy
attribute contains the name of the association-field on the inverse-side. -
@ManyToOne
is always the owning side of a bidirectional association. -
@OneToMany
is always the inverse side of a bidirectional association. -
The owning side of a
@OneToOne
association is the entity with the table containing the foreign key. -
The many side of many-to-one bidirectional relationships must not define the
mappedBy
element. The many side is always the owning side of the relationship. -
For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key.
-
For many-to-many bidirectional relationships, either side may be the owning side. So, we can pick the owning side of a many-to-many association ourself.
-
For example:
Assuming that we have two objects that are employee and company. A company that has many employees, but one employee is only worked in one company. So, in employee table, it has id of company.
So, we have our source code about this problem.
-
In the owning side, we have:
@Entity @Table(name = "EMPLOYEE") @Data public class Employee { @Id @Column(name = "ID") private int id; @Column(name = "EMPLOYEE_ID") private int employeeId; @Column(name = "NAME") private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "EMPLOYEE_ID", referencedColumnName = "ID") private Company company; }
-
In the inverse side, we have:
@Entity @Table(name = "COMPANY") @Data public class Company { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID") private int id; @Column(name = "NAME") private String name; @Column(name = "ADDRESS") private String address; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "company") private Collection<Employee> employees; }
–>
mappedBy
is the name of association-mapping attribute on the owning side. With this, we have now established a bidirectional association between Employee and Company entities.
The @JoinColumn
annotation defines the actual physical mapping on the owning side.
FetchType.LAZY
indicates that the entity will be fetched on demand. For example, we could query the database for an Employee object. The company object associated will not be fetched until we call Employee.getCompany();
.
-
Unidirectional
Only one entity has a relationship field or property that refers to the other.
For example, LineItem would have a relationship field that identifies Product, but Product would not have a relationship field or property for LineItem. In other words, LineItem knows about Product, but Product doesn’t know which LineItem instances refer to it.
Cascade Opeartions and Relationships
Entities that use relationships often have dependencies on the existence of the other entity in the relationship.
For example, a line item is part of an order, and if the order is deleted, then the line item should also be deleted. This is called a cascade delete relationship.
The javax.persistence.CascadeType
enumerated type defines the cascade operations that are applied in the cascade element of the relationship annotations.
Cascade Operation | Description |
---|---|
ALL | All cascade operations will be applied to the parent entity’s relatd entity. All is equivalent to specifying cascade = {DETACH, MERGE, PERSIST, REFRESH, REMOVE} . |
DETACH | if the parent entity is detached from the persistence context, the related entity will also detached. |
MERGE | if the parent entity is merged into the persistence context, the related entity will also be merged. |
PERSIST | If the parent entity is persisted into the persistence context, the related entity will also be persisted. |
REFRESH | If the parent entity is refreshed in the current persistence context, the related entity will also be refreshed. |
REMOVE | If the parent entity is removed from the current persistence context, the related entity will also be removed. |
Orphan Removal in relationships
When a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered orphans and the orphanRemoval
attribute can be used to specify that orphaned entities should be removed. For example, if an order has many line items, and one of the line items is removed from the order, the removed line item is considered an orphan. If orphanRemoval
is set to true, the line item entity will be deleted when the line item is removed from the order.
The orphanRemoval
attribute in @OneToMany
and @oneToOne
takes a boolean value, and is by default false
.
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() {
...
}
Embeddable Classes in Entity
Embeddable classes are used to represent the state of an entity, but don’t have a persistent identity of their own, unlike entity classes. Instances of an embedded class share the identity of the entity that owns it.
Embeddable classes only exist as the state of another entity. An entity may have single valued or collection-valued embeddable class attributes.
For example:
@Embeddable
public class ZipCode {}
String zip; String plusHour();
}
@Entity
public class Address {
@Id
protected int id;
String street1;
String street2;
String city
String pronices;
@Embeded
ZipCode z
...
}
Entities that own embeddable classes as part of their persistent state may annotate the field or property with the javax.persitence.Embedded
annotation, but are not required to do so.
Embeddable classes may themselves use other embeddable classes to represent their state. They may also contain collections of basic Java programming language types, or other embeddable classes. Embeddable classes may also contain relationships to other entities or collections of entities. If the embeddable class has such a relationship, the relationship is from the target entity or collection of entities to the entity that owns the embeddable class.
Wrapping up
- JPA can not persist
static
orfinal
fields.
Refer:
https://www.oracle.com/technetwork/middleware/ias/toplink-jpa-annotations-096251.html
http://www.javaguides.net/2019/01/introduction-to-java-persistence-api.html
http://www.javaguides.net/2018/11/guide-to-jpa-and-hibernate-cascade-types.html
https://docs.oracle.com/cd/E19226-01/820-7627/bnbqc/index.html