Java Persistence Java API - hornad.fei.tuke.skporuban/wt/JPA.pdf · JavaTM Persistence Context...

Post on 23-Feb-2019

266 views 0 download

Transcript of Java Persistence Java API - hornad.fei.tuke.skporuban/wt/JPA.pdf · JavaTM Persistence Context...

JavaTM Java Persistence API

Jaroslav Porubän, Peter Václavík2008

JavaTM

What is an Entity?

Models real-world object Plain Old Java Object (POJO)

No required interfaces, superclasses Has a persistence identity May have both persistent and non-

persistent state Non-persistent state (transient or

@Transient) Can extend other entity and non-

entity classes

JavaTM

Persistence Context

Represents a set of managed entity instances at runtime “Entity instance is in managed state” means

it is contained in a persistent context Not directly accessible to an application

Managed by an entity manager When a persistence context is closed, all

managed entity objects become detached and are unmanaged

JavaTM

Persistence Context Configuration

Persistence context is defined in a persistence.xml file This file is a required deployment descriptor

for the Java Persistence specification A persistence.xml file can define

one or more persistence units Persistence unit is tied to one and only one

data source Specifies set of classes defining mapping to a

particular database

JavaTM

Persistence Context Configuration Example<persistence> <persistence-unit name="shop"> <jta-data-source>java:/ShopDB </jta-data-source>

<class>examples.shop.Customer</class><class>examples.shop.Product</class><properties>

<property name="hibernate.show_sql" value="true"/> </properties> </persistence-unit></persistence>

JavaTM

Entity Manager

Is the central service for all persistence actions

Performs life-cycle operations on entities

Manages the O/R mapping between a fixed set of entity classes and an underlying data source

You can use Java Persistence outside of an application server in plain Java SE programs

JavaTM

Entity Manager API

Creating queries Finding objects Synchronizing objects Inserting objects into the database Providing caching Managing the interaction between

an entity and transactional services in a Java EE environment such as JTA

JavaTM

Entity Manager Injection

An EntityManager can be injected directly into an EJB using the @PersistenceContext annotation

@Statelesspublic class MySessionBean implements

MySessionRemote { @PersistenceContext(unitName="shop") private EntityManager entityManager;

...}

JavaTM

Entity Life Cycle

JavaTM

Entity Manager APIpublic interface EntityManager { public void persist(Object entity); public <T> T find(Class <T> entityClass,

Object primaryKey); public <T> T getReference(Class <T> entityClass,

Object primaryKey); public <T> T merge(T entity); public void remove(Object entity); public void lock(Object entity,

LockModeType lockMode);

public void refresh(Object entity); public boolean contains(Object entity); public void clear( );

public void joinTransaction( ); public void flush( );...continues on next page

JavaTM

Entity Manager API... from previous page

public FlushModeType getFlushMode( ); public void setFlushMode(FlushModeType type);

public Query createQuery(String queryString); public Query createNamedQuery(String name); public Query createNativeQuery(String sqlString); public Query createNativeQuery(String sqlString,

String resultSetMapping); public Query createNativeQuery(String sqlString,

Class resultClass);

public Object getDelegate( );

public void close( ); public boolean isOpen( );}

JavaTM

Entity Manager: Entity Life Cycle Management

Similar in functionality to Hibernate Session, JDO PersistenceManager, etc.

Life cycle methods: persist() - insert an entity into the DB remove() - remove an entity from the DB merge() - synchronize the state of

detached entities refresh() - reloads state from the

database

JavaTM

Entity Manager: Other Entity Management Methods

Finding entities: find()

Queries: createQuery(), createNamedQuery(),

createNativeQuery() Synchronizing entities with database:

flush() Other methods:

contains(), clear()

JavaTM

Finding Entities Example

Method find()MyEntity e = entityManager.find(MyEntity.class,2);

JavaTM

Persisting Entities

Persisting entities that have not yet been created in the database Queues object for insertion into the database Insert may happen immediately

Depending on a flush mode

The object instance becomes managed If the entity has any relationships with

other entities, these entities may also be created within the database if you have the appropriate cascade policies

JavaTM

Persisting Entities ExampleEntityManager entityManager;...MyEntity e = new MyEntity();...entityManager.persist(e);

JavaTM

Removing Entities

The remove() operation does not immediately delete the entity from the database

After remove() is invoked, the removed object will no longer be managed If the entity has any relationships to

other entity objects, those may also be removed depending on the cascading rules

JavaTM

Removing Entities Exampleprivate EntityManager entityManager;...public void removeMethod(long id) { SomeEntity e = entityManager.find(SomeEntity.class,id); entityManager.remove(e);}

JavaTM

Merging Entities The merge() method merge state

changes made to a detached entity back into persistence storage

The merge() method returns a managed copy of the given detached entity

public MyEntity updateOrderLine(MyEntity e){ return entityManager.merge(e);}

JavaTM

Refreshing Entities

Managed entity will be up-to-date with the database

The refresh() method refreshes the state of the entity from the database Overwriting any changes made to that entity

If the entity bean has any related entities, those entities may also be refreshed, depending on the cascade policy

JavaTM

Refreshing Entities Examplepublic void someMethod(int id) { SomeClass obj = entityManager.find(SomeClass.class, id);

...

//The state of the entity from the database //overwriting any changes made to that //entity

entityManager.refresh(obj);}

JavaTM

Queries

Persistent objects can be located by using JPQL or native SQL

You must create a Query object by calling methods: createQuery() – dynamically

created EJB QL query createNamedQuery() – statically

created EJB QL query createNativeQuery() – native

SQL query

JavaTM

Named Query Example @NamedQuery(name = "findUser",

query = "SELECT c FROM Customer c WHERE c.login = :custName")

@Entitypublic class Customer {…}

public Customer getUser(String login) { Query q = manager.createNamedQuery("findUser"); q.setParameter("custName", login); return (Customer)q.getSingleResult(); }

JavaTM

Query Example String condition = "where id=2";...//You can modify condition ...Query query = entityManager.createQuery("from Customer c " + condition);

Customer cust = (Customer)query.getSingleResult();

JavaTM

Updating Entity Example

public void updateMethod(int id, int newVal) { SomeClass c = entityManager.find(SomeClass.class, id); c.setValue(newVal);}

JavaTM

Java Persistence Programming Model

Persistence is the process of coordinating the data represented by a bean instance with the database

Entity is a POJO (no need to implement Enterprise Entity Bean)

Java Persistence API can automatically map your Java objects to and from a relational database (ORM)

Using of annotation to denote a POJO as an entity (instead of deployment descriptor)

JavaTM

Java Persistence Programming Model Example

@Entity public class MyEntity { // Persistent/transient fields // Property accessor methods // "Persistence logic" methods}

JavaTM

Entity Example @Entity public class Customer { private long id; private Collection<Order> orders = new HashSet(); ...

@Id public long getID() { return id; } protected void setID(long id) { this.id = id; }

Annotated as entity

@Id denotes primary key

Getters/setters to access state

JavaTM

Entity Example ...

@OneToMany public Collection<Order> getOrders() { return orders; }

public void setOrders( Collection<Order> orders) { this.orders = orders; }

// Other persistence methods}

Relationship between Customer and Order

JavaTM

O/R Mapping

A developer can take two directions when implementing entity beans: Derive a database schema from a Java

object model Derive a Java object model from

existing database schema Specified using

Annotations within the code Separate mapping file

JavaTM

Simple Mapping

public class Customer { int id; String name; int c_rating; Image photo;}

@Entity(access=FIELD)

@Column(name=“CREDIT”)

@Id

@Lob

CUSTOMERID NAME CREDIT PHOTO

JavaTM

Primary Key Primary key is the identity of a given

entity bean Every entity bean must have a primary

key, and it must be unique Primary keys can map to one or more

properties Primary keys must map to one of the

following types: Any Java primitive type (including wrappers) java.lang.String Primary-key class composed of primitives

and/or strings

JavaTM

@Id Generating the primary key:

Manually Using persistence provider -

@GeneratedValue annotation @GeneratedValue annotation

GeneratorType.AUTO – default GeneratorType.TABLE GeneratorType.SEQUENCE

GeneratorType. IDENTITY

JavaTM

Property Mappings

@Transient @Basic @Temporal @Lob @Enumerated

JavaTM

@Transient Persistence manager would assume that

every nontransient property in your bean class is persistent

Properties annotated with @Transient annotation persistence manager ignores and doesn't treat it as persistent

JavaTM

@Basic It is the simplest form of mapping

for a persistent properties of primitives and primitive wrapper types

Attribute fetch() specify whether a particular property is loaded lazily or eagerly when the persistent object is first fetched from the database FetchType.LAZY FetchType.EAGER - default

JavaTM

@Basic@Entitypublic class Customer implements java.io.Serializable { ... @Basic(fetch=FetchType.LAZY,optional=false) public String getFirstName() { return firstName; } public void setFirstName(String firstName){ this.firstName = firstName; } ... }

JavaTM

@Temporal Provides additional information to the

persistence provider about the mapping of a java.util.Date or java.util.Calendar property It allows to map these object types to a

date, a time, or a timestamp field in the database

Temporal types: TemporalType.DATE TemporalType.TIME TemporalType.TIMESTAMP - Default

JavaTM

@Temporal@Entitypublic class Customer implements java.io.Serializable { private java.util.Date timeCreated; ...

@Temporal(TemporalType.TIME) public java.util.Date getTimeCreated( ) { return timeCreated; } public void setTimeCreated( java.util.Date time) { timeCreated = time; }}

JavaTM

@Lob If persistent properties require a lot of

memory, for example: Images - java.sql.Blob Large text documents - java.sql.Clob

It is usually used in conjunction with the @Basic annotation to hint that the property should be lazily loaded

Properties annotated with a @Lob: Blob if the Java type is byte[], Byte[], or

java.io.Serializable Clob if the Java type is char[],

Character[], or java.lang.String

JavaTM

@Lobimport com.acme.imaging.JPEG;

@Entitypublic class Customer implements java.io.Serializable { private JPEG picture;

... @Lob @Basic(fetch=FetchType.LAZY) public JPEG getPicture( ) { return picture; } public void setPicture(JPEG picture) { this.picture = picture; }}

JavaTM

@Enumerated Maps Java enum types to the

database A Java enum property can be

mapped to: String representation

EnumType.STRING Numeric ordinal number

EnumType.ORDINAL - default

JavaTM

@Enumerated@Entitypublic class Customer implements java.io.Serializable { public enum CustomerType { UNREGISTERED, REGISTERED } private CustomerType customerType;

@Enumerated(EnumType.STRING) public CustomerType getCustomerType() {...} public void setCustomerType(CustomerType t) { ... }}

JavaTM

Entity Relationships

Models association between entities Supports unidirectional as well as

bidirectional relationships Unidirectional relationship: Entity A

references B, but B doesn't reference A Cardinalities:

One to one One to many Many to one Many to many

JavaTM

Cascading Behavior Cascading is used to propagate the effect

of an operation to associated entities Cascading can be applied to:

persist() merge() remove() refresh()

Cascading operations will work only when entities are associated to the persistence context Otherwise IllegalArgumentException

is thrown

JavaTM

Cascading Behavior

CascadeType.PERSIST deals with the creation of entities within the database

CascadeType.REMOVE deals with the deleting of entities within the database

CascadeType.MERGE deals with entity synchronization, meaning updates

CascadeType.REFRESH refreshes the object instance's state from the database

CascadeType.ALL Represents all of the cascade operations

JavaTM

One-to-One Unidirectional Relationship

CUSTOMER

ID INT PRIMARY KEY

FIRST_NAME CHAR(20)

LAST_NAME CHAR(20)

ADDRESS_ID INT

1 O:1

ADDRESS

ID INT PRIMARY KEY

CITY CHAR(20)

STATE CHAR(20)

ZIP CHAR(10)

STREET CHAR(40)

JavaTM

One-to-One Unidirectional Relationship@Entitypublic class Customer implements java.io.Serializable { ... private Address address; ... @OneToOne(cascade={CascadeType.ALL}) @JoinColumn (name="ADDRESS_ID") public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; }

JavaTM

One-to-One Bidirectional Relationship

1 O:1

CUSTOMER

ID INT PRIMARY KEY

FIRST_NAME CHAR(20)

LAST_NAME CHAR(20)

ADDRESS_ID INTCREDIT_CARD_ID INT

CREDIT_CARD

ID INT PRIMARY KEY

NUMBER CHAR(20)

NAME CHAR(4)

ORGANIZATION CHAR(20)

EXP_DATE DATE

JavaTM

One-to-One Bidirectional Relationship@Entitypublic class Customer implements java.io.Serializable { private CreditCard creditCard; ... @OneToOne (cascade={CascadeType.ALL}) @JoinColumn(name="CREDIT_CARD_ID") public CreditCard getCreditCard( ) { return creditCard; } public void setCreditCard(CreditCard card) { this.creditCard = card; } ...}

JavaTM

One-to-One Bidirectional Relationship@Entitypublic class CreditCard implements java.io.Serializable { private Customer customer; ... //Mapping is specified in creditCard //property of Customer bean class @OneToOne(mappedBy="creditCard") public Customer getCustomer( ) { return this.customer; } public void setCustomer(Customer customer) { this.customer = customer; }}

JavaTM

One-to-One Bidirectional Relationship

With all bidirectional relationship types, including one-to-one, there is always the concept of an owning side of the relationship

Used mappedBy attribute designated the CreditCard entity as the inverse side of the relationship Customer entity is the owning side of

the relationship

JavaTM

One-to-One Bidirectional Relationship

Setting up a bidirectional relationship:

Customer cust = new Customer();CreditCard card = new CreditCard();cust.setCreditCard(card);card.setCustomer(cust);entityManager.persist(cust);

JavaTM

One-to-One Bidirectional Relationship

Always wire both sides of a bidirectional relationship when modifying relationships

If you wanted to associate a CreditCard instance with a different Customer:

Customer newCust = em.find(Customer.class, newCustId);CreditCard card = oldCustomer.getCreditCard();oldCustomer.setCreditCard(null);newCust.setCreditCard(card);

JavaTM

One-to-Many Unidirectional Relationship

1 O:M

CUSTOMER

ID INT PRIMARY KEY

FIRST_NAME CHAR(20)

LAST_NAME CHAR(20)

ADDRESS_ID INTCREDIT_CARD_ID INT

PHONE

ID INT PRIMARY KEY

TYPE INT

CUSTOMER_ID INT

NUMBER CHAR(20)

JavaTM

One-to-Many Unidirectional Relationship@Entitypublic class Customer implements java.io.Serializable { ... private Collection<Phone> phoneNumbers= new ArrayList<Phone>(); ... @OneToMany(cascade={CascadeType.ALL}) @JoinColumn (name="CUSTOMER_ID") public Collection<Phone> getPhoneNumbers() {…} public void setPhoneNumbers(Collection<Phone> phones) {…}}

JavaTM

One-to-Many Unidirectional Relationship

Let's look at some code:Customer cust = entityManager.find(Customer.class, pk);Phone phone = new Phone("617-333-3333", 5);cust.getPhones().add(phone);

The new Phone will automatically be created in the database

If you need to remove a Phone from the relationship, you need to remove the Phone from both the collection and the database:

cust.getPhones().remove(phone);entityManager.remove(phone);

JavaTM

Many-to-One Unidirectional Relationship

CRUISE

ID INT PRIMARY KEY

NAME CHAR(30)

SHIP_ID INT

SHIP

ID INT PRIMARY KEY

TONNAGE DECIMAL(8,2)

NAME CHAR(30)

1O:M

JavaTM

Many-to-One Unidirectional Relationship@Entitypublic class Cruise implements java.io.Serializable { private Ship ship; ... @ManyToOne @JoinColumn (name="SHIP_ID") public Ship getShip() { return ship; } public void setShip(Ship ship) { this.ship = ship; }}

JavaTM

One-to-Many Bidirectional Relationship

CRUISE

ID INT PRIMARY KEY

NAME CHAR(30)

SHIP_ID INT

1 O:M

RESERVATION

ID INT PRIMARY KEY

DATE_RESERVED DATE

AMOUNT_PAID DECIMAL(8,2)

CRUISE_ID INT

JavaTM

One-to-Many Bidirectional Relationship@Entitypublic class Reservation implements java.io.Serializable { private Cruise cruise; ... @ManyToOne @JoinColumn(name="CRUISE_ID") public Cruise getCruise( ) { return cruise; } public void setCruise(Cruise cruise) { this.cruise = cruise ; }}

JavaTM

One-to-Many Bidirectional Relationship@Entitypublic class Cruise implements java.io.Serializable { private Collection<Reservation> reservations = new ArrayList<Reservation>(); ... @OneToMany(mappedBy="cruise") public Collection<Reservation> getReservations(){ return reservations; } public void setReservations( Collection<Reserveration> res) { this.reservations = res; }}

JavaTM

Many-to-Many Unidirectional Relationship

RESERVATION

ID INT PRIMARY KEY

DATE_RESERVED DATE

AMOUNT_PAID DECIMAL(8,2)

CRUISE_ID INT

CABIN

ID INT PRIMARY KEYSHIP_ID INTNAME CHAR(10)DECK_LEVEL INTBED_COUNT INT

CABIN_RESERVATION

RESERVATION_ID INT

CABIN_ID INT

1 O:M

1

O:M

JavaTM

Many-to-Many Unidirectional Relationship@Entitypublic class Reservation implements java.io.Serializable { ... @ManyToMany @JoinTable(name="CABIN_RESERVATION", joinColumns={@JoinColumn( name="RESERVATION_ID")},

inverseJoinColumns={ @JoinColumn(name="CABIN_ID")}) public Set<Cabin> getCabins( ) {...} public void setCabins(Set<Cabin> cabins) { this.cabins = cabins; } ...

JavaTM

Many-to-Many Bidirectional Relationship

RESERVATION

ID INT PRIMARY KEY

DATE_RESERVED DATE

AMOUNT_PAID DECIMAL(8,2)

CRUISE_ID INT

CUSTOMER _RESERVATION

RESERVATION_ID INT

CUSTOMER_ID INT

1 O:M

1

O:M

CUSTOMER

ID INT PRIMARY KEY

FIRST_NAME CHAR(20)

LAST_NAME CHAR(20)

ADDRESS_ID INTCREDIT_CARD_ID INT

JavaTM

Many-to-Many Bidirectional Relationship@Entitypublic class Reservation implements java.io.Serializable { private Set<Customer> customers = new HashSet<Customer>(); ... @ManyToMany @JoinTable (name="RESERVATION_CUSTOMER"), joinColumns={ @JoinColumn(name="RESERVATION_ID")}, inverseJoinColumns={ @JoinColumn(name="CUSTOMER_ID")}) public Set<Customer> getCustomers( ) {...} public void setCustomers(Set customers) {...} ...}

JavaTM

Many-to-Many Bidirectional Relationship@Entitypublic class Customer implements java.io.Serializable { private Collection<Reservation> reservations = new ArrayList<Reservation>( ); ... @ManyToMany(mappedBy="customers") public Collection<Reservation> getReservations(){ return reservations; } public void setReservations( Collection<Reservation> reservations) { this.reservations = reservations; } ...}

JavaTM

Entity Listeners Listeners (callback methods) are

designated to receive invocations from persistence provider at various stages of entity lifecycle

PrePersist / PostPersist PreRemove/ PostRemove PreUpdate / PostUpdate PostLoad

Annotate callback handling methods right in the entity class or put them in a separate listener class

JavaTM

Entity Listener@Entity@EntityListener(com.acme.AlertMonitor.class)public class AccountBean implements Account { ... @PrePersist public void validateCreate() {...}

@PostLoad public void adjustPreferredStatus() {...}}

JavaTM

Entity Listenerpublic class AlertMonitor {

@PostPersist public void newAccountAlert(Account acct) { ... }}