mirror of https://github.com/apache/openjpa.git
1374 lines
50 KiB
XML
1374 lines
50 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
Licensed to the Apache Software Foundation (ASF) under one
|
|
or more contributor license agreements. See the NOTICE file
|
|
distributed with this work for additional information
|
|
regarding copyright ownership. The ASF licenses this file
|
|
to you under the Apache License, Version 2.0 (the
|
|
"License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing,
|
|
software distributed under the License is distributed on an
|
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations
|
|
under the License.
|
|
-->
|
|
<chapter id="jpa_overview_pc">
|
|
<title>
|
|
Entity
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc">
|
|
<primary>
|
|
Entity
|
|
</primary>
|
|
<seealso>
|
|
persistent classes
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
class
|
|
</primary>
|
|
<secondary>
|
|
persistent
|
|
</secondary>
|
|
<see>
|
|
persistent classes
|
|
</see>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
persistence capable
|
|
</primary>
|
|
<see>
|
|
Entity
|
|
</see>
|
|
</indexterm>
|
|
<para>
|
|
JPA recognizes two types of persistent classes: <emphasis>entity</emphasis>
|
|
classes and <emphasis>embeddable</emphasis> classes. Each persistent instance of
|
|
an entity class - each <emphasis>entity</emphasis> - represents a unique
|
|
datastore record. You can use the <classname>EntityManager</classname> to find
|
|
an entity by its persistent identity (covered later in this chapter), or use a
|
|
<classname>Query</classname> to find entities matching certain criteria.
|
|
</para>
|
|
<para>
|
|
An instance of an embeddable class, on the other hand, is only stored as part of
|
|
a separate entity. Embeddable instances have no persistent identity, and are
|
|
never returned directly from the <classname>EntityManager</classname> or from a
|
|
<classname>Query</classname> unless the query uses a projection on owning class
|
|
to the embedded instance. For example, if <classname>Address</classname> is
|
|
embedded in <classname>Company</classname>, then
|
|
a query <classname>"SELECT a FROM Address a"</classname> will never return the
|
|
embedded <classname>Address</classname> of <classname>Company</classname>;
|
|
but a projection query such as
|
|
<classname>"SELECT c.address FROM Company c"</classname> will.
|
|
</para>
|
|
<para>
|
|
Despite these differences, there are few distinctions between entity classes and
|
|
embeddable classes. In fact, writing either type of persistent class is a lot
|
|
like writing any other class. There are no special parent classes to
|
|
extend from, field types to use, or methods to write. This is one important way
|
|
in which JPA makes persistence transparent to you, the developer.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
JPA supports both fields and JavaBean properties as persistent state. For
|
|
simplicity, however, we will refer to all persistent state as persistent fields,
|
|
unless we want to note a unique aspect of persistent properties.
|
|
</para>
|
|
</note>
|
|
<example id="jpa_overview_pc_pcclass">
|
|
<title>
|
|
Persistent Class
|
|
</title>
|
|
<programlisting>
|
|
package org.mag;
|
|
|
|
/**
|
|
* Example persistent class. Notice that it looks exactly like any other
|
|
* class. JPA makes writing persistent classes completely transparent.
|
|
*/
|
|
public class Magazine {
|
|
|
|
private String isbn;
|
|
private String title;
|
|
private Set articles = new HashSet();
|
|
private Article coverArticle;
|
|
private int copiesSold;
|
|
private double price;
|
|
private Company publisher;
|
|
private int version;
|
|
|
|
protected Magazine() {
|
|
}
|
|
|
|
public Magazine(String title, String isbn) {
|
|
this.title = title;
|
|
this.isbn = isbn;
|
|
}
|
|
|
|
public void publish(Company publisher, double price) {
|
|
this.publisher = publisher;
|
|
publisher.addMagazine(this);
|
|
this.price = price;
|
|
}
|
|
|
|
public void sell() {
|
|
copiesSold++;
|
|
publisher.addRevenue(price);
|
|
}
|
|
|
|
public void addArticle(Article article) {
|
|
articles.add(article);
|
|
}
|
|
|
|
// rest of methods omitted
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<section id="jpa_overview_pc_restrict">
|
|
<title>
|
|
Restrictions on Persistent Classes
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_restrict">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
restrictions on
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
There are very few restrictions placed on persistent classes. Still, it never
|
|
hurts to familiarize yourself with exactly what JPA does and does not support.
|
|
</para>
|
|
<section id="jpa_overview_pc_no_arg">
|
|
<title>
|
|
Default or No-Arg Constructor
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_no_arg">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
no-arg constructor requirement
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
constructor
|
|
</primary>
|
|
<secondary>
|
|
no-arg constructor requirement
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
The JPA specification requires that all persistent classes have a no-arg
|
|
constructor. This constructor may be public or protected. Because the compiler
|
|
automatically creates a default no-arg constructor when no other constructor is
|
|
defined, only classes that define constructors must also include a no-arg
|
|
constructor.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA's <emphasis>enhancer</emphasis> will automatically add a protected
|
|
no-arg constructor to your class when required. Therefore, this restriction does
|
|
not apply when using the enhancer. See <xref linkend="ref_guide_pc_enhance"/>
|
|
of the Reference Guide for details.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="jpa_overview_pc_final">
|
|
<title>
|
|
Final
|
|
</title>
|
|
<para>
|
|
Entity classes may not be final. No method of an entity class can be final.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA supports final classes and final methods.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="jpa_overview_pc_id">
|
|
<title>
|
|
Identity Fields
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_id">
|
|
<primary>
|
|
identity fields
|
|
</primary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_id">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
JPA id requirement
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
All entity classes must declare one or more fields which together form the
|
|
persistent identity of an instance. These are called <emphasis>identity
|
|
</emphasis> or <emphasis>primary key</emphasis> fields. In our <classname>
|
|
Magazine</classname> class, <literal>isbn</literal> and <literal>title</literal>
|
|
are identity fields, because no two magazine records in the datastore can have
|
|
the same <literal>isbn</literal> and <literal>title</literal> values.
|
|
<xref linkend="jpa_overview_meta_id"/> will show you how to denote your
|
|
identity fields in JPA metadata. <xref linkend="jpa_overview_pc_identity"/>
|
|
below examines persistent identity.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA fully supports identity fields, but does not require them. See
|
|
<xref linkend="ref_guide_pc_oid"/> of the Reference Guide for details.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="jpa_overview_pc_version">
|
|
<title>
|
|
Version Field
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_version">
|
|
<primary>
|
|
version fields
|
|
</primary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_version">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
JPA version requirement
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
The <literal>version</literal> field in our <classname>Magazine</classname>
|
|
class may seem out of place. JPA uses a version field in your entities to detect
|
|
concurrent modifications to the same datastore record. When the JPA runtime
|
|
detects an attempt to concurrently modify the same record, it throws an
|
|
exception to the transaction attempting to commit last. This prevents
|
|
overwriting the previous commit with stale data.
|
|
</para>
|
|
<para>
|
|
A version field is not required, but without one concurrent threads or
|
|
processes might succeed in making conflicting changes to the same record at the
|
|
same time. This is unacceptable to most applications.
|
|
<xref linkend="jpa_overview_meta_version"/> shows you how to designate a
|
|
version field in JPA metadata.
|
|
</para>
|
|
<para>
|
|
The version field must be an integral type (<classname> int</classname>,
|
|
<classname>Long</classname>, etc) or a <classname>
|
|
java.sql.Timestamp</classname>. You should consider version fields immutable.
|
|
Changing the field value has undefined results.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA fully supports version fields, but does not require them for concurrency
|
|
detection. OpenJPA can maintain surrogate version values or use state
|
|
comparisons to detect concurrent modifications. See
|
|
<xref linkend="ref_guide_mapping_jpa"/> in the Reference Guide.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="jpa_overview_pc_restrict_inheritance">
|
|
<title>
|
|
Inheritance
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_restrict_inheritance">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
inheritance of
|
|
</secondary>
|
|
<seealso>
|
|
inheritance
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
inheritance
|
|
</primary>
|
|
<secondary>
|
|
of persistent classes
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
JPA fully supports inheritance in persistent classes. It allows persistent
|
|
classes to inherit from non-persistent classes, persistent classes to inherit
|
|
from other persistent classes, and non-persistent classes to inherit from
|
|
persistent classes. It is even possible to form inheritance hierarchies in which
|
|
persistence skips generations. There are, however, a few important limitations:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Persistent classes cannot inherit from certain natively-implemented system
|
|
classes such as <classname>java.net.Socket</classname> and <classname>
|
|
java.lang.Thread</classname>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If a persistent class inherits from a non-persistent class, the fields of the
|
|
non-persistent superclass cannot be persisted.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
All classes in an inheritance tree must use the same identity type. We cover
|
|
entity identity in <xref linkend="jpa_overview_pc_identity"/>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="jpa_overview_pc_restrict_fields">
|
|
<title>
|
|
Persistent Fields
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_restrict_fields">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
field restrictions
|
|
</secondary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
field
|
|
</primary>
|
|
<secondary>
|
|
persistent
|
|
</secondary>
|
|
<see>
|
|
persistent fields
|
|
</see>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_restrict_fields">
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
restrictions on
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
JPA manages the state of all persistent fields. Before you access persistent
|
|
state, the JPA runtime makes sure that it has been loaded from the datastore.
|
|
When you set a field, the runtime records that it has changed so that the new
|
|
value will be persisted. This allows you to treat the field in exactly the same
|
|
way you treat any other field - another aspect of JPA's transparency.
|
|
</para>
|
|
<para>
|
|
JPA does not support static or final fields. It does, however, include built-in
|
|
support for most common field types. These types can be roughly divided into
|
|
three categories: immutable types, mutable types, and relations.
|
|
</para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
immutable types
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
immutable
|
|
</primary>
|
|
<secondary>
|
|
persistent field types
|
|
</secondary>
|
|
</indexterm>
|
|
<emphasis>Immutable</emphasis> types, once created, cannot be changed. The only
|
|
way to alter a persistent field of an immutable type is to assign a new value to
|
|
the field. JPA supports the following immutable types:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
All primitives (<classname>int, float, byte</classname>, etc)
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
All primitive wrappers (<classname>java.lang.Integer, java.lang.Float,
|
|
java.lang.Byte</classname>, etc)
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.lang.String</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.math.BigInteger</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.math.BigDecimal</classname>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
JPA also supports <classname>byte[]</classname>, <classname>Byte[]</classname>,
|
|
<classname>char[]</classname>, and <classname>Character[]</classname> as
|
|
immutable types. That is, you can persist fields of these types,
|
|
but you should not manipulate individual array indexes without resetting the
|
|
array into the persistent field.
|
|
</para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
mutable types
|
|
</secondary>
|
|
<seealso>
|
|
proxies
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
mutable
|
|
</primary>
|
|
<secondary>
|
|
persistent field types
|
|
</secondary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
<seealso>
|
|
proxies
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
user-defined types
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
user-defined
|
|
</primary>
|
|
<secondary>
|
|
persistent field types
|
|
</secondary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
</indexterm>
|
|
Persistent fields of <emphasis>mutable</emphasis> types can be altered without
|
|
assigning the field a new value. Mutable types can be modified directly through
|
|
their own methods. The JPA specification requires that implementations support
|
|
the following mutable field types:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.util.Date</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.util.Calendar</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.sql.Date</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.sql.Timestamp</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.sql.Time</classname>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Enums
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Entity types (relations between entities)
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Embeddable types
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.util.Collection</classname>s of entities
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.util.Set</classname>s of entities
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.util.List</classname>s of entities
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>java.util.Map</classname>s in which each entry maps the value of one
|
|
of a related entity's fields to that entity.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Collection and map types may be parameterized.
|
|
</para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
of unknown types
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
Object
|
|
</primary>
|
|
<secondary>
|
|
as persistent field type
|
|
</secondary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
</indexterm>
|
|
Most JPA implementations also have support for persisting serializable values as
|
|
binary data in the datastore. <xref linkend="jpa_overview_meta"/> has more
|
|
information on persisting serializable types.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA also supports arrays, <classname>java.lang.Number</classname>,
|
|
<classname>java.util.Locale</classname>, all JDK 1.2 <classname>Set</classname>,
|
|
<classname>List</classname>, and <classname>Map</classname> types,
|
|
and many other mutable and immutable field types. OpenJPA also allows you to
|
|
plug in support for custom types.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="jpa_overview_pc_restrict_conclusion">
|
|
<title>
|
|
Conclusions
|
|
</title>
|
|
<para>
|
|
This section detailed all of the restrictions JPA places on persistent classes.
|
|
While it may seem like we presented a lot of information, you will seldom find
|
|
yourself hindered by these restrictions in practice. Additionally, there are
|
|
often ways of using JPA's other features to circumvent any limitations you run
|
|
into.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_overview_pc_identity">
|
|
<title>
|
|
Entity Identity
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_identity">
|
|
<primary>
|
|
JPA
|
|
</primary>
|
|
<secondary>
|
|
identity
|
|
</secondary>
|
|
<seealso>
|
|
identity
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
entity identity
|
|
</primary>
|
|
<see>
|
|
identity
|
|
</see>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_identity">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
JPA
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
numeric
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
qualitative
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
numeric identity
|
|
</primary>
|
|
<seealso>
|
|
identity
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
qualitative identity
|
|
</primary>
|
|
<seealso>
|
|
identity
|
|
</seealso>
|
|
</indexterm>
|
|
Java recognizes two forms of object identity: numeric identity and qualitative
|
|
identity. If two references are <emphasis>numerically</emphasis> identical, then
|
|
they refer to the same JVM instance in memory. You can test for this using the
|
|
<literal>==</literal> operator. <emphasis>Qualitative</emphasis> identity, on
|
|
the other hand, relies on some user-defined criteria to determine whether two
|
|
objects are "equal". You test for qualitative identity using the <methodname>
|
|
equals</methodname> method. By default, this method simply relies on numeric
|
|
identity.
|
|
</para>
|
|
<para>
|
|
JPA introduces another form of object identity, called <emphasis>entity
|
|
identity</emphasis> or <emphasis>persistent identity</emphasis>. Entity
|
|
identity tests whether two persistent objects represent the same state in the
|
|
datastore.
|
|
</para>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
persistent fields
|
|
</primary>
|
|
<secondary>
|
|
id
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
id
|
|
</primary>
|
|
<secondary>
|
|
fields
|
|
</secondary>
|
|
<seealso>
|
|
persistent fields
|
|
</seealso>
|
|
</indexterm>
|
|
The entity identity of each persistent instance is encapsulated in its
|
|
<emphasis>identity field(s)</emphasis>. If two entities of the same type have
|
|
the same identity field values, then the two entities represent the same state
|
|
in the datastore. Each entity's identity field values must be unique among all
|
|
other entities of the same type.
|
|
</para>
|
|
<para>
|
|
Identity fields must be primitives, primitive wrappers, <classname>
|
|
String</classname>s, <classname>Date</classname>s, <classname>
|
|
Timestamp</classname>s, or embeddable types.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
OpenJPA supports entities as identity fields, as the Reference Guide discusses
|
|
in <xref linkend="ref_guide_pc_oid_entitypk"/>. For legacy schemas with binary
|
|
primary key columns, OpenJPA also supports using identity fields of type
|
|
<classname>byte[]</classname>. When you use a <classname>byte[]</classname>
|
|
identity field, you must create an identity class. Identity classes are
|
|
covered below.
|
|
</para>
|
|
</note>
|
|
<warning>
|
|
<para>
|
|
Changing the fields of an embeddable instance while it is assigned to an
|
|
identity field has undefined results. Always treat embeddable identity instances
|
|
as immutable objects in your applications.
|
|
</para>
|
|
</warning>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
uniqueness requirement
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>
|
|
uniquness requirement
|
|
</primary>
|
|
<seealso>
|
|
identity
|
|
</seealso>
|
|
</indexterm>
|
|
If you are dealing with a single persistence context (see
|
|
<xref linkend="jpa_overview_emfactory_perscontext"/>), then you do not
|
|
have to compare identity fields to test whether two entity references represent
|
|
the same state in the datastore. There is a much easier way: the <literal>==
|
|
</literal> operator. JPA requires that each persistence context maintain only
|
|
one JVM object to represent each unique datastore record. Thus, entity identity
|
|
is equivalent to numeric identity within a persistence context. This is referred
|
|
to as the <emphasis>uniqueness requirement</emphasis>.
|
|
</para>
|
|
<para>
|
|
The uniqueness requirement is extremely important - without it, it would be
|
|
impossible to maintain data integrity. Think of what could happen if two
|
|
different objects in the same transaction were allowed to represent the same
|
|
persistent data. If you made different modifications to each of these objects,
|
|
which set of changes should be written to the datastore? How would your
|
|
application logic handle seeing two different "versions" of the same data?
|
|
Thanks to the uniqueness requirement, these questions do not have to be
|
|
answered.
|
|
</para>
|
|
<section id="jpa_overview_pc_identitycls">
|
|
<title>
|
|
Identity Class
|
|
</title>
|
|
<para>
|
|
<indexterm zone="jpa_overview_pc_identitycls">
|
|
<primary>
|
|
identity class
|
|
</primary>
|
|
<seealso>
|
|
identity
|
|
</seealso>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_identitycls">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
class requirements
|
|
</secondary>
|
|
</indexterm>
|
|
If your entity has only one identity field, you can use the value of that field
|
|
as the entity's identity object in all <link linkend="jpa_overview_em">
|
|
<classname>EntityManager</classname></link> APIs. Otherwise, you must supply an
|
|
identity class to use for identity objects. Your identity class must meet the
|
|
following criteria:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The class must be public.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The class must be serializable.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The class must have a public no-args constructor.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The names of the non-static fields or properties of the class must be the same
|
|
as the names of the identity fields or properties of the corresponding entity
|
|
class, and the types must be identical.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The <methodname>equals</methodname> and <methodname>hashCode</methodname>
|
|
methods of the class must use the values of all fields or properties
|
|
corresponding to identity fields or properties in the entity class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If the class is an inner class, it must be <literal>static</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
All entity classes related by inheritance must use the same identity class, or
|
|
else each entity class must have its own identity class whose inheritance
|
|
hierarchy mirrors the inheritance hierarchy of the owning entity classes (see
|
|
<xref linkend="jpa_overview_pc_identity_hierarchy"/>).
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<note>
|
|
<para>
|
|
Though you may still create identity classes by hand, OpenJPA provides the
|
|
<classname>appidtool</classname> to automatically generate proper identity
|
|
classes based on your identity fields. See
|
|
<xref linkend="ref_guide_pc_oid_application"/> of the Reference Guide.
|
|
</para>
|
|
</note>
|
|
<example id="jpa_overview_pc_identity_appidcode">
|
|
<title>
|
|
Identity Class
|
|
</title>
|
|
<para>
|
|
This example illustrates a proper identity class for an entity with multiple
|
|
identity fields.
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* Persistent class using application identity.
|
|
*/
|
|
public class Magazine {
|
|
|
|
private String isbn; // identity field
|
|
private String title; // identity field
|
|
|
|
// rest of fields and methods omitted
|
|
|
|
|
|
/**
|
|
* Application identity class for Magazine.
|
|
*/
|
|
public static class MagazineId {
|
|
|
|
// each identity field in the Magazine class must have a
|
|
// corresponding field in the identity class
|
|
public String isbn;
|
|
public String title;
|
|
|
|
/**
|
|
* Equality must be implemented in terms of identity field
|
|
* equality, and must use instanceof rather than comparing
|
|
* classes directly (some JPA implementations may subclass the
|
|
* identity class).
|
|
*/
|
|
public boolean equals(Object other) {
|
|
if (other == this)
|
|
return true;
|
|
if (!(other instanceof MagazineId))
|
|
return false;
|
|
|
|
MagazineId mi = (MagazineId) other;
|
|
return (isbn == mi.isbn
|
|
|| (isbn != null && isbn.equals(mi.isbn)))
|
|
&& (title == mi.title
|
|
|| (title != null && title.equals(mi.title)));
|
|
}
|
|
|
|
/**
|
|
* Hashcode must also depend on identity values.
|
|
*/
|
|
public int hashCode() {
|
|
return ((isbn == null) ? 0 : isbn.hashCode())
|
|
^ ((title == null) ? 0 : title.hashCode());
|
|
}
|
|
|
|
public String toString() {
|
|
return isbn + ":" + title;
|
|
}
|
|
}
|
|
}
|
|
</programlisting>
|
|
</example>
|
|
<section id="jpa_overview_pc_identity_hierarchy">
|
|
<title>
|
|
Identity Hierarchies
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_identity_hierarchy">
|
|
<primary>
|
|
identity
|
|
</primary>
|
|
<secondary>
|
|
hierarchy
|
|
</secondary>
|
|
</indexterm>
|
|
<mediaobject>
|
|
<imageobject>
|
|
<!-- PNG image data, 320 x 267 (see README) -->
|
|
<imagedata fileref="img/appid-hierarchy.png" width="213px"/>
|
|
|
|
</imageobject>
|
|
</mediaobject>
|
|
<para>
|
|
An alternative to having a single identity class for an entire inheritance
|
|
hierarchy is to have one identity class per level in the inheritance hierarchy.
|
|
The requirements for using a hierarchy of identity classes are as follows:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The inheritance hierarchy of identity classes must exactly mirror the hierarchy
|
|
of the persistent classes that they identify. In the example pictured above,
|
|
abstract class <classname>Person</classname> is extended by abstract class
|
|
<classname>Employee</classname>, which is extended by non-abstract class
|
|
<classname> FullTimeEmployee</classname>, which is extended by non-abstract
|
|
class <classname>Manager</classname>. The corresponding identity classes, then,
|
|
are an abstract <classname>PersonId</classname> class, extended by an abstract
|
|
<classname>EmployeeId</classname> class, extended by a non-abstract <classname>
|
|
FullTimeEmployeeId</classname> class, extended by a non-abstract <classname>
|
|
ManagerId</classname> class.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Subclasses in the identity hierarchy may define additional identity fields until
|
|
the hierarchy becomes non-abstract. In the aforementioned example, <classname>
|
|
Person</classname> defines an identity field <literal>ssn</literal>, <classname>
|
|
Employee</classname> defines additional identity field <literal>userName
|
|
</literal>, and <classname>FullTimeEmployee</classname> adds a final identity
|
|
field, <literal>empId</literal>. However, <classname>Manager</classname> may not
|
|
define any additional identity fields, since it is a subclass of a non-abstract
|
|
class. The hierarchy of identity classes, of course, must match the identity
|
|
field definitions of the persistent class hierarchy.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
It is not necessary for each abstract class to declare identity fields. In the
|
|
previous example, the abstract <classname>Person</classname> and <classname>
|
|
Employee</classname> classes could declare no identity fields, and the first
|
|
concrete subclass <classname>FullTimeEmployee</classname> could define one or
|
|
more identity fields.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
All subclasses of a concrete identity class must be <methodname>equals
|
|
</methodname> and <methodname>hashCode</methodname>-compatible with the
|
|
concrete superclass. This means that in our example, a <classname>ManagerId
|
|
</classname> instance and a <classname>FullTimeEmployeeId</classname> instance
|
|
with the same identity field values should have the same hash code, and should
|
|
compare equal to each other using the <methodname>equals</methodname> method of
|
|
either one. In practice, this requirement reduces to the following coding
|
|
practices:
|
|
</para>
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Use <literal>instanceof</literal> instead of comparing <classname>Class
|
|
</classname> objects in the <methodname>equals</methodname> methods of your
|
|
identity classes.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
An identity class that extends another non-abstract identity class should not
|
|
override <methodname>equals</methodname> or <methodname>hashCode</methodname>.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_overview_pc_callbacks">
|
|
<title>
|
|
Lifecycle Callbacks
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_callbacks">
|
|
<primary>
|
|
lifecycle callbacks
|
|
</primary>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_callbacks">
|
|
<primary>
|
|
persistent classes
|
|
</primary>
|
|
<secondary>
|
|
lifecycle callbacks
|
|
</secondary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<para>
|
|
It is often necessary to perform various actions at different stages of a
|
|
persistent object's lifecycle. JPA includes a variety of callbacks methods for
|
|
monitoring changes in the lifecycle of your persistent objects. These callbacks
|
|
can be defined on the persistent classes themselves and on non-persistent
|
|
listener classes.
|
|
</para>
|
|
<section id="jpa_overview_pc_callbacks_methods">
|
|
<title>
|
|
Callback Methods
|
|
</title>
|
|
<indexterm zone="jpa_overview_pc_callbacks_methods">
|
|
<primary>
|
|
lifecycle callbacks
|
|
</primary>
|
|
<secondary>
|
|
callback methods
|
|
</secondary>
|
|
</indexterm>
|
|
<indexterm zone="jpa_overview_pc_callbacks_methods">
|
|
<primary>
|
|
entity
|
|
</primary>
|
|
<secondary>
|
|
callback methods
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Every persistence event has a corresponding callback method marker. These
|
|
markers are shared between persistent classes and their listeners. You can use
|
|
these markers to designate a method for callback either by annotating that
|
|
method or by listing the method in the XML mapping file for a given class. The
|
|
lifecycle events and their corresponding method markers are:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PrePersist
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PrePersist.html">
|
|
<classname>PrePersist</classname></ulink>: Methods marked with this annotation
|
|
will be invoked before an object is persisted. This could be used for assigning
|
|
primary key values to persistent objects. This is equivalent to the XML element
|
|
tag <literal>pre-persist</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PostPersist
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PostPersist.html">
|
|
<classname>PostPersist</classname></ulink>: Methods marked with this annotation
|
|
will be invoked after an object has transitioned to the persistent state. You
|
|
might want to use such methods to update a screen after a new row is added. This
|
|
is equivalent to the XML element tag <literal>post-persist</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PostLoad
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PostLoad.html">
|
|
<classname>PostLoad</classname></ulink>: Methods marked with this annotation
|
|
will be invoked after all eagerly fetched fields of your class have been loaded
|
|
from the datastore. No other persistent fields can be accessed in this method.
|
|
This is equivalent to the XML element tag <literal>post-load</literal>.
|
|
</para>
|
|
<para>
|
|
<classname>PostLoad</classname> is often used to initialize non-persistent
|
|
fields whose values depend on the values of persistent fields, such as a complex
|
|
data structure.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PreUpdate
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PreUpdate.html">
|
|
<classname>PreUpdate</classname></ulink>: Methods marked with this annotation
|
|
will be invoked just the persistent values in your objects are flushed to the
|
|
datastore. This is equivalent to the XML element tag <literal>
|
|
pre-update</literal>.
|
|
</para>
|
|
<para>
|
|
<classname>PreUpdate</classname> is the complement to <classname>PostLoad
|
|
</classname>. While methods marked with <classname>PostLoad</classname> are most
|
|
often used to initialize non-persistent values from persistent data, methods
|
|
annotated with <classname>PreUpdate</classname> is normally used to set
|
|
persistent fields with information cached in non-persistent data.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PostUpdate
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PostUpdate.html">
|
|
<classname>PostUpdate</classname></ulink>: Methods marked with this annotation
|
|
will be invoked after changes to a given instance have been stored to the
|
|
datastore. This is useful for clearing stale data cached at the application
|
|
layer. This is equivalent to the XML element tag <literal>post-update</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PreRemove
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PreRemove.html">
|
|
<classname>PreRemove</classname></ulink>: Methods marked with this annotation
|
|
will be invoked before an object transactions to the deleted state. Access to
|
|
persistent fields is valid within this method. You might use this method to
|
|
cascade the deletion to related objects based on complex criteria, or to perform
|
|
other cleanup. This is equivalent to the XML element tag <literal>
|
|
pre-remove</literal>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<indexterm>
|
|
<primary>
|
|
PostRemove
|
|
</primary>
|
|
<seealso>
|
|
lifecycle callbacks
|
|
</seealso>
|
|
</indexterm>
|
|
<ulink url="http://java.sun.com/javaee/5/docs/api/javax/persistence/PostRemove.html">
|
|
<classname>PostRemove</classname></ulink>: Methods marked with this annotation
|
|
will be invoked after an object has been marked as to be deleted. This is
|
|
equivalent to the XML element tag <literal>post-remove</literal>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
<section id="jpa_overview_callbacks_using">
|
|
<title>
|
|
Using Callback Methods
|
|
</title>
|
|
<para>
|
|
When declaring callback methods on a persistent class, any method may be used
|
|
which takes no arguments and is not shared with any property access fields.
|
|
Multiple events can be assigned to a single method as well.
|
|
</para>
|
|
<para>
|
|
Below is an example of how to declare callback methods on persistent classes:
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* Example persistent class declaring our entity listener.
|
|
*/
|
|
@Entity
|
|
public class Magazine {
|
|
|
|
@Transient
|
|
private byte[][] data;
|
|
|
|
@ManyToMany
|
|
private List<Photo> photos;
|
|
|
|
@PostLoad
|
|
public void convertPhotos() {
|
|
data = new byte[photos.size()][];
|
|
for (int i = 0; i < photos.size(); i++)
|
|
data[i] = photos.get(i).toByteArray();
|
|
}
|
|
|
|
@PreDelete
|
|
public void logMagazineDeletion() {
|
|
getLog().debug("deleting magazine containing" + photos.size()
|
|
+ " photos.");
|
|
}
|
|
}
|
|
|
|
</programlisting>
|
|
<para>
|
|
In an XML mapping file, we can define the same methods without annotations:
|
|
</para>
|
|
<programlisting>
|
|
<entity class="Magazine">
|
|
<pre-remove>logMagazineDeletion</pre-remove>
|
|
<post-load>convertPhotos</post-load>
|
|
</entity>
|
|
</programlisting>
|
|
<note>
|
|
<para>
|
|
We fully explore persistence metadata annotations and XML in
|
|
<xref linkend="jpa_overview_meta"/>.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
<section id="jpa_overview_entity_listeners_using">
|
|
<title>
|
|
Using Entity Listeners
|
|
</title>
|
|
<para>
|
|
Mixing lifecycle event code into your persistent classes is not always ideal. It
|
|
is often more elegant to handle cross-cutting lifecycle events in a
|
|
non-persistent listener class. JPA allows for this, requiring only that listener
|
|
classes have a public no-arg constructor. Like persistent classes, your listener
|
|
classes can consume any number of callbacks. The callback methods must take in a
|
|
single <classname>java.lang.Object</classname> argument which represents the
|
|
persistent object that triggered the event.
|
|
</para>
|
|
<para>
|
|
Entities can enumerate listeners using the <classname>EntityListeners
|
|
</classname> annotation. This annotation takes an array of listener classes as
|
|
its value.
|
|
</para>
|
|
<para>
|
|
Below is an example of how to declare an entity and its corresponding listener
|
|
classes.
|
|
</para>
|
|
<programlisting>
|
|
/**
|
|
* Example persistent class declaring our entity listener.
|
|
*/
|
|
@Entity
|
|
@EntityListeners({ MagazineLogger.class, ... })
|
|
public class Magazine {
|
|
|
|
// ... //
|
|
}
|
|
|
|
|
|
/**
|
|
* Example entity listener.
|
|
*/
|
|
public class MagazineLogger {
|
|
|
|
@PostPersist
|
|
public void logAddition(Object pc) {
|
|
getLog ().debug ("Added new magazine:" + ((Magazine) pc).getTitle ());
|
|
}
|
|
|
|
|
|
@PreRemove
|
|
public void logDeletion(Object pc) {
|
|
getLog().debug("Removing from circulation:" +
|
|
((Magazine) pc).getTitle());
|
|
}
|
|
}
|
|
</programlisting>
|
|
<para>
|
|
In XML, we define both the listeners and their callback methods as so:
|
|
</para>
|
|
<programlisting>
|
|
<entity class="Magazine">
|
|
<entity-listeners>
|
|
<entity-listener class="MagazineLogger">
|
|
<post-persist>logAddition</post-persist>
|
|
<pre-remove>logDeletion</pre-remove>
|
|
</entity-listener>
|
|
</entity-listeners>
|
|
</entity>
|
|
</programlisting>
|
|
</section>
|
|
<section id="jpa_overview_entity_listeners_exclude">
|
|
<title>
|
|
Entity Listeners Hierarchy
|
|
</title>
|
|
<indexterm zone="jpa_overview_entity_listeners_exclude">
|
|
<primary>
|
|
lifecycle listeners
|
|
</primary>
|
|
<secondary>
|
|
hierarchy
|
|
</secondary>
|
|
</indexterm>
|
|
<para>
|
|
Entity listener methods are invoked in a specific order when a given event is
|
|
fired. So-called <emphasis>default</emphasis> listeners are invoked first: these
|
|
are listeners which have been defined in a package annotation or in the root
|
|
element of XML mapping files. Next, entity listeners are invoked in the order of
|
|
the inheritance hierarchy, with superclass listeners being invoked before
|
|
subclass listeners. Finally, if an entity has multiple listeners for the same
|
|
event, the listeners are invoked in declaration order.
|
|
</para>
|
|
<para>
|
|
You can exclude default listeners and listeners defined in superclasses from the
|
|
invocation chain through the use of two class-level annotations:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<classname>ExcludeDefaultListeners</classname>: This annotation indicates that
|
|
no default listeners will be invoked for this class, or any of its subclasses.
|
|
The XML equivalent is the empty <literal>exclude-default-listeners</literal>
|
|
element.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<classname>ExcludeSuperclassListeners</classname>: This annotation will cause
|
|
OpenJPA to skip invoking any listeners declared in superclasses. The XML
|
|
equivalent is the empty <literal>exclude-superclass-listeners</literal> element.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
<section id="jpa_overview_pc_conclusion">
|
|
<title>
|
|
Conclusions
|
|
</title>
|
|
<para>
|
|
This chapter covered everything you need to know to write persistent class
|
|
definitions in JPA. JPA cannot use your persistent classes, however, until you
|
|
complete one additional step: you must define the persistence metadata. The next
|
|
chapter explores metadata in detail.
|
|
</para>
|
|
</section>
|
|
</chapter>
|