In
part-1 of this series, I just introduced JPA. In this post, I discuss on the
life of an entity and briefly explain how to query entities using JPQL. It helps you understand and develop JPA based
applications.
Life Cycle of an Entity
As a developer, it is very crucial for you to understand how the EntityManager manages the entity. The EntityManager performs several
operations to manage entity instances. An entity instance moves from one state
to another during these operations. The entity instance attains four states
such as: New, Managed, Removed and Detached in its life. The diagram in
Figure-1 depicts these states and their transition.
Figure-1: Entity Life Cycle
When an entity instance is initially created in the application, it attains the New state. The new entity instance just created has no persistent identity, is not yet associated with a persistence context and has no representation in the database.
The entity instance attains Managed state when an attempt is made
to save it to the database using persist() method of the EntityManager. The managed entity instance has a
persistent identity and is associated with a persistence
context. The persist() method
must be invoked within an active transaction context. On transaction commit,
the new entity instance is saved to the database. When an entity instance is
retrieved from the database by an EntityManager using its find() method or
through a query execution, the entity instance attains the managed state. If a
managed entity instance is modified within an active transaction the update is
propagated to the database on transaction commit. When EntityManager invokes its refresh()
method on a managed entity, the state of the entity instance gets refreshed
from the database overwriting changes made to the entity, if any.
When the EntityManager invokes its remove()
method on a managed entity within an active transaction, the entity instance is scheduled for removal from the
database.
The entity instance moves to Removed
state from managed state. The removed entity instance has a persistent identity and is
associated with a persistent context. It is
physically deleted from the database on transaction commit.
A managed entity attains a Detached state when the EntityManager
invokes its detach() method on it. In the detached state, the entity instance
has a persistence identity and is not associated with a persistent context. A detached entity instance is not managed by
any EntityManager but still represent data in the database. Changes made to a detached
entity instance are not stored in the database unless modified detached
instance is merged back into the persistent context to become managed again. All the entity instances associated with an
EntityManager become detached when the EntityManager is closed. Also all the
entity instances are detached when the clear() method of the EntityManager is
invoked which clears the persistence context associated with the EntityManager.
The
entity in a persistent context is synchronized to the database when the active transaction
with which the entity is associated commits. To force synchronization of the
managed entity to the underlying database, the flush() method of the EntityManager instance is invoked.
If the entity is in the removed state, flush forces
removal of the entity from the database.
Querying Entities
JPA provides a query language, JPQL (Java Persistence Query
Language) to query entities efficiently using the EntityManager. It is similar
to SQL in its syntax, object-oriented, well expressive and more flexible than
traditional SQL. Unlike SQL query which directly deals with table and column
names, a query in JPQL operates over persistent entity schema in the
application. The JPQL query is translated into native SQL query and is executed
over the database schema to which the entities are mapped. Arbitrary identifiers are assigned to entities so that they can be referenced elsewhere in the query.
For
example, consider a simple select query for all the Employee entities:
SELECT e FROM Employee e
In the query example above, the identifier e is assigned to the entity Employee.
Creating
Queries
Depending upon how the query string is defined, queries can be
classified into two different types: Static query and Dynamic query.
Static Query: A static query (or named query) is one which is defined in
metadata by using @NamedQuery annotation before the entity class. The name element of @NamedQuery specifies the name of the query while
the query element of @NamedQuery is the query itself.
For example,
@NamedQuery(name = "Employee.findAll"
query = “SELECT e FROM Employee e”)
@Entity
public class Employee{
...
}
The createNamedQuery() method of the EntityManager instance
is used to create a static query referring by its name as shown
below:
Query query = em.createNamedQuery("Employee.findAll");
Since these named queries are statically defined, during
deployment time itself, the persistent provider may parse and translate the
JPQL into native SQL, cache them, thereby yielding better performance.
Dynamic Query: A Dynamic Query is created directly using the createQuery() method
of the EntityManager instance within a method
of some class that deals with application’s business logic. For example,
public
List getEmployeeList() {
Query query =
em.createQuery("select e from Employee e");
List empList = query.getResultList(); // query execution
return empList;
}
Since
query translation from JPQL to SQL occurs at run-time, the query execution may
become slow. Thus static queries are better choice if the scenario for which
the query to be executed is well known in advance.
Executing
Queries
The Query interface provides separate methods to
execute updatable statements such as UPDATE and DELETE and non-updatable statement
such as SELECT query.
A SELECT query can be of two types based
on the result it return on execution: single result query and multiple results
query. The Query interface has two separate methods named getSingleResult() and
getResultList() to deal with the situations.
Single Result
An invocation of the method getSingleResult()
of a query instance executes the query and returns an
untyped object representing a single row matching the criteria in the query
string. If the match fails, then the method throws an exception signifying no
result. Also, if more than one match found on query execution, the method throws
an exception.
The following code shows how
to execute a SELECT query that returns a single entity.
Query sqry =
em.createQuery("SELECT e FROM Employee e WHERE e.empid = 123");
em.createQuery("SELECT e FROM Employee e WHERE e.empid = 123");
Employee e = (Enployee) sqry.getSingleResult();
Multiple Results
The method getResultList() executes
a query and returns the query result as an untyped List object containing
multiple entity instances. The following code shows the same:
Query mqry =
entityManager.createQuery("SELECT e
FROM Employee e");
List employees = mqry.getResultList();
Further, both the methods only execute SELECT
statements and throw an IllegalStateException exception if UPDATE or DELETE
statements are used in place.
The Query interface has executeUpdate() method to execute UPDATE and DELETE statements. When
the method is invoked on the query, it returns the number of entities updated
or deleted. The following code shows how to execute such statements:
Query uqry =
em.createQuery("UPDATE Employee e SET e.designation=’Manager’");
int
uCount = uqry.executeUpdate();
Parameters in Query
Parameterized queries may offer efficiency when executed. In JPQL,
parameterized query execution is similar to the PreparedStatement interface in JDBC
API. In this case the query is created once and can be executed again and again
by setting values for the parameters. The parameter values can be set using setParameter()
method of the Query interface in JPQL. JPQL supports two types of parameters in
queries: Positional and Named.
Positional Parameters
Positional
parameters are prefixed with a question mark (?) followed the number
denoting the position of the parameter in the query. The following example shows a parameterized
query with positional parameters:
String strQry =
“SELECT e FROM Employee e
WHERE e.empname = ?1 and e.designation
= ?2”;
Query pQry
= em.createQuery(strQry);
pQry.setParameter(1,
eName);
pQry.setParameter(2,
eDesignation);
The above example, the positional parameters ?1 and ?2 will be
replaced with the values of the variables eName and eDesignation provided using
setParameter() methods.
Named Parameters
Similarly named parameters are query parameters that are prefixed
with a colon(:). The following example shows how to use named parameters in
aquery:
String strQry =
"SELECT e FROM Employee e WHERE e.empname
=
:eName and e.designation = :eDesignation";
Query nQry
= em.createQuery(strQry);
nQry.setParameter(“eName”,
aName);
nQry.setParameter(“eDesignation”,
aDesignation);
Conclusion
In this post, I covered
entity life cycle and briefly introduced JPQL query. In the next, post of this
series, I will show you how to develop a simple JPA based application using a
suitable development environment. Keep following me at this site.
0 comments:
Post a Comment