Professional Documents
Culture Documents
0
JPA 2.0| 14-June-2012
Topics
Introduction to JPA 2.0 Entity Manager API
JPA Interfaces. Relationship mapping.
JPA configuration. o One to One
Sample configuration Java SE/EE o Many to One
Spring Integration o One to Many
Anatomy of Entity. o Many to Many
Minimal Entity. Inheritance Mapping.
Persistent Identity generation techniques. JPQL
o AUTO id generation Criteria API
o Table id generation JPA Exceptions
o Sequence id generation References.
Entity Lifecycle.
Persistent context.
The Java Persistence API provides Java developers with an object/relational mapping facility for
managing relational data in Java applications. Java Persistence consists of four areas:
o The Java Persistence API
o The query language
o The Java Persistence Criteria API
o Object/relational mapping metadata
EntityManager
o EntityManager instance is analogous to a database connection.
o In a multithreaded web application, each thread will have its own EntityManager
EntityTransaction
o Each EntityManager has a single EntityTransaction, which is required for persisting changes to the underlying
database.
Query
o EntityManager serves as a factory for generating Query classes.
In persistence.xml, we can we can optionally configure which classes we want to include for a
given persistence unit. This is mostly useful in multi datastore applications.
Persistence Provider
o The Java Persistence API has a pluggable Service Provider Interface (SPI) that allows any compliant Java EE
server to communicate with any compliant persistence provider implementation.
o The provider class should implement the javax.persistence.spi.PersistenceProvider interface must be listed
in the provider element.
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
<property name="javax.persistence.jdbc.user" value="APP"/>
<property name="javax.persistence.jdbc.password" value="APP"/>
</properties>
</persistence>
Refer http://docs.oracle.com/cd/B32110_01/web.1013/b28221/cfgdepds005.htm
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property
name="persistenceUnitName" value=jpaDemo"/> </bean>
LocalContainerEntityManagerFactoryBean
for annotation
o Configure a datasource and JPA vendor-specific adapters. scanning.
o Define datasource bean.
o Create the LocalContainerEntityManagerFactoryBean
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-
ref="dataSource"/>
</context:component-scan>
o Define Transaction manager
An entity represents a table in a relational database, and each entity instance corresponds to a
row in that table.
The entity class must have a no-arg constructor. The no-arg constructor must be public or
protected.
The entity class must be a top-level class. An enum or interface must not be designated as an
entity.
The entity class must not be final. No methods or persistent instance variables of the entity class
may be final.
The persistent state of an entity is represented by instance variables (transient variables will not
be the part of persistent state)
@Entity
public class Employee {
@Id
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
..
..
@TableGenerator(name="Emp_Gen", table="ID_GEN",
pkColumnName="GEN_NAME",
valueColumnName="GEN_VALinitialValue=0,allocationSize=100))
@Id
@GeneratedValue(generator="Emp_Gen")
private int id;
Minimal configuration
o we are not concerned that it be any particular sequence.
o In this case, no generator is named, so the provider will use a default sequence object of its own choosing.
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private int id;
@SequenceGenerator(name="Emp_Gen", sequenceName="Emp_Seq")
@Id
@GeneratedValue(generator="Emp_Gen")
private int id;
The state of persistent entities is synchronized to the database when the transaction commits
new new()
refresh() persist()
managed
remove()
persist()
removed
detached
If the persistence context participates in a transaction, the in-memory state of the managed
entities will get synchronized to the database.
An entity manager manages a persistence context and a persistence context is a managed set of
entity instances.
Persistence
Application Context (L2 cache)
Entity Manager
Entity A
Entity C
Entity a Entity B
Entity b
Entities
If there is an association between two entities, one of the following relationship modeling
annotations must be applied to the corresponding persistent property or field of the referencing
entity: @OneToOne, @OneToMany, @ManyToOne, @ManyToMany.
For one-to-one relationship, the owning side corresponds to the side that contains the
corresponding foreign key.
We can declare performance strategy to use with fetching related rows FetchType
o LAZY, EAGER (Lazy means don't load row until the property is retrieved)
@Entity
public class Student { Student
@Id
studentId College_id
int studentId;
...
@ManyToOne College
@JoinColumn ID ...
(name=College_id)
College college;
}
}
Many side will own the relationship so join column annotation will be put on many side.
@Entity
public class College { College
@Id ID ...
int id;
@OneToMany(mappedBy=college)
...
Set<Student> students;
}
@Entity Student
public class Students { ID ... College_id
@Id
int id;
...
@ManyToOne
College college;
}
@Entity
public class Delegate {
...
@ManyToMany
@JoinTable(name="JOIN_DELEGATE_EVENT",
joinColumns={@JoinColumn(name="delegate_id")},
inverseJoinColumns={@JoinColumn(name="event_id")})
List<Event> events;
EVENT DELEGATE
EVENT_ID DELEGATE_ID
JOIN_DELEGATE_EVENT
o SINGLE_TABLE
o JOINED
o TABLE_PER_CLASS
@Entity
@DiscriminatorValue(name=Module")
public class Module extends Project { . . . }
SINGLE_TABLE strategy - all classes in the hierarchy are mapped to a single table in
the database
Discriminator column - contains a value that identifies the subclass
Discriminator type - {STRING, CHAR, INTEGER}
Discriminator value - value entered into the discriminator column for each entity in
a class hierarchy
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Project { . . . }
@Entity
public class Module extends Project { . . . }
@Entity
public class Task extends Module { . . . }
One cannot use AUTO for primary key generation strategy with conjunction with table per
concrete class" inheritance, because in such a case the identity column must be present in each
table and its values must be mutually exclusive.
In joined inheritance a table is defined for each class in the inheritance hierarchy to store only the
local attributes of that class. Each table in the hierarchy must also store the object's id (primary
key), which is only defined in the root class.
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Project { . . . }
@Entity
public class Module extends Project { . . . }
@Entity
public class Task extends Module { . . . }
Advantage:
o Single table inheritance mapping is the fastest of all inheritance models, since it never requires a join to
retrieve a persistent instance from the database.
Disadvantage:
o The larger the inheritance model gets, the "wider" the mapped table gets, in that for every field in the entire
inheritance hierarchy, a column must exist in the mapped table. This may have undesirable consequence on
the database size, since a wide or deep inheritance hierarchy will result in tables with many mostly-empty
columns.
JOINED
Advantage:
o Using joined subclass tables results in the most normalized database schema, meaning the schema with the
least spurious or redundant data.
Disadvantage:
o The joined strategy is often the slowest of the inheritance models.
TABLE_PER_CLASS
Advantage :
o The table-per-class strategy is very efficient when operating on instances of a known class(no joins).
Project
Module
Task
It is heavily inspired by SQL, and its queries resemble SQL queries in syntax, but operate against
JPA entity objects rather than directly with database tables.
In addition to retrieving objects (SELECT queries), JPQL supports bulk UPDATE and DELETE queries
The main difference between JPQL and SQL lies in that the former deals with JPA entities, while
the latter deals directly with relational data.
JPQL eliminates the need for you to use JDBC API from your Java codethe container does all this
work for you behind the scenes.
JPQL lets you define queries using one of the following three statements: SELECT, UPDATE, or
DELETE.
Query API:
o AUTO - any changes made to entity objects will be reflected the very next time when a SELECT query is made
o COMMIT - the persistence engine may only update all the state of the entities during the database COMMIT
Use createNamedQuery() factory method at runtime and pass in the query name
Query must have already been statically defined either in an annotation or XML
Query names are globally scoped
Provider has opportunity to precompile the queries and return errors at deployment time
Can include parameters and hints in static query definition
@NamedQuery(name="Sale.findByCustId",
@NamedQuery(name="Sale.findByCustId",
query="select
query="select s fromsSale
froms Sale s
wherewhere s.customer.id
s.customer.id = :custId= :custId
order order
by s.salesDate")
by s.salesDate")
publicpublic
List findSalesByCustomer(Customer
List findSalesByCustomer(Customercust) { cust) {
returnreturn
entityManager.createNamedQuery(
entityManager.createNamedQuery(
"Sale.findByCustId")
"Sale.findByCustId")
.setParameter("custId",
.setParameter("custId", cust.getId())
cust.getId())
.getResultList();
.getResultList();
} }
Return all sales for a given customer
Query q = em.createNativeQuery(
"SELECT o.id, o.quantity, o.item " +
"FROM Order o, Item i " +
"WHERE (o.item = i.id) AND (i.name = 'widget')",
com.acme.Order.class);
If more than one matches occur during query execution a run-time exception
NonUniqueResultException will be thrown
EntityManager em = ...;
String jpql = "select p from Person where p.age > 20";
Query query = em.createQuery(jpql);
List result = query.getResultList();
Above code will compile happily, but will fail at run time because the JPQL query string is
syntactically incorrect. The correct syntax for the second line is :
o String jpql = "select p from Person p where p.age > 20";
o the Java compiler has no way to detect such an error.
Line 1,2 : Get entity manager, EntityManager creates an instance CriteriaBuilder. CriteriaBuilder is
the factory for CriteriaQuery.
In line 3, the CriteriaBuilder factory constructs a CriteriaQuery instance. The generic type
argument declares the type of result this CriteriaQuery will return upon execution.
In line 4, the CriteriaQuery is set to query from Person.class.
o As a result, root<Person> instance p is returned. Root is a query expression that denotes the extent of a
persistent entity. Root<T> essentially says: "Evaluate this query across all instances of type T." It is similar to
the FROM clause of a JPQL or SQL query.
Line 5 constructs a Predicate. Predicate is another common form of query expression that
evaluates to either true or false. A predicate is constructed by the CriteriaBuilder
Line 6 sets the predicate on the CriteriaQuery as its WHERE clause.
CriteriaBuilder is the factory for CriteriaQuery and query expressions of all sorts.
CriteriaQuery is a tree of query-expression nodes that are used to specify query clauses such as
FROM, WHERE, and ORDER BY in a traditional string-based query language.
CriteriaQuery is transferred to an executable query with its type information preserved so that the
elements of the selected list can be accessed without any run-time casting.
Method Description
CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
Root<Customer> c = q.from(Customer.class);
SetJoin<Customer, PurchaseOrder> o = c.join(Customer_.orders);
Predicate p = cb.equal(o.get(PurchaseOrder_.status), Status.DELIVERED)
.negate();
The join expression created from the root expression c and the persistent Customer.orders
attribute.
The original attribute is of type java.util.Set, the resultant join expression is SetJoin.
SetJoin is a specialized Join for an attribute of declared type java.util.Set.
Though queries are often written with constant literals, it is not a good practice. The good practice
is to parameterize a query, which allows the query to be parsed or prepared only once, cached,
and reused. So a better way to write the query is to use a named parameter:
o String jpql = "select p from Person p where p.age > :age";
A parameterized query binds the value of the parameter before the query execution:
o Query query = em.createQuery(jpql).setParameter("age", 20);
o List result = query.getResultList();
The parameter expression is created with explicit type information to be an Integer and is directly
used to bind a value of 20 to the executable query.
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.groupBy(pet.get(Pet_.color));
This query returns all Pet entities and groups the results by the pets color.
The CriteriaQuery.having method is used in conjunction with groupBy to filter over the groups.
The having method takes a conditional expression as a parameter. By calling the having method,
the query result is restricted according to the conditional expression:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.groupBy(pet.get(Pet_.color));
cq.having(cb.in(pet.get(Pet_.color)).value("brown").value("blonde"));
Exceptions in
javax.persistence
package are
self-explanatory