- 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
finalJava modifier for classes, methods and attributes…- A POJO implements the
java.io.SerializableJava 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.xmlfile 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.xmlfile (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 attached 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.PostLoadExample
@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 disabledExtended 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.Basicannotation confirms the persistent nature of a field with the possibility of configuring propertiesExample
@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.Dateorjava.util.Calendarmust 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
enumin 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@javax.persistence.Column(name = "MOTIVE_LABEL", nullable = false, unique = true) // With 'constraint MOTIVE_unique unique(MOTIVE_LABEL)' private String _motive_label;Other properties of
@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.Idannotation 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.Embeddableand@javax.persistence.EmbeddedIdannotations 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_PINabove, primary keys may be generated by the RDBMS (depending upon offered support for that). Strategies are:AUTO(default),IDENTITY,SEQUENCEorTABLE.@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_CASEandJURISDICTIONtables are merged into theCriminal_caseEntity 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 { …
pkJoinColumnsannotation attribute may be omitted here. TheCriminal_caseEntity Bean gets the_jurisdiction_addresspersistent field fromJURISDICTIONtable.@javax.persistence.Column(name = "JURISDICTION_ADDRESS", table = "JURISDICTION") private String _jurisdiction_address;Rules
- The
javax.persistence.SecondaryTablesannotation is used when more than two tables are merged- For Entity Bean relationships, the
javax.persistence.JoinColumnannotation (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.ManyToManyThe 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.OneToOneExample (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.ManyToOnebelowBidirectionality
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
mappeByannotation attribute is similar to theinverse = "true"indicator within Hibernate
@javax.persistence.OneToManyExample (see association between
PrisonerandConvictionin figure below)@javax.persistence.OneToMany(cascade = javax.persistence.CascadeType.REMOVE) // Cascade operations may be setup (no cascade by default) by means ofjavax.persistence.CascadeType@javax.persistence.JoinColumn(name = "PRISON_FILE_NUMBER") private java.util.Set<Conviction> _conviction;
@javax.persistence.ManyToOneExample (see association between
PrisonerandMotivein figure below)@javax.persistence.ManyToOne(optional = false) @javax.persistence.JoinColumn(name = "MOTIVE_NUMBER", referencedColumnName = "MOTIVE_NUMBER") private Motive _incarceration_motive;
@javax.persistence.ManyToManyusing a third-party table (line 2 below)Example (see association between
PrisonerandCriminal_case-offenserole- 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
PrisonerandCriminal_case-participantrole- 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.ManyToManyside loadingBy default, multi-valued associations are ruled by the lazy loading mode (for performance reasons). One may change that as follows (see association from
PrisonertoShortened_sentencein 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 (
Prisoneris 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_numberis a field of thePrisonerEntity Bean):SELECT p._prison_file_number FROM Prisoner p- Arbitrary characters (
_given_nameand_surnameare fields of thePrisonerEntity 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 (
?1parameter represents the first parameterized position) → seeoffensenavigation in figure aboveSELECT p FROM Prisoner p WHERE ?1 MEMBER OF p._offenseLook for all decisions linked to all prisoners (two equivalent solutions) →
_judicial_decisioncorresponds to the navigation fromPrisonertoJudicial_decisionin figure aboveSELECT judicial_decision FROM Prisoner p, IN (p._judicial_decision) judicial_decisionSELECT ELEMENTS(p._judicial_decision) FROM Prisoner pLonger navigation (
_jurisdiction_nameis a field of theCriminal_caseEntity Bean) → seeoffensenavigation 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 aboveUsage
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
DELETEandUPDATEJPQL statements are redundant withremoveandmergemethods within an entity manager. They may however be useful for bulk processingExample
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_TABLEstrategy
- 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.DiscriminatorColumnisDTYPE.- Default value for the
discriminatorTypeattribute of@javax.persistence.DiscriminatorColumnisjavax.persistence.DiscriminatorType.STRING.- Default values for
@javax.persistence.DiscriminatorValueare class names.
TABLE_PER_CLASSstrategy
- 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 { …
JOINEDstrategy
- 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.MappedSuperclassannotation 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.AssociationOverridesExample
@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.).