Professional Documents
Culture Documents
objects
Content
1. Object states
2. Making objects persistent
3. Loading an object
4. Querying
5. Modifying persistent , detached objects
6. Automatic state detection
7. Deleting persistent object
8. Flushing the Session
9. Transitive persistence
States of an object and transitions
Object States
Transient Object
It has just been instantiated using the new operator, and it
is not associated with a persistence context.
It has no persistent representation in the database and has
no a persistent identity.
Persistent Object
Just have been saved or loaded.
An instance with a persistent identity that is currently
associated with a persistence context.
Persistence provider (Hibernate) will detect any changes
made to an object in persistent state and synchronize the
state with the database when the unit of work completes
Object States
Detached Object
an object that has been persistent, but its persistence
context has been closed.
The reference to the object is still valid, and might even be
modified
A detached instance can be reattached to a new persistence
context at a later point in time, making it (and all the
modifications) persistent again by calling
Removed Object
an instance with a persistent identity, associated with a
persistence context, is scheduled for removal from the
database.
The persistence context
a cache of managed entity instances
In a Hibernate application, one Session has one internal persistence
context. In a Java Persistence application, an EntityManager has a
persistence context.
Within the persistence context, the entity instances and
their lifecycle is managed by a session (entity manager)
The session (entity manager) tracks all entity instances within a
persistence context for changes and updates made, and flushes these
changes to the database.
Once a persistence context is closed, all managed entity instances are
no longer managed (detached), and any state changes to this instance
will not be synchronized with the database.
Making objects persistent
We can make a transient instance persistent by
associating it with a session.
HourlyEmployee fritz =
new HourlyEmployee();
// fritz is in transient state
fritz.setName("Fritz");
fritz.setAddress('Paris');
Long generatedId =
(Long)sess.save(fritz);
// fritz is in persistent state
You may assign the identifier
sess.save(fritz, new Long(1234));
JPA: Persisting an Entity Instance
A new entity instance becomes both managed and
persistent by invoking the persist() method on it
Customer fritz =
new Customer("Hoang", "Nguyen");
em.persist(fritz);
If the Customer entity type has a generated identifier, the value is
associated to the instance when persist() is called.
If the identifier is not automatically generated, the application-
assigned (usually natural) key value has to be set on the instance
before persist() is called.
Loading an object
If you already know its identifier, using load()
HourlyEmployee fritz =
(HourlyEmployee)
sess.load(HourlyEmployee.class,
empId);
Can load state into a given instance:
Employee employee = new Employee();
// load pk's state into employee
sess.load(employee, empId);
load() will throw an unrecoverable exception if
there is no matching database row
Loading an object
If you are not certain that a matching row exists, you
should use the get() method, which returns null if
there is no matching row
Customer customer = (Customer)
sess.get(Customer.class, id);
if (customer==null) { ... }
Can load an object using an SQL SELECT ... FOR
UPDATE, using a LockMode.
Customer customer = (Customer)
sess.get(Customer.class,
id,
LockMode.UPGRADE);
Loading an object
It is possible to re-load an object and all its
collections at any time, using the refresh()
method.
sess.save(customer);
// force the SQL INSERT
sess.flush();
// re-read the state after the trigger executes
sess.refresh(customer);
This is useful when database triggers are used to
initialize some of the properties of the object.
JPA: Loading an object
Load an entity instance by its identifier value with
the entity manager's find() method:
Customer c =
em.find(Customer.class, cusId);
Can reload an entity instance and it's collections
at any time using the em.refresh() operation
Querying
If you don't know the identifiers of the objects you
are looking for, you need a query.
Hibernate supports an easy-to-use but powerful
object oriented query language (OOQL).
For programmatic query creation, Hibernate
supports a sophisticated Criteria and Example
query feature (QBC and QBE).
You may also express your query in the native
SQL of your database, with optional support from
Hibernate for result set conversion into objects.
Executing Query
Queries are represented with an instance of
org.hibernate.Query.
You obtain a Query using the current Session:
Query query = session
.createQuery("FROM Employee AS emp WHERE " +
"emp.birthdate < ?");
query.setDate(0, date);
A query is executed by invoking list()
List empployees = query.list();
might execute the query using the iterate()
Iterator iter = sess.createQuery(
"FROM Employee AS emp ORDER BY emp.name")
.iterate();
JPA: Executing Query
Queries are represented with an instance of
javax.persistence.Query.
obtain a Query using the current entity manager:
Query query = em.createQuery(
"SELECT emp FROM Employee AS emp
WHERE emp.birthdate < ?1");
query.setParametter(1, date,
TemporalType.DATE);
A query is executed by invoking getResultList()
List empplyees =
query.getResultList();
Queries that return tuples
Queries sometimes return tuples of objects, in which case each tuple is
returned as an array:
Query query = session.createQuery("SELECT emp,
dep FROM Employee AS emp JOIN
emp.depatment AS dep");
Iterator iter = query.list().iterator();
while (iter.hasNext()){
Object[] objs = (Object[])iter.next();
Employee emp = (Employee) objs[0];
Depatment dep = (Depatment) objs[1];
}
Scalar results
Queries may specify a property of a class and SQL aggregate
functions in the select clause. They are considered "scalar"
results
Query query = session.createQuery(
"SELECT emp.name, emp.email " +
"FROM Employee AS emp");
Iterator iter = query.list().iterator();
while(iter.hasNext()){
Object[] row = (Object[])iter1.next();
String name = (String) row[0];
String email = (String) row[1];
}
Bind parameters
Methods on Query are provided for binding values
to named parameters or JDBC-style ? possitonal
parameters.
Hibernate numbers parameters from zero.
Named parameters are identifiers of the form
:name in the query string.
The advantages of named parameters are:
named parameters are insensitive to the order they occur in
the query string
they may occur multiple times in the same query
they are self-documenting
Bind parameters - Examples
Named parameter (preferred)
List emps = sess.createQuery(
"from HourlyEmployee emp where emp.name = :pname")
.setString("pname", "Fritz").list();
Positional parameter
Iterator emps = sess.createQuery(
"from DomesticCat cat where cat.name=? and cat.age=?")
.setString(0, "Izi")
.setInteger(1, 12).iterate();
q.setParameter("pname", "Paul");
List emps getResultList();
Positional parameter
Query q = em.createQuery("SELECT e FROM Employee e WHERE
e.name LIKE ?1 and e.wage > ?2");
q.setParameter(1, "Smith");
q.setParameter(2, 1200);
List emps = getResultList();
e.name IN (:namesList)");
Pagination
Can specify bounds upon your result set
The maximum number of rows, and / or
The first row you want to retrieve
Example:
Query q =
sess.createQuery("from
Employee");
q.setFirstResult(20);
q.setMaxResults(10);
List cats = q.list();
Scrollable iteration
If your JDBC driver supports scrollable
ResultSets, the Query interface may be used to
obtain a ScrollableResults object, which allows
flexible navigation of the query results.
Example:
Query q = sess.createQuery(
"select emp from Employee emp "
+
"order by emp.name");
ScrollableResults cats =
q.scroll();
Externalizing named queries
You may also define named queries in the mapping document
<query name ="team.by.name.and.city">
<![CDATA[
from Team as team where
team.name = ? and team.city = ?
]]></query>
Parameter binding and executing is done programatically:
Query q = sess.getNamedQuery(
"team.by.name.and.city");
q.setString(0, name);
q.setString(1, city);
List cats = q.list();
JPA - Externalizing named queries
Named queries can be defined in EJB QL or in SQL.
Query names are scoped to the persistence unit.
Example
@NamedQuery(
name="findAllCustomersWithName",
query="SELECT c FROM Customer c WHERE c.name
LIKE :custName")
Use of a named query:
customers =
em.createNamedQuery("findAllCustomersWithName")
.setParameter("custName", "Smith")
.getResultList();
Filtering collections.
A collection filter is a special type of query that may be
applied to a persistent collection or array. The query string
may refer to this, meaning the current collection element .
Example:
session.update(team);
Query query3 =
session.createFilter(team.getPlayers(),
"where this.firstname = ?");
Collection players = (Collection)
query3.setParameter(0, "nguyen").list();
Iterator iter = players.iterator();
while (iter.hasNext()){
Player p = (Player) iter.next();
System.out.println(p);
}
Criteria queries
HQL is extremely powerful but some developers prefer
to build queries dynamically, using an object-oriented
API, rather than building query strings.
Hibernate provides an intuitive Criteria query API for
these cases
Example:
Criteria crit =
session.createCriteria(Team.class);
crit.add(Expression.eq("name","HAGL"))
;
Queries in native SQL
You may express a query in native SQL, using createSQLQuery()
If you chose to use the Hibernate API, you must enclose SQL aliases in
braces:
SQLQuery query = session
.createSQLQuery("select * from team");
query.addEntity(Team.class);
or
SQLQuery query = session.createSQLQuery(
"select {team.*} from team {team}");
query.addEntity("team", Team.class);
Modifying persistent object
Transactional persistent instances may be manipulated
by the application and any changes to persistent state
will be persisted when the Session is flushed
(automatically).
So the most straightforward way to update the state of
an object is to load() it, and then manipulate it
directly, while the Session is open:
Example:
DomesticCat cat = (DomesticCat)
sess.load( Cat.class, new Long(69));
cat.setName("PK");
sess.flush();
Modifying detached object
To reattach of detached instances using the
Session.update() or Session.merge()
methods:
Example:
// in the first session
SalaryEmployee emp = (SalaryEmployee)
firstSession.load(SalaryEmployee.class, empId);
Department dep = new Department();
firstSession.save(dept);
// in a higher layer of the application
emp.setDepartment(dep);