- Java Persistence API -JPA- (see API ☛) is a specification, which formally describes the way by which Java objects may be persistent when concomitantly used with popular RDBMS (Oracle, MySQL, PostgreSQL, JavaDB…)
- JPA is in essence an API, which is mostly composed of Java annotations
- JPA is intended to be a superset of famous persistence frameworks, Hibernate in particular
- JPA is the underlying technology of Entity Beans in the Java EE technology
- ISO/IEC 9075-1 to 5 standard defining SQL99 and divided into Framework, Foundation, Call Level Interface -CLI-, Persistent Stored Modules et Host Language Bindings
- Update (mainly XML): SQL:2003, SQL:2006 (ISO/IEC 9075-14:2006)
- CLI key implementations:
- Open DataBase Connectivity -ODBC- from Microsoft
- Java DataBase Connectivity -JDBC- ☛
- Oracle Call Interface -OCI- from Oracle (natively)
- Java technologies for persistence: Java DataBase Connectivity -JDBC-, Java Data Objects -JDO-, Java Persistence API -JPA-
- Hibernate
- EclipseLink JPA
- Oracle TopLink
- OpenJPA
- Using JPA at large:
import javax.persistence.*;
- Service Provider Interface -SPI-:
javax.persistence.spi
- A Plain Old Java Object -POJO- is a Java class whose instances are supposed to persist in a database
- A POJO is ruled by constraints: constructor without arguments, normalized getter and setter methods for persistent attributes, no use of the
final
Java modifier for classes, methods and attributes…- A POJO implements the
java.io.Serializable
Java interface- A POJO is declared as persistent in a persistent unit
Entity Beans can be managed through a persistence manager only.
Example Java EE
@javax.persistence.PersistenceContext(unitName = "New_York_City_Penitentiary", type = javax.persistence.PersistenceContextType.TRANSACTION)) private javax.persistence.EntityManager _entityManager; // No instantiation required; this is resource injection...
Example Java SE (
persistence.xml
file must be set up)javax.persistence.EntityManagerFactory _emf = javax.persistence.Persistence.createEntityManagerFactory("New_York_City_Penitentiary"); javax.persistence.EntityManager _entityManager = _emf.createEntityManager();
Example of
persistence.xml
file (Java SE)<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="New_York_City_Penitentiary" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>com.franckbarbier.nycp_java_se.Prisoner</class> <class>com.franckbarbier.nycp_java_se.Shortened_sentence</class> <class>com.franckbarbier.nycp_java_se.Final_discharge</class> <class>com.franckbarbier.nycp_java_se.Conviction</class> <class>com.franckbarbier.nycp_java_se.Motive</class> <class>com.franckbarbier.nycp_java_se.Criminal_case</class> <class>com.franckbarbier.nycp_java_se.Judicial_decision</class> <class>com.franckbarbier.nycp_java_se.Incarceration</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/New_York_City_Penitentiary_database"/> <property name="javax.persistence.jdbc.user" value="FranckBarbier"/> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/> <property name="javax.persistence.jdbc.password" value="FranckBarbier"/> </properties> </persistence-unit> </persistence>
Property setup for a specific persistence provider
<properties> <property name="hibernate.show_sql" value="true"/> </properties>
- When Managed, an Entity Bean is synchronized with the database. All changes made to the Entity Bean lead to appropriate updates at flush/commit time
- When Removed, an Entity Bean is deleted in the database at flush/commit time
- When Detached, no synchronization exists. Transaction rollback or entity manager closing leads to detach Entity Beans
- The Exists state is the common Java mode
_entityManager.persist(prisoner);
Prisoner updated_prisoner = (Prisoner) _entityManager.merge(prisoner); // 'updated_prisoner' is managed while 'prisoner' is no longer managed
_entityManager.remove(prisoner);
Prisoner prisoner = _entityManager.find(Prisoner.class,primary_key);
Prisoner prisoner = _entityManager.getReference(Prisoner.class,primary_key);
_entityManager.refresh(prisoner); // Re-synchronization with the database's real-time state. All modifications are lost
Synchronization occurs through the possible use of the following annotations attaced to on-purpose Java methods.
@javax.persistence.PrePersist
@javax.persistence.PostPersist
@javax.persistence.PreRemove
@javax.persistence.PostRemove
@javax.persistence.PreUpdate
@javax.persistence.PostUpdate
@javax.persistence.PostLoad
Example
@javax.persistence.PostLoad public void just_loaded() { System.out.println(this.toString() + " just loaded..."); }
_entityManager.clear(); // All managed Entity Beans are detached. All modifications are lost
_entityManager.flush(); // All managed Entity Beans are detached. All modifications will be definitely made at commit time
Transaction support
A transaction support is injected as resource as in the following example (BMT standing for Bean-Managed Transaction).
@javax.annotation.Resource private javax.transaction.UserTransaction _userTransaction; // No instantiation required!
JTS (standing for Java Transaction Service) is by default enabled in the persistence unit; it can be disabled as follows.
<persistence-unit name="New_York_City_Penitentiary" transaction-type="RESOURCE_LOCAL"> … <non-jta-data-source>New_York_City_Penitentiary</non-jta-data-source> … </persistence-unit>
Managing transactions manually is done as follows.
// Transactions are managed in the Bean-Managed Transaction mode (Java SE for instance): private javax.persistence.EntityTransaction _entityTransaction = _entityManager.getTransaction();
Dealing with transactions (Bean-Managed Transaction mode)
Transaction-scoped persistence context (
javax.persistence.PersistenceContextType.TRANSACTION
)_userTransaction.begin(); // '_entityManager' is enabled _entityManager.persist(prisoner); assert(_entityManager.contains(prisoner) == true); _userTransaction.commit(); // '_entityManager' is disabled
Extended persistence context (
javax.persistence.PersistenceContextType.EXTENDED
)_userTransaction.begin(); _entityManager.joinTransaction(); _entityManager.persist(prisoner); // It may also be called outside a transaction scope _userTransaction.commit();
Building a JPA application or simple module is mostly concerned with creating Entity Beans that map to tables in a database. However, this mapping has not to be, in any case, a one-to-one mapping, i.e., 1 table does not systematically amount to 1 and only 1 Entity Bean.
The mapping is thus ruled by creation processes, key and recurrent navigation between objects, performance with suitable dependency loading (lazy or eager modes).
Constraints (not illustrated in examples)
- Entity Beans requires a constructor without arguments
- Entity Beans requires getter and setter Java methods for persistent fields
Simple Entity Bean
Basic annotations
@javax.persistence.Entity
: this annotation makes a Java class an Entity Bean@javax.persistence.Table
: database mappingExample
@javax.persistence.Entity(name = "My_prisoner") // Class name by default when 'name' is not used @javax.persistence.Table(name = "Prisoner") // It is optional when the table name is equal to the Java class name public class Prisoner implements java.io.Serializable { …
Persistent field
- All non-static, non-transient fields are by default persistent unless annotated by
@javax.persistence.Transient
.- The
@javax.persistence.Basic
annotation confirms the persistent nature of a field with the possibility of configuring properties.Example
@javax.persistence.Basic(fetch=javax.persistence.FetchType.LAZY /* By default */, optional=true) // The other value for the fetch attribute is 'javax.persistence.FetchType.EAGER' @javax.persistence.Column(name = "CUSTOMER_NICKNAME") private String _customer_nickname;
Temporal persistent field
- Fields of type
java.util.Date
orjava.util.Calendar
must be annotated with@javax.persistence.Temporal
.Example
@javax.persistence.Column(name = "DATE_OF_INCARCERATION")
@javax.persistence.Temporal(javax.persistence.TemporalType.DATE)
private java.util.Date _date_of_incarceration;Enumerated persistent field
- Fields of type
enum
in Java may be used in conjunction with JPA with the help of@javax.persistence.Enumerated
.Example (Java)
public enum Fire_truck_statuses {Idle, Dispatched, Arrived , Blocked, Breakdown}
Example -JPA-
@javax.persistence.Column(name = "FIRE_TRUCK_STATUS")
@javax.persistence.Enumerated(javax.persistence.EnumType.STRING)
private Fire_truck_statuses _fire_truck_status;Example (SQL)
create table BCMS_session_Fire_truck( … FIRE_TRUCK_STATUS varchar(10) constraint FIRE_TRUCK_STATUS_CHECK check (fire_truck_status IN ('Idle', 'Dispatched', 'Arrived', 'Blocked', 'Breakdown')), …
Embeddable and embedded Entity Beans
Embeddable Entity Beans do not map to tables. Instead, they later become field types in enclosing Entity Beans.
@javax.persistence.Embeddable public class Address … @javax.persistence.Column(name = "ZIP_CODE", length = 5) private String _zip_code; … … @javax.persistence.Entity // Table name must be 'Customer' public class Customer implements java.io.Serializable { … @javax.persistence.Embedded @javax.persistence.AttributeOverrides({@javax.persistence.AttributeOverride(name = "_zip_code", column = @javax.persistence.Column(name = "ZIP_CODE_OF_CUSTOMER_INVOICING_ADDRESS"))}) private Address _invoicing_address; @javax.persistence.Embedded private Address _shipping_address; … …
More about
@javax.persistence.Column
Other properties of@javax.persistence.Column(name = "MOTIVE_LABEL", nullable = false, unique = true) // With 'constraint MOTIVE_unique unique(MOTIVE_LABEL)' private String _motive_label;
@javax.persistence.Column
:
insertable
(default value istrue
)updatable
(default value istrue
)Primary key Simple primary keys are based on elementary types (
long
,Long
,String
…). The@javax.persistence.Id
annotation is necessary.@javax.persistence.Entity // Table name must be 'Customer' public class Customer implements java.io.Serializable { @javax.persistence.Id @javax.persistence.Column(name = "CUSTOMER_PIN") // With 'constraint CUSTOMER_key primary key(CUSTOMER_PIN)' private String _customer_PIN; …
Composite primary key
Composite primary keys are based on non-elementary types that require the construction of devoted classes. The
@javax.persistence.Embeddable
and@javax.persistence.EmbeddedId
annotations are necessary.@javax.persistence.Embeddable public class Criminal_casePK implements java.io.Serializable { @javax.persistence.Basic(optional = false) @javax.persistence.Column(name = "CRIMINAL_CASE_NUMBER") private String _criminal_case_number; @javax.persistence.Basic(optional = false) @javax.persistence.Column(name = "JURISDICTION_NAME") private String _jurisdiction_name; … … @javax.persistence.Entity @javax.persistence.Table(name = "CRIMINAL_CASE") // Optional since class name is equal to table name public class Criminal_case implements java.io.Serializable { @javax.persistence.EmbeddedId // With 'constraint CRIMINAL_CASE_key primary key(CRIMINAL_CASE_NUMBER,JURISDICTION_NAME)' private Criminal_casePK _criminal_casePK; … …
Alternative method
public class Criminal_casePK implements java.io.Serializable { … // '@javax.persistence.Embeddable' is no longer used! … @javax.persistence.Entity @javax.persistence.IdClass(Criminal_casePK.class) @javax.persistence.Table(name = "CRIMINAL_CASE") // Optional since class name is equal to table name public class Criminal_case implements java.io.Serializable { …
Business versus generated primary key
Instead of having primary keys based on business fields, e.g.,
CUSTOMER_PIN
above, primary keys may be generated by the RDBMS (depending upon offered support for that). Strategies are:AUTO
(default),IDENTITY
,SEQUENCE
orTABLE
.@javax.persistence.Entity public class Order implements java.io.Serializable { @javax.persistence.Id @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY) @javax.persistence.Column(name = "ORDER_ID") // With 'create table ORDER(ORDER_ID integer generated always as identity, …);' private Integer _id; …
Alternative strategy
@javax.persistence.Id @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.SEQUENCE, generator = "MY_GENERATOR") @javax.persistence.Column(name = "ORDER_ID") // With 'create sequence MY_GENERATOR;' private Integer _id;
For instance, the
CRIMINAL_CASE
andJURISDICTION
tables are merged into theCriminal_case
Entity Bean.@javax.persistence.Entity @javax.persistence.Table(name = "CRIMINAL_CASE") // Optional since class name is equal to table name @javax.persistence.SecondaryTable(name = "JURISDICTION", pkJoinColumns = {@javax.persistence.PrimaryKeyJoinColumn(name = "JURISDICTION_NAME")}) public class Criminal_case implements java.io.Serializable { …
pkJoinColumns
annotation attribute may be omitted here. TheCriminal_case
Entity Bean gets the_jurisdiction_address
persistent field fromJURISDICTION
table.@javax.persistence.Column(name = "JURISDICTION_ADDRESS", table = "JURISDICTION") private String _jurisdiction_address;
Rules
- The
javax.persistence.SecondaryTables
annotation is used when more than two tables are merged- For Entity Bean relationships, the
javax.persistence.JoinColumn
annotation (see below) by default applies to the base table (i.e.,CRIMINAL_CASE
). To apply to the secondary table (i.e.,JURISDICTION
), the latter must be named
The following JPA annotations are available to manage Entity Bean relationships (foreign keys in tables).
@javax.persistence.OneToOne
@javax.persistence.OneToMany
@javax.persistence.ManyToOne
@javax.persistence.ManyToMany
The following Java interfaces can be used to manage association ends with the many role.
java.util.Set<E>
java.util.List<E>
java.util.Map<K,V>
@javax.persistence.OneToOne
Example (two related entities are linked by means of their primary keys)
@javax.persistence.Entity // Table name must be 'Customer' public class Customer implements java.io.Serializable { @javax.persistence.Id @javax.persistence.Column(name = "CUSTOMER_PIN") // With 'constraint CUSTOMER_key primary key(CUSTOMER_PIN)' private String _customer_PIN; @javax.persistence.OneToOne @javax.persistence.PrimaryKeyJoinColumn private Client _client; // Entity Bean 'Client' offers a primary key similar to '_customer_PIN' in 'Customer' Entity Bean …
Example (default mode: two related entities are linked by means of a foreign key while this one is a priori unique in the target entity)
@javax.persistence.Entity public class Order implements java.io.Serializable { @javax.persistence.Id @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY) @javax.persistence.Column(name = "ORDER_ID") // With 'create table ORDER(ORDER_ID integer generated always as identity, …);' private Integer _id; @javax.persistence.OneToOne // An order leads to one and only one invoice @javax.persistence.JoinColumn(name = "ORDER_ID", referencedColumnName = "INVOICE_ID") private Invoice _invoice; …
Example (two related entities are linked by means of a third-party table)
This case is similar to
@javax.persistence.ManyToOne
below.Bidirectionality
Entity Bean relationships can be either mono-directional or bidirectional.
Example of bidirectionality using
@javax.persistence.OneToOne
@javax.persistence.Entity public class Invoice implements java.io.Serializable { … @javax.persistence.OneToOne(mappedBy = "_invoice") private Order _order; // Caution: JPA *DOES NOT* use this side to interact with the RDBMS. Moreover, the mutual consistency has to be maintained by the developer …
Note: the
mappeBy
annotation attribute is similar to theinverse = "true"
indicator within Hibernate.
@javax.persistence.OneToMany
Example (see association between
Prisoner
andConviction
in figure below)@javax.persistence.OneToMany(cascade = javax.persistence.CascadeType.REMOVE) // Cascade operations may be setup (no cascade by default) by means of
javax.persistence.CascadeType
@javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER") private java.util.Set<Conviction> _conviction;
@javax.persistence.ManyToOne
Example (see association between
Prisoner
andMotive
in figure below)@javax.persistence.ManyToOne(optional = false) @javax.persistence.JoinColumn(name = "MOTIVE_NUMBER", referencedColumnName = "MOTIVE_NUMBER") private Motive _incarceration_motive;
@javax.persistence.ManyToMany
using a third-party table (line 2 below)Example (see association between
Prisoner
andCriminal_case
-offense
role- in figure below)@javax.persistence.ManyToMany(/* cascade = javax.persistence.CascadeType.MERGE */) // 'Prisoner' owns the relationship
@javax.persistence.JoinTable(name = "PRISONER_CRIMINAL_CASE", joinColumns = { @javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER", referencedColumnName = "PRISON_FILE_NUMBER")}, // 'CRIMINAL_CASE_NUMBER'-'JURISDICTION_NAME' is a foreign key in 'PRISONER_CRIMINAL_CASE' to 'Criminal_case': inverseJoinColumns = { @javax.persistence.JoinColumn(name = "CRIMINAL_CASE_NUMBER", referencedColumnName = "CRIMINAL_CASE_NUMBER"), @javax.persistence.JoinColumn(name = "JURISDICTION_NAME", referencedColumnName = "JURISDICTION_NAME") }) private java.util.Set<Criminal_case> _offense;Bidirectionality
Example (see association between
Prisoner
andCriminal_case
-participant
role- in figure below)@javax.persistence.ManyToMany(mappedBy = "_offense") // 'Criminal_case' does not own the relationship (cascading operations with 'javax.persistence.CascadeType' is a priori useless) private java.util.Set<Prisoner> _participant; // Caution: JPA *DOES NOT* use this side to interact with the RDBMS. Moreover, the mutual consistency has to be maintained by the developer
@javax.persistence.ManyToMany
side loadingBy default, multi-valued associations are ruled by the lazy loading mode (for performance reasons). One may change that as follows (see association from
Prisoner
toShortened_sentence
in figure below).@javax.persistence.OneToMany(cascade = javax.persistence.CascadeType.REMOVE, fetch = javax.persistence.FetchType.EAGER) // 'EAGER': each time, a 'Prisoner' Entity Bean is loaded (with 'find' for instance), all of its 'Shortened_sentence' Entity Beans are concomitantly loaded. // Instead, the 'lazy' mode leads to the loading of these when one accesses the collection itself using 'get_shortened_sentence' @javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER") private java.util.Set<Shortened_sentence> _shortened_sentence;
Principles
- JPQL statements are translated by a JPA engine into native SQL statements.
- JPQL statements are based on the logical Entity Bean dependencies and not on the database table dependencies.
- JPQL has been mainly inspired by its ancestor EJB-QL, which itself has been inspired by many SQL-like languages: OQL (from ODMG), JDOQL and Hibernate SQL (a.k.a. HQL).
Example (dependency schema between Entity Beans)
Basic requests
- Computing a single value:
SELECT COUNT(p) FROM Prisoner AS p
.- Computing a set of objects (
Prisoner
is the name of an Entity Bean; it is not a table name):SELECT OBJECT(p) FROM Prisoner AS p
(simpler form:SELECT p FROM Prisoner p
).- Computing a set of attributes (
_prison_file_number
is a field of thePrisoner
Entity Bean):SELECT p._prison_file_number FROM Prisoner p
.- Arbitrary characters (
_given_name
and_surname
are fields of thePrisoner
Entity Bean):SELECT p._given_name,p._surname FROM Prisoner p WHERE p._prison_file_number LIKE '19%'
(%
in JPQL is equivalent to*
in file system while_
is equivalent to?
in file system).Advanced requests
Request
Prisoners “under remand”, i.e., prisoners for which no conviction decision has been taken.
SQL-like style
Native queries are standard SQL queries. They do not rely on Entity Beans.
Declaration
@javax.persistence.NamedNativeQuery(name = "Prisoner.Under_remand_SQL", query = "SELECT * FROM Prisoner WHERE prison_file_number NOT IN (SELECT prison_file_number FROM Conviction)")
Usage
for (Object o : _entityManager.createNamedQuery("Prisoner.Under_remand_SQL").getResultList()) { try { Object[] prisoner_properties = (Object[]) o; System.out.print("Under remand: - "); for (int i = 0; i < prisoner_properties.length; i++) { System.out.print(prisoner_properties[i] + " - "); } System.out.println(); } catch (ClassCastException cce) { // The type of 'o' is not 'Object[]', so? } }
JPQL style (♡)
@javax.persistence.Entity(name = "MY_PRISONER") @javax.persistence.Table(name = "PRISONER") @javax.persistence.SecondaryTable(name = "INCARCERATION", pkJoinColumns = {@javax.persistence.PrimaryKeyJoinColumn(name = "PRISON_FILE_NUMBER")}) @javax.persistence.NamedNativeQuery(name = "Prisoner.Under_remand_SQL", query = "SELECT * FROM Prisoner WHERE prison_file_number NOT IN (SELECT prison_file_number FROM Conviction)") @javax.persistence.NamedQueries({@javax.persistence.NamedQuery(name = "Prisoner.All_JPQL", query = "SELECT p FROM Prisoner"), @javax.persistence.NamedQuery(name = "Prisoner.Under_remand_JPQL", query = "SELECT p FROM Prisoner WHERE p._conviction IS EMPTY") }) public class Prisoner implements java.io.Serializable { …
The power of JPQL relies on the strong utilization of navigations between Entity Beans.
Example (collection-based requests)
Look for prisoners who are involved in a given criminal case (
?1
parameter represents the first parameterized position) → seeoffense
navigation in figure aboveSELECT p FROM Prisoner p WHERE ?1 MEMBER OF p._offense
Look for all decisions linked to all prisoners (two equivalent solutions) →
_judicial_decision
corresponds to the navigation fromPrisoner
toJudicial_decision
in figure aboveSELECT judicial_decision FROM Prisoner p, IN (p._judicial_decision) judicial_decision
SELECT ELEMENTS(p._judicial_decision) FROM Prisoner p
Longer navigation (
_jurisdiction_name
is a field of theCriminal_case
Entity Bean) → seeoffense
navigation in figure aboveSELECT criminal_case FROM Prisoner p, IN(p._offense) criminal_case, IN(criminal_case._jurisdiction_name) jurisdiction_name WHERE jurisdiction_name = 'Pau'
Request
Prisoners who are not involved in a given criminal case (the latter is a parameter in the named query, i.e.,
:criminal_case
).Declaration
@javax.persistence.NamedQuery(name = "Prisoner.Not_involved_in_criminal_case_V1", query = "SELECT p FROM Prisoner p WHERE :criminal_case NOT MEMBER OF p._offense"), // See 'offense' navigation in figure above @javax.persistence.NamedQuery(name = "Prisoner.Not_involved_in_criminal_case_V2", query = "SELECT p1 FROM Prisoner p1 WHERE p1 NOT IN (SELECT p2 FROM Criminal_case c INNER JOIN c._participant p2 WHERE c = :criminal_case)") // See 'participant' navigation in figure above
Usage
public java.util.Collection<persistence.Prisoner> non_participants(persistence.Criminal_case criminal_case) { assert (_entityManager != null); criminal_case = _entityManager.find(persistence.Criminal_case.class, new persistence.Criminal_casePK(criminal_case.get_criminal_case_number(), criminal_case.get_jurisdiction_name())); return _entityManager.createNamedQuery("Prisoner.Not_involved_in_criminal_case_V1").setParameter("criminal_case", criminal_case).getResultList(); }
Beyond
SELECT
DELETE
andUPDATE
JPQL statements are redundant withremove
andmerge
methods within an entity manager. They may however be useful for bulk processing.Example
DELETE FROM Prisoner p WHERE p._prison_file_number IN ('1993','1995','2001')
UPDATE Prisoner p SET p._given_name = 'undefined given name' WHERE p._surname IS NULL
Overview
JPA enables the management of inheritance based on three strategies.
- Several Entity Beans involved in an inheritance hierarchy map to only one table in the database (
SINGLE_TABLE
): this is the default mode.- Only concrete Entity Beans have their own mapping tables without any factorization table (
TABLE_PER_CLASS
).- All Entity Beans have their own mapping tables (
JOINED
) including abstract and intermediate classes.Inheritance in JPA is a support for polymorphic requests.
SINGLE_TABLE
strategy
- A dedicated column is required to distinguish instances from each other.
- The main disadvantage of this strategy is the grouping of unnecessary properties in the single table (like Hibernate).
- The main advantage is higher performance.
Example
Mother class
@javax.persistence.Inheritance @javax.persistence.DiscriminatorColumn(name = "SEX", discriminatorType = javax.persistence.DiscriminatorType.CHAR) abstract public class Human_being implements java.io.Serializable { …
Daughter class
@javax.persistence.DiscriminatorValue('1') public class Male extends Human_being { …
- Default value for the name attribute for
@javax.persistence.DiscriminatorColumn
isDTYPE
.- Default value for the
discriminatorType
attribute of@javax.persistence.DiscriminatorColumn
isjavax.persistence.DiscriminatorType.STRING
.- Default values for
@javax.persistence.DiscriminatorValue
are class names.
TABLE_PER_CLASS
strategy
- Abstract Entity Beans have no corresponding tables in the database (associations with such Entity Beans are impossible!).
- The main disadvantage is lower performance based on table union for polymorphic requests.
- The main advantage is higher performance when inserting rows.
Example
Mother class
@javax.persistence.Inheritance(strategy = javax.persistence.InheritanceType.TABLE_PER_CLASS) abstract public class Human_being implements java.io.Serializable { …
Daughter class
// No special annotation is required! public class Male extends Human_being { …
JOINED
strategy
- A dedicated column is required to distinguish instances from each other (default is
DTYPE
).- The main disadvantage is lower performance.
- The main advantage is a transparent support for polymorphism.
Example
Mother class
@javax.persistence.Inheritance(strategy = javax.persistence.InheritanceType.JOINED) @javax.persistence.DiscriminatorColumn(name = "DECISION_TYPE_NUMBER", discriminatorType = javax.persistence.DiscriminatorType.STRING) abstract public class Judicial_decision implements java.io.Serializable { …
Daughter class
@javax.persistence.DiscriminatorValue(Conviction.DECISION_TYPE_NUMBER) public class Conviction extends Judicial_decision { public static final String DECISION_TYPE_NUMBER = "1";
Utility annotations
The
@javax.persistence.MappedSuperclass
annotation is used for factorizing JPA properties in a utility class but not for setting up inheritance from the database viewpoint (no concomitant use of@javax.persistence.Entity
) is allowed!Example
@javax.persistence.MappedSuperclass // No table is associated with this class... // It just serves as factorization for inheriting classes public class Customer implements java.io.Serializable { @javax.persistence.Id @javax.persistence.Column(name = "CUSTOMER_PIN") // With 'constraint CUSTOMER_key primary key(CUSTOMER_PIN)' private String _customer_PIN; … @javax.persistence.OneToMany private java.util.Collection<Order> _order; …
Other utility annotations
@javax.persistence.AttributeOverride
@javax.persistence.AttributeOverrides
@javax.persistence.AssociationOverride
@javax.persistence.AssociationOverrides
Example
@javax.persistence.Entity @javax.persistence.AttributeOverride(name="_customer_PIN",column=@javax.persistence.Column(name="SPECIAL_CUSTOMER_ID")) @javax.persistence.AssociationOverride(name="_order",joinColumns=@javax.persistence.JoinColumn(name="SPECIAL_CUSTOMER_ID")) public class Special_customer extends Customer { …
javax.persistence.EntityManagerFactory
interface offers a getMetamodel
method
that returns an instance of the Metamodel
interface for dealing with the database's metadata.
Metamodel
,
one may dynamically discover the structure of the database (which tables? Which relationships? Etc.).