Specification: Jakarta Persistence Version: 3.2.0-DRAFT02 Status: DRAFT Release: February 29, 2024
Copyright (c) 2019, 2024 Eclipse Foundation.
Eclipse Foundation Specification License
By using and/or copying this document, or the Eclipse Foundation document from which this statement is linked, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
Permission to copy, and distribute the contents of this document, or the Eclipse Foundation document from which this statement is linked, in any medium for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the document, or portions thereof, that you use:
-
link or URL to the original Eclipse Foundation document.
-
All existing copyright notices, or if one does not exist, a notice (hypertext is preferred, but a textual representation is permitted) of the form:
"Copyright (c) [$date-of-document] Eclipse Foundation, Inc. [$url to this license]"
Inclusion of the full text of this NOTICE must be provided. We request that authorship attribution be provided in any software, documents, or other items or products that you create pursuant to the implementation of the contents of this document, or any portion thereof.
No right to create modifications or derivatives of Eclipse Foundation documents is granted pursuant to this license, except anyone may prepare and distribute derivative works and portions of this document in software that implements the specification, in supporting materials accompanying such software, and in documentation of such software, PROVIDED that all such works include the notice below. HOWEVER, the publication of derivative works of this document for use as a technical specification is expressly prohibited.
The notice is:
Copyright (c) 2018 Eclipse Foundation. This software or document includes material copied from or derived from [title and URI of the Eclipse Foundation specification document].
Disclaimers
THIS DOCUMENT IS PROVIDED "AS IS," AND THE COPYRIGHT HOLDERS AND THE ECLIPSE FOUNDATION MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
THE COPYRIGHT HOLDERS AND THE ECLIPSE FOUNDATION WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF.
The name and trademarks of the copyright holders or the Eclipse Foundation may NOT be used in advertising or publicity pertaining to this document or its contents without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders.
1. Introduction
This document is the specification of the Jakarta API for the management of persistence and object/relational mapping in the Jakarta EE and Java SE platforms. The technical objective of this work is to provide a standard object/relational mapping facility for the Java application developer using a Java domain model to manage data held in a relational database.
-
The Jakarta Persistence 3.1 specification is the first release with new features and enhancements after the specification was moved to the Eclipse Foundation.
-
The Jakarta Persistence 3.0 specification was the first release after moving the project to Eclipse Foundation. All APIs were moved from the package
javax.*
to the packagejakarta.*
. Every property name containingjavax
was renamed so thatjavax
is replaced withjakarta
. -
The Java Persistence 2.2 specification enhanced the API with support for repeating annotations; injection into attribute converters; support for mapping the
LocalDate
,LocalTime
,LocalDateTime
,OffsetTime
, andOffsetDateTime
types fromjava.time
; and methods to retrieve the results ofQuery
andTypedQuery
as streams. -
The Java Persistence 2.1 specification added support for schema generation, type conversion methods, use of entity graphs in queries and find operations, unsynchronized persistence contexts, stored procedure invocation, and injection into entity listener classes. It also included enhancements to the query language, the Criteria API, and to the mapping of native queries.
1.1. Authorship
The Jakarta Persistence Specification incorporates work done over two decades by the EJB 3.0 expert group, the Java Persistence 2.0, 2.1, and 2.2 expert groups, under the aegis of the Java Community Process, and by the Jakarta Persistence project at the Eclipse Foundation.
1.2. Document Conventions
Regular serif font is used for information that is prescriptive under this specification.
Italic serif font is used for paragraphs that contain descriptive information, such as notes describing typical use, or notes clarifying the text with prescriptive specification.
Monospaced font
is used for code examples and to specify the BNF of the
Jakarta Persistence query language.
This document defines the semantics of a set of Java language annotations. An XML descriptor (as specified in Chapter 12) may be used as an alternative to annotations or to augment or override annotations. The elements of this descriptor mirror the annotations and have identical semantics to the corresponding annotations. When semantic requirements are written in terms of annotations, it should be understood that the same semantics apply to the corresponding elements of the XML descriptor.
2. Entities
An entity is a lightweight persistent domain object.[1] Entities support inheritance, polymorphic associations, and polymorphic queries.
The primary programming artifact is the entity class. An entity class may make use of auxiliary classes that serve as helper classes or that are used to represent the state of the entity.
This chapter describes requirements on entity classes and instances.
2.1. The Entity Class
The entity class must be annotated with the Entity
annotation or
declared as an entity in the XML descriptor.
-
The entity class must be a top-level class or a static inner class. An enum, record, or interface may not be designated as an entity.
-
The entity class must have a public or protected constructor with no parameters, which is called by the persistence provider runtime to instantiate the entity.[2] The entity class may have additional constructors for use by the application.
-
The entity class must be non-final. Every method and persistent instance variable of the entity class must be non-final.
An entity might be an abstract class, or it might be a concrete class. An entity may extend a non-entity class, or it may extend another entity class. A non-entity class may extend an entity class.
The persistent state of an entity is represented by instance variables, which may correspond to JavaBeans properties. An instance variable may be directly accessed only within the methods of the entity, by the entity instance itself. An instance variable of an entity must not be directly accessed by a client of the entity. The state of the entity is available to clients only through the methods of the entity—that is, via accessor (getter/setter) methods, or via other business methods.
2.2. Persistent Fields and Properties
The persistent state of an entity is accessed by the persistence provider runtime via either:
-
property access using JavaBeans-style property accessors, or
-
field access, that is, direct access to instance variables.
The instance variables of a class must have private, protected, or package visibility, independent of whether field access or property access is used. When property access is used, the property accessor methods must be public or protected.
The type of a persistent field or property of an entity class may be:
-
any basic type listed below in Section 2.6, including any Java
enum
type, -
an entity type or a collection of some entity type, as specified in Section 2.11,
-
an embeddable class, as defined in Section 2.7, or
-
a collection of a basic type or embeddable type, as specified in Section 2.8.
Object/relational mapping metadata may be specified to customize the object/relational mapping and the loading and storing of the entity state and relationships, as specified in Chapter 11.
The placement of object/relational mapping annotations depends on whether property access or field access is used:
-
When field access is used, mapping annotations must be placed on instance variables, and the persistence provider runtime accesses instance variables directly. Every non-
transient
instance variable not annotated with theTransient
annotation is persistent. -
When property-based access is used, mapping annotations must be placed on getter methods[3], and the persistence provider runtime accesses persistent state via the property accessor methods. Every property not annotated with the
Transient
annotation is persistent.
Mapping annotations must not be applied to fields or properties marked
transient
or Transient
, since those fields and properties are not
persistent.
Whether property access, field access, or a mix of the two options is used by the provider to access the state of a given entity class or entity hierarchy is determined by the rules defined in Section 2.3.
Terminology Note: The persistent fields and properties of an entity class are generically referred to in this document as “attributes” of the class. |
Collection-valued persistent fields and properties must be defined in
terms of one of the following collection-valued interfaces, regardless
of whether the entity class otherwise adheres to the JavaBeans method
conventions noted below, and of whether field or property access is used:
java.util.Collection
, java.util.Set
, java.util.List
[4],
java.util.Map
.
Use of the generic variants of these collection types is strongly encouraged,
for example, Set<Order>
is preferred to the raw type Set
.
Terminology Note: The terms “collection” and “collection-valued” are used
in this specification to denote any of the above types, unless further
qualified. In cases where a java.util.Collection type (or one of its
subtypes) is to be distinguished, the type is identified as such. The
terms “map” and “map collection” are used to denote to a collection of
type java.util.Map .
|
A collection implementation type such as HashSet
or ArrayList
may be
used by the application to initialize a collection-valued field or property
before the entity is made persistent. Once the entity becomes managed
(or detached), subsequent access to the collection must be through the
interface type.
2.2.1. Persistent Attribute Type
The enumeration jakarta.persistence.metamodel.Attribute.PersistentAttributeType
defines a classification of persistent entity attributes: BASIC
for
basic attributes, EMBEDDED
for embedded attributes, ELEMENT_COLLECTION
for element collections, and MANY_TO_ONE
, ONE_TO_ONE
, ONE_TO_MANY
,
and MANY_TO_MANY
for associations of the indicated multiplicity.
Each persistent attribute of an entity belongs to exactly one of the
listed types.
It is an error for an attribute of an entity to be annotated with
mapping annotations indicating conflicting persistent attribute types.
For example, an field may not be annotated @Basic @Embedded
,
@ManyToOne @ElementCollection
, or @OneToOne @ManyToMany
. The
persistence provider must detect such contradictory combinations of
mapping annotations and report the error.[5]
2.2.2. Property Access
When property access is used, persistent properties of the entity class
must follow the method signature conventions for JavaBeans read/write
properties, as defined by the JavaBeans Introspector
class. For every
persistent property property
of type T
of the entity, there must be
a getter method, getProperty
, and setter method setProperty
. For
boolean properties, isProperty
may be used as an alternative name for
the getter method.[6]
For single-valued persistent properties, these method signatures are:
T getProperty()
void setProperty(T t)
For collection-valued persistent properties, the type T
in the method
signatures above must be one of the collection interface types listed
above in Section 2.2.
In addition to returning and setting the persistent state of the entity instance, a property accessor method may contain additional logic, for example, logic to perform validation. The persistence provider runtime triggers execution of this logic when property-based access is used.
Therefore, caution should be exercised in adding business logic to accessor methods when property access is used. The order in which the persistence provider runtime calls these methods when loading or storing persistent state is not defined. Logic contained in such methods should therefore not rely on any specific invocation order.
If property access is used and lazy fetching is specified, portable applications should not directly access the entity state underlying the property methods of managed instances until after it has been fetched by the persistence provider.[7]
If a persistence context is joined to a transaction, runtime exceptions
thrown by property accessor methods cause the current transaction to be
marked for rollback; any exception thrown by such methods when called by
the persistence runtime to load or store persistent state causes the
persistence runtime to mark the current transaction for rollback and to
throw a PersistenceException
wrapping the application exception.
An entity subclass may override a property accessor method inherited from a superclass. However, portable applications must not override the object/relational mapping metadata applied to the persistent fields and properties of entity superclasses.
For example:
@Entity
public class Customer implements Serializable {
private Long id;
private String name;
private Address address;
private Collection<Order> orders = new HashSet();
private Set<PhoneNumber> phones = new HashSet();
// No-arg constructor
public Customer() {}
@Id // property access is used
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@OneToMany
public Collection<Order> getOrders() {
return orders;
}
public void setOrders(Collection<Order> orders) {
this.orders = orders;
}
@ManyToMany
public Set<PhoneNumber> getPhones() {
return phones;
}
public void setPhones(Set<PhoneNumber> phones) {
this.phones = phones;
}
// Business method to add a phone number to the customer
public void addPhone(PhoneNumber phone) {
this.getPhones().add(phone);
// Update the phone entity instance to refer to this customer
phone.addCustomer(this);
}
}
2.3. Access Type
An access type determines how the persistence provider runtime reads
and writes the persistent state of an entity from and to an instance of
the entity class, as specified above in Section 2.2.
AccessType
enumerates the two possibilities:
public enum AccessType {
FIELD,
PROPERTY
}
The access type for a persistent attribute depends on the placement of
object/relational mapping annotations in the entity class, and may be
explicitly overridden via use of the Access
annotation defined in
Section 11.1.1.
2.3.1. Default Access Type
By default, a single access type (FIELD
or PROPERTY
) is inferred for
an entity hierarchy. The default access type of an entity hierarchy is
determined by the placement of mapping annotations on the attributes of
the entity classes and mapped superclasses of the entity hierarchy which
do not explicitly specify an access type.
-
If mapping annotations are placed on instance variables,
FIELD
access is inferred. -
If mapping annotations are placed on getter methods,
PROPERTY
access is inferred.
An access type may be explicitly specified by means of the Access
annotation[8], as described
below in Section 2.3.2.
Every class in an entity hierarchy whose access type is defaulted in this
way must be consistent in its placement of mapping annotations on either
fields or properties, such that a single, consistent default access type
applies within the hierarchy. Any embeddable class used by an entity within
the hierarchy has the same access type as the default access type of the
hierarchy unless the Access
annotation is specified, as defined below.
It is an error if a default access type cannot be determined and an access
type is not explicitly specified by a class-level Access
annotation or
the XML descriptor. The behavior of applications which mix the placement
of mapping annotations on fields and properties within an entity hierarchy
without explicitly specifying the class-level Access
annotation is
undefined.[9]
2.3.2. Explicit Access Type
The access type of an individual entity class, mapped superclass, or
embeddable class may be specified for that class, independent of the
default for the entity hierarchy to which it belongs, by annotating the
class with the Access
annotation.
-
When
Access(FIELD)
is applied to an entity class, mapped superclass, or embeddable class, mapping annotations may be placed on the instance variables of that class, and the persistence provider runtime accesses persistent state via direct access to the instance variables declared by the class. Every non-transient
instance variable not annotated with theTransient
annotation is persistent. -
When
Access(PROPERTY)
is applied to an entity class, mapped superclass, or embeddable class, mapping annotations may be placed on the properties of that class, and the persistence provider runtime accesses persistent state via the properties declared by that class. Every property not annotated with theTransient
annotation is persistent.
The explicit access type may be overridden at the attribute level. That
is, a class which explicitly specifies an access type using the Access
annotation may also have fields or properties annotated Access
, and so
the class may have a mix of access types.
-
When
Access(FIELD)
is specified at the class level, an individual attribute within the class may be selectively designated for property access by annotating a property getterAccess(PROPERTY)
. Mapping annotations for this attribute must be placed on the getter. If a mapping annotation is placed on a property getter which is not annotatedAccess(PROPERTY)
, the behavior is undefined. -
When
Access(PROPERTY)
is specified at the class level, an individual attribute within the class may be selectively designated for field access by annotating an instance variableAccess(FIELD)
. Mapping annotations for this attribute must be placed on the field. If a mapping annotation is placed on a field which is not annotatedAccess(FIELD)
, the behavior is undefined.
It is permitted (but redundant) to place Access(FIELD)
on a field whose
class has field access or Access(PROPERTY)
on a property whose class has
property access. On the other hand, the behavior is undefined if:
-
Access(PROPERTY)
annotates a field, -
Access(FIELD)
annotates a property getter, or -
the
Access
annotation occurs on a property setter.
Portable application should avoid such misplaced @Access
annotations.
When access types are combined within a class, the Transient
annotation
should be used to avoid duplicate persistent mappings. For example:
@Entity @Access(PROPERTY)
public class Customer {
private Long id;
@Access(FIELD) // use field access for name
private String name;
@Id
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Transient // suppress duplicated name attribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
}
The Access
annotation does not affect the access type of other entity
classes or mapped superclasses in the entity hierarchy. In particular,
persistent state inherited from a superclass is always accessed according
to the access type of that superclass.
2.3.3. Access Type of an Embeddable Class
The access type of an embeddable class is determined by the access type of
the entity class, mapped superclass, or embeddable class in which it is
embedded (including as a member of an element collection) independent of
whether the access type of the containing class is explicitly specified or
defaulted. A different access type for an embeddable class can be specified
for that embeddable class by means of the Access
annotation as described
above in Section 2.3.2.
2.3.4. Defaulted Access Types of Embeddable Classes and Mapped Superclasses
Care must be taken when implementing an embeddable class or mapped superclass
which is used both in a context of field access and in a context of property
access, and whose access type is not explicitly specified by means of the
Access
annotation or XML mapping file.
Such a class should be implemented so that the number, names, and types of its persistent attributes are independent of the access type in use. The behavior of an embeddable class or mapped superclass whose attributes are not independent of access type is undefined with regard to use with the metamodel API if the class occurs in contexts of differing access types within the same persistence unit.
2.4. Primary Keys and Entity Identity
Every entity must have a primary key. The value of its primary key uniquely
identifies an entity instance within a persistence context and to operations
of the EntityManager
, as described in Chapter 3.
The primary key must be declared by:
-
the entity class that is the root of the entity hierarchy, or
-
a mapped superclass that is a (direct or indirect) superclass of all entity classes in the entity hierarchy.
A primary key must be defined exactly once in each entity hierarchy.
-
A primary key comprises one or more fields or properties (“attributes”) of the entity class.
-
A simple primary key is a single persistent field or property of the entity class whose type is one of the legal simple primary key types listed below. The
Id
annotation defined in Section 11.1.22 orid
XML element must be used to identify the simple primary key. -
A composite primary key must correspond to either a single persistent field or property, or to a set of fields or properties, as described below.[10] A primary key class must be defined to represent the composite primary key.
-
If the composite primary key corresponds to a single field or property of the entity, the
EmbeddedId
annotation defined by Section 11.1.17 identifies the primary key, and the type of the annotated field or property is the primary key class. -
Otherwise, when the composite primary key corresponds to multiple fields or properties, the
Id
annotation defined by Section 11.1.22 identifies the fields and properties which comprise the composite key, and theIdClass
annotation defined by Section 11.1.23 must specify the primary key class.
-
A simple primary key or field or property belonging to a composite primary key should have one of the following basic types:
-
any Java primitive type, or
java.lang
wrapper for a primitive type, [11] -
java.lang.String
, -
java.util.UUID
, -
java.time.LocalDate
,java.util.Date
, orjava.sql.Date
, -
BigDecimal
orBigInteger
fromjava.math
.
If a primary key field or property has type java.util.Date
, the temporal
type must be explicitly specified as DATE
using the Temporal
annotation
defined by Section 11.1.54, or by equivalent XML.
If the primary key is a composite primary key derived from the primary key of another entity, the primary key may contain an attribute whose type is that of the primary key of the referenced entity, as specified below in Section 2.4.2.
An entity with a primary key involving any type other than the types
listed above is not portable. If the primary key is generated by the
persistence provider, as defined by Section 11.1.21, and its type is not
long
, int
, java.util.UUID
, java.lang.String
, java.lang.Long
,
or java.lang.Integer
, the entity is not portable.
The application must not change the value of the primary key of an entity instance after the instance is made persistent[12]. If the application does change the value of a primary key of an entity instance after the entity instance is made persistent, the behavior is undefined.[13]
2.4.1. Composite primary keys
The following rules apply to composite primary keys:
-
The primary key class may be a non-abstract regular Java class with a public or protected constructor with no parameters. Alternatively, the primary key class may be any Java record type, in which case it need not have a constructor with no parameters.
-
The access type (
FIELD
orPROPERTY
) of a primary key class is determined by the access type of the entity for which it is the primary key, unless the primary key is an embedded id and an explicit access type is specified using theAccess
annotation, as defined in Section 2.3.2. -
If property-based access is used, the properties of the primary key class must be public or protected.
-
The primary key class must define
equals
andhashCode
methods. The semantics of value equality for these methods must be consistent with the database equality for the database types to which the key is mapped. -
A composite primary key must either be represented and mapped as an embeddable class (see Section 11.1.17) or it must be represented as an id class and mapped to multiple fields or properties of the entity class (see Section 11.1.23).
-
If the composite primary key class is represented as an id class, the names of primary key fields or properties of the primary key class and those of the entity class to which the id class is mapped must correspond and their types must be the same.
-
A primary key which corresponds to a derived identity must conform to the rules specified below in Section 2.4.2.
2.4.2. Primary Keys Corresponding to Derived Identities
The identity of an entity is said to be partially derived from the identity of a second entity when the child or dependent first entity is the owner of a many-to-one or one-to-one relationship which targets the parent second entity and the foreign key referencing the parent entity forms part of the primary key of the dependent entity.
A derived identity might be represented as a simple primary key or as a composite primary key, as described in Section 2.4.2.1 below. The dependent entity class has a composite primary key if
-
it declares one or more primary key attributes in addition to those corresponding to the primary key of the parent, or
-
the parent itself has a composite primary key
and then an embedded id or id class must be used to represent the primary key of the dependent entity. In the case that the parent has a composite key, it is not required that parent entity and dependent entity both use embedded ids, nor that both use id classes.
A ManyToOne
or OneToOne
relationship which maps a primary key column
or columns may be declared using either:
-
the
Id
annotation, when no otherId
orEmbeddedId
attribute maps the same primary key column or columns, or -
the
MapsId
annotation, if some other attribute or attributes annotatedId
orEmbeddedId
also map the primary key column or columns.
If a ManyToOne
or OneToOne
relationship declared by a dependent
entity is annotated Id
or MapsId
, an instance of the entity cannot be
made persistent until the relationship has been assigned a reference to an
instance of the parent entity, since the identity of the dependent entity
declaring the relationship is derived from the referenced parent entity.
[14]
A dependent entity may have more than one parent entity.
2.4.2.1. Specification of Derived Identities
If a dependent entity uses an id class to represent its primary key, one of the two following rules must be observed:
-
The names and types of the attributes of the id class and the
Id
attributes of the dependent entity class must correspond as follows:-
The
Id
attribute of the dependent entity class and the corresponding attribute in the id class must have the same name. -
If an
Id
attribute of the dependent entity class is of basic type, the corresponding attribute in the id class must have the same type. -
If an
Id
attribute of the entity is aManyToOne
orOneToOne
relationship to the parent entity, the corresponding attribute in the id class must be of the same Java type as the id class or embedded id of the parent entity (if the parent entity has a composite primary key) or the type of theId
attribute of the parent entity (if the parent entity has a simple primary key).
-
-
Alternatively, if the dependent entity declares a single primary key attribute, that is, a
OneToOne
relationship attribute annotatedId
, then the id class specified by the dependent entity must be the same as the primary key class of the parent entity.
If a dependent entity uses an embedded id to represent its primary key,
the relationship attribute which targets the parent entity must be annotated
MapsId
.
-
If the embedded id of the dependent entity is of the same Java type as the primary key of the parent entity, then the relationship attribute maps both the relationship to the parent and the primary key of the dependent entity, the relationship attribute must be a
OneToOne
association, and theMapsId
annotation must leave thevalue
element unspecified. [15] -
Otherwise, the
value
element of theMapsId
annotation must specify the name of the attribute within the embedded id to which the relationship attribute corresponds and this attribute of the embedded id must be of the same type as the primary key of the parent entity.
An attribute of an embedded id which corresponds to a relationship targeting a parent entity is treated by the provider as “read only”—that is, any direct mutation of the attribute is not propagated to the database.
If a dependent entity has a single primary key attribute annotated Id
,
and the primary key of the parent entity is a simple primary key, then
the primary key of the dependent entity is a simple primary key of the
same Java type as that of the parent entity, the relationship attribute
must be a OneToOne
association targeting the parent entity, and either:
-
the primary key attribute annotated
Id
is the relationship attribute itself, or -
the primary key attribute annotated
Id
has the same type as the simple primary key of the parent entity, the relationship attribute is annotatedMapsId
, and thevalue
element of theMapsId
annotation is left unspecified.
Neither EmbeddedId
nor IdClass
is specified for the dependent entity.
2.4.2.2. Mapping of Derived Identities
A dependent entity has derived primary key attributes, and might also have additional primary key attributes which are not derived from any parent entity.
-
Any primary key attribute of a dependent entity which is derived from the identity of a parent entity is mapped by annotations of the corresponding
ManyToOne
orOneToOne
relationship attribute. The default mapping for this relationship is specified in Section 2.12. The default mapping may be overridden by annotating the relationship attribute with theJoinColumn
orJoinColumns
annotation. -
If the dependent entity uses an id class, the
Column
annotation may be used to override the default mapping ofId
attributes which arenot
derived from any parent entity. -
If the dependent entity uses an embedded id to represent its primary key, the
AttributeOverride
annotation applied to theEmbeddedId
attribute may be used to override the default mapping of embedded id attributes which are not derived from any parent entity.
2.4.2.3. Examples of Derived Identities
The following examples illustrate the rules specified above.
Example 1:
The parent entity has a simple primary key:
@Entity
public class Employee {
@Id long empId;
String empName;
// ...
}
Case (a): The dependent entity uses IdClass
to represent a composite key:
public class DependentId {
String name; // matches name of @Id attribute
long emp; // matches name of @Id attribute and type of Employee PK
}
@Entity
@IdClass(DependentId.class)
public class Dependent {
@Id String name;
// id attribute mapped by join column default
@Id @ManyToOne
Employee emp;
// ...
}
Sample query:
SELECT d
FROM Dependent d
WHERE d.name = 'Joe' AND d.emp.empName = 'Sam'
Case(b): The dependent entity uses EmbeddedId
to represent a composite key:
@Embeddable
public class DependentId {
String name;
long empPK; // corresponds to PK type of Employee
}
@Entity
public class Dependent {
@EmbeddedId DependentId id;
// id attribute mapped by join column default
@MapsId("empPK") // maps empPK attribute of embedded id
@ManyToOne
Employee emp;
// ...
}
Sample query:
SELECT d
FROM Dependent d
WHERE d.id.name = 'Joe' AND d.emp.empName = 'Sam'
Example 2:
The parent entity uses IdClass
:
public class EmployeeId {
String firstName;
String lastName;
// ...
}
@Entity
@IdClass(EmployeeId.class)
public class Employee {
@Id String firstName
@Id String lastName
// ...
}
Case (a): The dependent entity uses IdClass
:
public class DependentId {
String name; // matches name of attribute
EmployeeId emp; //matches name of attribute and type of Employee PK
}
@Entity
@IdClass(DependentId.class)
public class Dependent {
@Id
String name;
@Id
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@ManyToOne
Employee emp;
}
Sample query:
SELECT d
FROM Dependent d
WHERE d.name = 'Joe' AND d.emp.firstName = 'Sam'
Case (b): The dependent entity uses
EmbeddedId
. The type of the empPK
attribute is the same as that of
the primary key of Employee
. The EmployeeId
class needs to be
annotated Embeddable
or denoted as an embeddable class in the XML
descriptor.
@Embeddable
public class DependentId {
String name;
EmployeeId empPK;
}
@Entity
public class Dependent {
@EmbeddedId
DependentId id;
@MapsId("empPK")
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@ManyToOne
Employee emp;
// ...
}
Sample query:
SELECT d
FROM Dependent d
WHERE d.id.name = 'Joe' AND d.emp.firstName = 'Sam'
Note that the following alternative query will yield the same result:
SELECT d
FROM Dependent d
WHERE d.id.name = 'Joe' AND d.id.empPK.firstName = 'Sam'
Example 3:
The parent entity uses EmbeddedId
:
@Embeddable
public class EmployeeId {
String firstName;
String lastName;
// ...
}
@Entity
public class Employee {
@EmbeddedId
EmployeeId empId;
// ...
}
Case (a): The dependent entity uses IdClass
:
public class DependentId {
String name; // matches name of @Id attribute
EmployeeId emp; // matches name of @Id attribute and type of embedded id of Employee
}
@Entity
@IdClass(DependentId.class)
public class Dependent {
@Id
@Column(name="dep_name") // default column name is overridden
String name;
@Id
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@ManyToOne Employee
emp;
}
Sample query:
SELECT d
FROM Dependent d
WHERE d.name = 'Joe' and d.emp.empId.firstName = 'Sam'
Case (b): The dependent entity uses EmbeddedId
:
@Embeddable
public class DependentId {
String name;
EmployeeId empPK; // corresponds to PK type of Employee
}
@Entity
public class Dependent {
// default column name for "name" attribute is overridden
@AttributeOverride(name="name", column=@Column(name="dep_name"))
@EmbeddedId DependentId id;
@MapsId("empPK")
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@ManyToOne
Employee emp;
// ...
}
Sample query:
SELECT d
FROM Dependent d
WHERE d.id.name = 'Joe' and d.emp.empId.firstName = 'Sam'
Note that the following alternative query will yield the same result:
SELECT d
FROM Dependent d
WHERE d.id.name = 'Joe' AND d.id.empPK.firstName = 'Sam'
Example 4:
The parent entity has a simple primary key:
@Entity
public class Person {
@Id
String ssn;
// ...
}
Case (a): The dependent entity has a
single primary key attribute which is mapped by the relationship
attribute. The primary key of MedicalHistory
is of type String
.
@Entity
public class MedicalHistory {
// default join column name is overridden
@Id
@OneToOne
@JoinColumn(name="FK")
Person patient;
// ...
}
Sample query:
SELECT m
FROM MedicalHistory m
WHERE m.patient.ssn = '123-45-6789'
Case (b): The dependent entity has
a single primary key attribute corresponding to the relationship
attribute. The primary key attribute is of the same basic type as the
primary key of the parent entity. The MapsId
annotation applied to the
relationship attribute indicates that the primary key is mapped by the
relationship attribute.[16]
@Entity
public class MedicalHistory {
@Id
String id; // overriding not allowed
// ...
// default join column name is overridden
@MapsId
@JoinColumn(name="FK")
@OneToOne
Person patient;
// ...
}
Sample query:
SELECT m
FROM MedicalHistory m WHERE m.patient.ssn = '123-45-6789'
Example 5:
The parent entity uses IdClass
. The
dependent’s primary key class is of same type as that of the parent
entity.
public class PersonId {
String firstName;
String lastName;
}
@Entity
@IdClass(PersonId.class)
public class Person {
@Id
String firstName;
@Id
String lastName;
// ...
}
Case (a): The dependent entity uses IdClass
:
@Entity
@IdClass(PersonId.class)
public class MedicalHistory {
@Id
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@OneToOne
Person patient;
// ...
}
Sample query:
SELECT m
FROM MedicalHistory m
WHERE m.patient.firstName = 'Charles'
Case (b): The dependent entity uses the
EmbeddedId
and MapsId
annotations. The PersonId
class needs to be
annotated Embeddable
or denoted as an embeddable class in the XML
descriptor.
@Entity
public class MedicalHistory {
// all attributes map to relationship:
AttributeOverride not allowed
@EmbeddedId
PersonId id;
// ...
@MapsId
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@OneToOne Person patient;
// ...
}
Sample query:
SELECT m
FROM MedicalHistory m
WHERE m.patient.firstName = 'Charles'
Note that the following alternative query will yield the same result:
SELECT m
FROM MedicalHistory m
WHERE m.id.firstName = 'Charles'
Example 6:
The parent entity uses EmbeddedId
. The
dependent’s primary key is of the same type as that of the parent.
@Embeddable
public class PersonId {
String firstName;
String lastName;
}
@Entity
public class Person {
@EmbeddedId PersonId id;
// ...
}
Case (a): The dependent class uses IdClass
:
@Entity
@IdClass(PersonId.class)
public class MedicalHistory {
@Id
@OneToOne
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
Person patient;
// ...
}
Case (b): The dependent class uses EmbeddedId
:
@Entity
public class MedicalHistory {
// All attributes are mapped by the relationship
// AttributeOverride is not allowed
@EmbeddedId PersonId id;
// ...
@MapsId
@JoinColumns({
@JoinColumn(name="FK1", referencedColumnName="firstName"),
@JoinColumn(name="FK2", referencedColumnName="lastName")
})
@OneToOne
Person patient;
// ...
}
2.5. Entity Versions
An entity might have a version, a persistent field or property used by
the persistence provider to perform optimistic locking, as specified in
Section 3.5.2. The version field or property holds a version number or
timestamp identifying the revision of the entity data held by an entity
class instance. In the course of performing lifecycle operations involving
the entity instance, the persistence provider gets and sets the version
field or property of the entity instance to determine or modify its version
number or timestamp. The Version
annotation defined in Section 11.1.57 or
version
XML element must be used to explicitly identify the version field
or property of an entity.
An entity class may access the state of its version field or property or export a method which allows other user-written code to access the version, but user-written code must not directly modify the value of the version field or property of an entity instance after the entity is made persistent. [17] With the exception noted in Section 4.11, only the persistence provider is permitted to set or update the entity version. If the application does directly modify the value of the version field or property of an entity instance after it is made persistent, the behavior is undefined.
The version must be of one of the following basic types:
-
int
,Integer
,short
,Short
,long
,Long
, or -
java.time.LocalDateTime
,java.time.Instant
, orjava.sql.Timestamp
.
A portable application must not declare a version field or property with any other type.
An entity class should have at most one version. A portable application must not define an entity class having more than one version field or property.
The version should be declared by the root entity class in an entity class hierarchy, or by one of its mapped superclasses. A portable application must not declare a version field or property in a subclass of the root class of an entity class hierarchy.
2.6. Basic Types
The following Java types are considered basic types:
-
any Java primitive type, or
java.lang
wrapper class for a primitive type, -
java.lang.String
, -
java.util.UUID
, -
BigInteger
orBigDecimal
fromjava.math
, -
LocalDate
,LocalTime
,LocalDateTime
,OffsetTime
,OffsetDateTime
,Instant
, orYear
fromjava.time
, -
Date
,Time
, orTimestamp
fromjava.sql
[20], -
byte[]
orByte[]
,char[]
orCharacter[]
[21], -
any Java
enum
type, -
any other type which implements
java.io.Serializable
.
Persistence for basic types is defined in Section 11.1.6 and Section 11.1.18.
2.7. Embeddable Classes
An entity may use other fine-grained classes to represent entity state. Instances of these classes, unlike entity instances, do not have persistent identity of their own. Instead, they exist only as part of the state of the entity to which they belong. An entity may have collections of embeddables as well as single-valued embeddable attributes. Embeddables may also be used as map keys and map values. Embedded objects belong strictly to their owning entity, and are not sharable across persistent entities. Attempting to share an embedded object across entities has undefined semantics.
Embeddable classes must be annotated as
Embeddable
or denoted in the XML descriptor as such. The access type
for an embedded object is determined as described in Section 2.3.
An embeddable class may be a regular Java class which adheres to the
requirements specified in Section 2.1 for entities, with the exception that
an embeddable class is not annotated as Entity
, and an embeddable
class may not be abstract.
Alternatively, an embeddable class may be any Java record type.
An embeddable class may be used to represent the state of another embeddable class.
An embeddable class (including an embeddable class within another embeddable class) may contain a collection of a basic type or other embeddable class.[22]
An embeddable class may contain a relationship to an entity or collection of entities. Since instances of embeddable classes themselves have no persistent identity, the relationship from the referenced entity is to the entity that contains the embeddable instance(s) and not to the embeddable itself.[23] An embeddable class that is used as an embedded id or as a map key must not contain such a relationship.
Additional requirements and restrictions on embeddable classes are described in Section 2.8.
2.8. Collections of Embeddable Classes and Basic Types
A persistent field or property of an entity
or embeddable class may correspond to a collection of a basic type or
embeddable class (“element collection”). Such a collection, when
specified as such by the ElementCollection
annotation, is mapped by
means of a collection table, as defined in Section 11.1.8. If the
ElementCollection
annotation (or XML equivalent) is not specified for
the collection-valued field or property, the rules of Section 2.10 apply.
An embeddable class (including an embeddable class within another embeddable class) that is contained within an element collection must not contain an element collection, nor may it contain a relationship to an entity other than a many-to-one or one-to-one relationship. The embeddable class must be on the owning side of such a relationship and the relationship must be mapped by a foreign key mapping. (See Section 2.11)
2.9. Map Collections
Collections of elements and entity
relationships can be represented as java.util.Map
collections.
The map key and the map value independently can each be a basic type, an embeddable class, or an entity.
The ElementCollection
, OneToMany
, and
ManyToMany
annotations are used to specify the map as an element
collection or entity relationship as follows: when the map value is a
basic type or embeddable class, the ElementCollection
annotation is
used; when the map value is an entity, the OneToMany
or ManyToMany
annotation is used.
Bidirectional relationships represented as
java.util.Map
collections support the use of the Map
datatype on one
side of the relationship only.
2.9.1. Map Keys
If the map key type is a basic type, the
MapKeyColumn
annotation can be used to specify the column mapping for
the map key. If the MapKeyColumn
annotation is not specified, the
default values of the MapKeyColumn
annotation apply as described in Section 11.1.34.
If the map key type is an embeddable class,
the mappings for the map key columns are defaulted according to the
default column mappings for the embeddable class. (See Section 11.1.9). The
AttributeOverride
and AttributeOverrides
annotations can be used to
override these mappings, as described in Section 11.1.4 and Section 11.1.5. If an
embeddable class is used as a map key, the embeddable class must
implement the hashCode
and equals
methods consistently with the
database columns to which the embeddable is
mapped[24].
If the map key type is an entity, the
MapKeyJoinColumn
and MapKeyJoinColumns
annotations are used to
specify the column mappings for the map key. If the primary key of the
referenced entity is a simple primary key and the MapKeyJoinColumn
annotation is not specified, the default values of the
MapKeyJoinColumn
annotation apply as described in Section 11.1.36.
If Java generic types are not used in the
declaration of a relationship attribute of type java.util.Map
, the
MapKeyClass
annotation must be used to specify the type of the key of
the map.
The MapKey
annotation is used to specify
the special case where the map key is itself the primary key or a
persistent field or property of the entity that is the value of the map.
The MapKeyClass
annotation is not used when MapKey
is specified.
2.9.2. Map Values
When the value type of the map is a basic
type or an embeddable class, a collection table is used to map the map.
If Java generic types are not used, the targetClass
element of the
ElementCollection
annotation must be used to specify the value type
for the map. The default column mappings for the map value are derived
according to the default mapping rules for the CollectionTable
annotation defined in Section 11.1.8. The Column
annotation is used to override
these defaults for a map value of basic type. The AttributeOverride(s)
and AssociationOverride(s)
annotations are used to override
the mappings for a map value that is an embeddable class.
When the value type of the map is an entity,
a join table is used to map the map for a many-to-many relationship or,
by default, for a one-to-many unidirectional relationship. If the
relationship is a bidirectional one-to-many/many-to-one relationship, by
default the map is mapped in the table of the entity that is the value
of the map. If Java generic types are not used, the targetEntity
element of the OneToMany
or ManyToMany
annotation must be used to
specify the value type for the map. Default mappings are described in
Section 2.12.
2.10. Mapping Defaults for Non-Relationship Fields or Properties
If a persistent field or property other than a relationship property is not annotated with one of the mapping annotations defined in Chapter 11 (and no equivalent mapping information is specified in any XML descriptor), the following default mapping rules are applied in order:
-
If the type of the field or property is a class annotated with the
Embeddable
annotation, the field or property is mapped as if it were annotated with theEmbedded
annotation. See Section 11.1.15 and Section 11.1.16. -
Otherwise, if the type of the field or property is one of the one of the basic types listed in Section 2.6, it is mapped in the same way as if it were annotated as
Basic
. See Section 11.1.6, Section 11.1.18, Section 11.1.29, and Section 11.1.54.
It is an error if no annotation is present and neither of the above rules apply.
2.11. Entity Relationships
Relationships among entities may be one-to-one, one-to-many, many-to-one, or many-to-many. Relationships are polymorphic.
If there is an association between two
entities, one of the following relationship modeling annotations must be
applied to the corresponding persistent property or field of the
referencing entity: OneToOne
, OneToMany
, ManyToOne
,
ManyToMany
. For associations that do not specify the target type
(e.g., where Java generic types are not used for collections), it is
necessary to specify the entity that is the target of the
relationship.[25] Equivalent XML elements may be used
as an alternative to these mapping annotations.
These annotations mirror common practice in relational database schema modeling. The use of the relationship modeling annotations allows the object/relationship mapping of associations to the relational database schema to be fully defaulted, to provide an ease-of-development facility. This is described in Section 2.12.
Relationships may be bidirectional or unidirectional. A bidirectional relationship has both an owning side and an inverse (non-owning) side. A unidirectional relationship has only an owning side. The owning side of a relationship determines the updates to the relationship in the database, as described in Section 3.3.4.
The following rules apply to bidirectional relationships:
The inverse side of a bidirectional
relationship must refer to its owning side by use of the mappedBy
element of the OneToOne
, OneToMany
, or ManyToMany
annotation.
The mappedBy
element designates the property or field in the entity
that is the owner of the relationship.
-
The many side of one-to-many / many-to-one bidirectional relationships must be the owning side, hence the
mappedBy
element cannot be specified on theManyToOne
annotation. -
For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key.
-
For many-to-many bidirectional relationships either side may be the owning side.
The relationship modeling annotation
constrains the use of the cascade=REMOVE
specification. The
cascade=REMOVE
specification should only be applied to associations
that are specified as OneToOne
or OneToMany
. Applications that
apply cascade=REMOVE
to other associations are not portable.
Associations that are specified as OneToOne
or OneToMany
support use of the orphanRemoval
option. The following
behaviors apply when orphanRemoval
is in effect:
-
If an entity that is the target of the relationship is removed from the relationship (by setting the relationship to null or removing the entity from the relationship collection), the remove operation will be applied to the entity being orphaned. The remove operation is applied at the time of the flush operation. The
orphanRemoval
functionality is intended for entities that are privately “owned” by their parent entity. Portable applications must otherwise not depend upon a specific order of removal, and must not reassign an entity that has been orphaned to another relationship or otherwise attempt to persist it. If the entity being orphaned is a detached, new, or removed entity, the semantics oforphanRemoval
do not apply. -
If the remove operation is applied to a managed source entity, the remove operation will be cascaded to the relationship target in accordance with the rules of Section 3.3.3, (and hence it is not necessary to specify
cascade=REMOVE
for the relationship)[26].
Section 2.12, defines relationship mapping defaults for entity relationships. Additional mapping annotations (e.g., column and table mapping annotations) may be specified to override or further refine the default mappings and mapping strategies described in Section 2.12.
In addition, this specification also requires support for the following alternative mapping strategies:
-
The mapping of unidirectional one-to-many relationships by means of foreign key mappings. The
JoinColumn
annotation or corresponding XML element must be used to specify such non-default mappings. See Section 11.1.26. -
The mapping of unidirectional and bidirectional one-to-one relationships, bidirectional many-to-one/one-to-many relationships, and unidirectional many-to-one relationships by means of join table mappings. The
JoinTable
annotation or corresponding XML element must be used to specify such non-default mappings. See Section 11.1.28.
Such mapping annotations must be specified on the owning side of the relationship. Any overriding of mapping defaults must be consistent with the relationship modeling annotation that is specified. For example, if a many-to-one relationship mapping is specified, it is not permitted to specify a unique key constraint on the foreign key for the relationship.
The persistence provider handles the object/relational mapping of the relationships, including their loading and storing to the database as specified in the metadata of the entity class, and the referential integrity of the relationships as specified in the database (e.g., by foreign key constraints).
Note that it is the application that bears responsibility for maintaining the consistency of runtime relationships—for example, for insuring that the “one” and the “many” sides of a bidirectional relationship are consistent with one another when the application updates the relationship at runtime. |
If there are no associated entities for a multi-valued relationship of an entity fetched from the database, the persistence provider is responsible for returning an empty collection as the value of the relationship.
2.12. Relationship Mapping Defaults
This section defines the mapping defaults
that apply to the use of the OneToOne
, OneToMany
, ManyToOne
,
and ManyToMany
relationship modeling annotations. The same mapping
defaults apply when the XML descriptor is used to denote the
relationship cardinalities.
2.12.1. Bidirectional OneToOne Relationships
Assuming that:
-
Entity A references a single instance of Entity B.
-
Entity B references a single instance of Entity A.
-
Entity A is specified as the owner of the relationship.
The following mapping defaults apply:
-
Entity A is mapped to a table named
A
. -
Entity B is mapped to a table named
B
. -
Table
A
contains a foreign key to tableB
. The foreign key column name is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_
"; the name of the primary key column in tableB
. The foreign key column has the same type as the primary key of tableB
and there is a unique key constraint on it.
Example:
@Entity
public class Employee {
private Cubicle assignedCubicle;
@OneToOne
public Cubicle getAssignedCubicle() {
return assignedCubicle;
}
public void setAssignedCubicle(Cubicle cubicle) {
this.assignedCubicle = cubicle;
}
// ...
}
@Entity
public class Cubicle {
private Employee residentEmployee;
@OneToOne(mappedBy="assignedCubicle")
public Employee getResidentEmployee() {
return residentEmployee;
}
public void setResidentEmployee(Employee employee) {
this.residentEmployee = employee;
}
// ...
}
In this example:
-
Entity
Employee
references a single instance of EntityCubicle
. -
Entity
Cubicle
references a single instance of EntityEmployee
. -
Entity
Employee
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
Entity
Cubicle
is mapped to a table namedCUBICLE
. -
Table
EMPLOYEE
contains a foreign key to tableCUBICLE
. The foreign key column is namedASSIGNEDCUBICLE_<PK of CUBICLE>
, where<PK of CUBICLE>
denotes the name of the primary key column of tableCUBICLE
. The foreign key column has the same type as the primary key ofCUBICLE
, and there is a unique key constraint on it.
2.12.2. Bidirectional ManyToOne / OneToMany Relationships
Assuming that:
-
Entity A references a single instance of Entity B.
-
Entity B references a collection of Entity A[27].
-
Entity A must be the owner of the relationship.
The following mapping defaults apply:
-
Entity A is mapped to a table named
A
. -
Entity B is mapped to a table named
B
. -
Table
A
contains a foreign key to tableB
. The foreign key column name is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_
"; the name of the primary key column in tableB
. The foreign key column has the same type as the primary key of tableB
.
Example:
@Entity
public class Employee {
private Department department;
@ManyToOne
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
// ...
}
@Entity
public class Department {
private Collection<Employee> employees = new HashSet();
@OneToMany(mappedBy="department")
public Collection<Employee> getEmployees() {
return employees;
}
public void setEmployees(Collection<Employee> employees) {
this.employees = employees;
}
// ...
}
In this example:
-
Entity
Employee
references a single instance of EntityDepartment
. -
Entity
Department
references a collection of EntityEmployee
. -
Entity
Employee
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
Entity
Department
is mapped to a table namedDEPARTMENT
. -
Table
EMPLOYEE
contains a foreign key to tableDEPARTMENT
. The foreign key column is namedDEPARTMENT_<PK of DEPARTMENT>
, where<PK of DEPARTMENT>
denotes the name of the primary key column of tableDEPARTMENT
. The foreign key column has the same type as the primary key ofDEPARTMENT
.
2.12.3. Unidirectional Single-Valued Relationships
Assuming that:
-
Entity A references a single instance of Entity B.
-
Entity B does not reference Entity A.
A unidirectional relationship has only an owning side, which in this case must be Entity A.
The unidirectional single-valued relationship
modeling case can be specified as either a unidirectional OneToOne
or
as a unidirectional ManyToOne
relationship.
2.12.3.1. Unidirectional OneToOne Relationships
The following mapping defaults apply:
-
Entity A is mapped to a table named
A
. -
Entity B is mapped to a table named
B
. -
Table
A
contains a foreign key to tableB
. The foreign key column name is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_
"; the name of the primary key column in tableB
. The foreign key column has the same type as the primary key of tableB
and there is a unique key constraint on it.
Example:
@Entity
public class Employee {
private TravelProfile profile;
@OneToOne
public TravelProfile getProfile() {
return profile;
}
public void setProfile(TravelProfile profile) {
this.profile = profile;
}
// ...
}
@Entity
public class TravelProfile {
// ...
}
In this example:
-
Entity
Employee
references a single instance of EntityTravelProfile
. -
Entity
TravelProfile
does not reference EntityEmployee
. -
Entity
Employee
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
Entity
TravelProfile
is mapped to a table namedTRAVELPROFILE
. -
Table
EMPLOYEE
contains a foreign key to tableTRAVELPROFILE
. The foreign key column is namedPROFILE_<PK of TRAVELPROFILE>
, where<PK of TRAVELPROFILE>
denotes the name of the primary key column of tableTRAVELPROFILE
. The foreign key column has the same type as the primary key ofTRAVELPROFILE
, and there is a unique key constraint on it.
2.12.3.2. Unidirectional ManyToOne Relationships
The following mapping defaults apply:
-
Entity A is mapped to a table named
A
. -
Entity B is mapped to a table named
B
. -
Table
A
contains a foreign key to tableB
. The foreign key column name is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_"; the name of the primary key column in tableB
. The foreign key column has the same type as the primary key of tableB
.
Example:
@Entity
public class Employee {
private Address address;
@ManyToOne
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
// ...
}
@Entity
public class Address {
// ...
}
In this example:
-
Entity
Employee
references a single instance of EntityAddress
. -
Entity
Address
does not reference EntityEmployee
. -
Entity
Employee
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
Entity
Address
is mapped to a table namedADDRESS
. -
Table
EMPLOYEE
contains a foreign key to tableADDRESS
. The foreign key column is namedADDRESS_<PK of ADDRESS>
, where<PK of ADDRESS>
denotes the name of the primary key column of tableADDRESS
. The foreign key column has the same type as the primary key ofADDRESS
.
2.12.4. Bidirectional ManyToMany Relationships
Assuming that:
-
Entity A references a collection of Entity B.
-
Entity B references a collection of Entity A.
-
Entity A is the owner of the relationship.
The following mapping defaults apply:
-
Entity A is mapped to a table named
A
. -
Entity B is mapped to a table named
B
. -
There is a join table that is named
A_B
(owner name first). This join table has two foreign key columns. One foreign key column refers to tableA
and has the same type as the primary key of tableA
. The name of this foreign key column is formed as the concatenation of the following: the name of the relationship property or field of entity B; "_
"; the name of the primary key column in tableA
. The other foreign key column refers to tableB
and has the same type as the primary key of tableB
. The name of this foreign key column is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_
"; the name of the primary key column in tableB
.
Example:
@Entity
public class Project {
private Collection<Employee> employees;
@ManyToMany
public Collection<Employee> getEmployees() {
return employees;
}
public void setEmployees(Collection<Employee> employees) {
this.employees = employees;
}
// ...
}
@Entity
public class Employee {
private Collection<Project> projects;
@ManyToMany(mappedBy="employees")
public Collection<Project> getProjects() {
return projects;
}
public void setProjects(Collection<Project> projects) {
this.projects = projects;
}
// ...
}
In this example:
-
Entity
Project
references a collection of EntityEmployee
. -
Entity
Employee
references a collection of EntityProject
. -
Entity
Project
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Project
is mapped to a table namedPROJECT
. -
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
There is a join table that is named
PROJECT_EMPLOYEE
(owner name first). This join table has two foreign key columns. One foreign key column refers to tablePROJECT
and has the same type as the primary key ofPROJECT
. The name of this foreign key column isPROJECTS_<PK of PROJECT>
, where<PK of PROJECT>
denotes the name of the primary key column of tablePROJECT
. The other foreign key column refers to tableEMPLOYEE
and has the same type as the primary key ofEMPLOYEE
. The name of this foreign key column isEMPLOYEES_<PK of EMPLOYEE>
, where<PK of EMPLOYEE>
denotes the name of the primary key column of tableEMPLOYEE
.
2.12.5. Unidirectional Multi-Valued Relationships
Assuming that:
-
Entity A references a collection of Entity B.
-
Entity B does not reference Entity A.
A unidirectional relationship has only an owning side, which in this case must be Entity A.
The unidirectional multi-valued relationship
modeling case can be specified as either a unidirectional OneToMany
or
as a unidirectional ManyToMany
relationship.
2.12.5.1. Unidirectional OneToMany Relationships
The following mapping defaults apply:
-
Entity A is mapped to a table named
A
. -
Entity B is mapped to a table named
B
. -
There is a join table that is named
A_B
(owner name first). This join table has two foreign key columns. One foreign key column refers to tableA
and has the same type as the primary key of tableA
. The name of this foreign key column is formed as the concatenation of the following: the name of entity A; "_
"; the name of the primary key column in tableA
. The other foreign key column refers to tableB
and has the same type as the primary key of tableB
and there is a unique key constraint on it. The name of this foreign key column is formed as the concatenation of the following: the name of the relationship property or field of entity A; "_
"; the name of the primary key column in tableB
.
Example:
@Entity
public class Employee {
private Collection<AnnualReview> annualReviews;
@OneToMany
public Collection<AnnualReview> getAnnualReviews() {
return annualReviews;
}
public void setAnnualReviews(Collection<AnnualReview> annualReviews) {
this.annualReviews = annualReviews;
}
// ...
}
@Entity
public class AnnualReview {
// ...
}
In this example:
-
Entity
Employee
references a collection of EntityAnnualReview
. -
Entity
AnnualReview
does not reference EntityEmployee
. -
Entity
Employee
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
Entity
AnnualReview
is mapped to a table namedANNUALREVIEW
. -
There is a join table that is named
EMPLOYEE_ANNUALREVIEW
(owner name first). This join table has two foreign key columns. One foreign key column refers to tableEMPLOYEE
and has the same type as the primary key ofEMPLOYEE
. This foreign key column is namedEMPLOYEE_<PK of EMPLOYEE>
, where<PK of EMPLOYEE>
denotes the name of the primary key column of tableEMPLOYEE
. The other foreign key column refers to tableANNUALREVIEW
and has the same type as the primary key ofANNUALREVIEW
. This foreign key column is namedANNUALREVIEWS_<PK of ANNUALREVIEW>
, where<PK of ANNUALREVIEW>
denotes the name of the primary key column of tableANNUALREVIEW
. There is a unique key constraint on the foreign key that refers to tableANNUALREVIEW
.
2.12.5.2. Unidirectional ManyToMany Relationships
The following mapping defaults apply:
-
Entity
A
is mapped to a table namedA
. -
Entity
B
is mapped to a table namedB
. -
There is a join table that is named
A_B
(owner name first). This join table has two foreign key columns. One foreign key column refers to tableA
and has the same type as the primary key of table A. The name of this foreign key column is formed as the concatenation of the following: the name of entityA
; "_
"; the name of the primary key column in tableA
. The other foreign key column refers to tableB
and has the same type as the primary key of tableB
. The name of this foreign key column is formed as the concatenation of the following: the name of the relationship property or field of entityA
; "_
"; the name of the primary key column in tableB
.
Example:
@Entity
public class Employee {
private Collection<Patent> patents;
@ManyToMany
public Collection<Patent> getPatents() {
return patents;
}
public void setPatents(Collection<Patent> patents) {
this.patents = patents;
}
// ...
}
@Entity
public class Patent {
//...
}
In this example:
-
Entity
Employee
references a collection of EntityPatent
. -
Entity
Patent
does not reference EntityEmployee
. -
Entity
Employee
is the owner of the relationship.
The following mapping defaults apply:
-
Entity
Employee
is mapped to a table namedEMPLOYEE
. -
Entity
Patent
is mapped to a table namedPATENT
. -
There is a join table that is named
EMPLOYEE_PATENT
(owner name first). This join table has two foreign key columns. One foreign key column refers to tableEMPLOYEE
and has the same type as the primary key ofEMPLOYEE
. This foreign key column is namedEMPLOYEE_<PK of EMPLOYEE>
, where<PK of EMPLOYEE>
denotes the name of the primary key column of tableEMPLOYEE
. The other foreign key column refers to tablePATENT
and has the same type as the primary key ofPATENT
. This foreign key column is namedPATENTS_<PK of PATENT>
, where<PK of PATENT>
denotes the name of the primary key column of tablePATENT
.
2.13. Inheritance
An entity may inherit from another entity class. Entities support inheritance, polymorphic associations, and polymorphic queries.
Both abstract and concrete classes can be
entities. Both abstract and concrete classes can be annotated with the
Entity
annotation, mapped as entities, and queried for as entities.
Entities can extend non-entity classes and non-entity classes can extend entity classes.
These concepts are described further in the following sections.
2.13.1. Abstract Entity Classes
An abstract class can be specified as an entity. An abstract entity differs from a concrete entity only in that it cannot be directly instantiated. An abstract entity is mapped as an entity and can be the target of queries (which will operate over and/or retrieve instances of its concrete subclasses).
An abstract entity class is annotated with
the Entity
annotation or denoted in the XML descriptor as an entity.
The following example shows the use of an abstract entity class in the entity inheritance hierarchy.
Example: Abstract class as an Entity
@Entity
@Table(name="EMP")
@Inheritance(strategy=JOINED)
public abstract class Employee {
@Id
protected Integer empId;
@Version
protected Integer version;
@ManyToOne
protected Address address;
// ...
}
@Entity
@Table(name="FT_EMP")
@DiscriminatorValue("FT")
@PrimaryKeyJoinColumn(name="FT_EMPID")
public class FullTimeEmployee extends Employee {
// Inherit empId, but mapped in this class to FT_EMP.FT_EMPID
// Inherit version mapped to EMP.VERSION
// Inherit address mapped to EMP.ADDRESS fk
// Defaults to FT_EMP.SALARY
protected Integer salary;
// ...
}
@Entity
@Table(name="PT_EMP")
@DiscriminatorValue("PT")
// PK column is PT_EMP.EMPID due to `PrimaryKeyJoinColumn` default
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
// ...
}
2.13.2. Mapped Superclasses
An entity may inherit from a superclass that provides persistent entity state and mapping information, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.
A mapped superclass, unlike an entity, is not
queryable and must not be passed as an argument to EntityManager
or
Query
operations. Persistent relationships defined by a mapped
superclass must be unidirectional.
Both abstract and concrete classes may be
specified as mapped superclasses. The MappedSuperclass
annotation (or
mapped-superclass
XML descriptor element) is used to designate a
mapped superclass.
A class designated as a mapped superclass has no separate table defined for it. Its mapping information is applied to the entities that inherit from it.
A class designated as a mapped superclass can
be mapped in the same way as an entity except that the mappings will
apply only to its subclasses since no table exists for the mapped
superclass itself. When applied to the subclasses, the inherited
mappings will apply in the context of the subclass tables. Mapping
information can be overridden in such subclasses by using the
AttributeOverride
and AssociationOverride
annotations or
corresponding XML elements.
All other entity mapping defaults apply equally to a class designated as a mapped superclass.
The following example illustrates the definition of a concrete class as a mapped superclass.
Example: Concrete class as a mapped superclass
@MappedSuperclass
public class Employee {
@Id
protected Integer empId;
@Version
protected Integer version;
@ManyToOne
@JoinColumn(name="ADDR")
protected Address address;
public Integer getEmpId() { ... }
public void setEmpId(Integer id) { ... }
public Address getAddress() { ... }
public void setAddress(Address addr) { ... }
}
// Default table is FTEMPLOYEE table
@Entity
public class FTEmployee extends Employee {
// Inherited empId field mapped to FTEMPLOYEE.EMPID
// Inherited version field mapped to FTEMPLOYEE.VERSION
// Inherited address field mapped to FTEMPLOYEE.ADDR fk
// Defaults to FTEMPLOYEE.SALARY
protected Integer salary;
public FTEmployee() {}
public Integer getSalary() { ... }
public void setSalary(Integer salary) { ... }
}
@Entity
@Table(name="PT_EMP")
@AssociationOverride(name="address", joincolumns=@JoinColumn(name="ADDR_ID"))
public class PartTimeEmployee extends Employee {
// Inherited empId field mapped to PT_EMP.EMPID
// Inherited version field mapped to PT_EMP.VERSION
// address field mapping overridden to PT_EMP.ADDR_ID fk
@Column(name="WAGE")
protected Float hourlyWage;
public PartTimeEmployee() {}
public Float getHourlyWage() { ... }
public void setHourlyWage(Float wage) { ... }
}
2.13.3. Non-Entity Classes in the Entity Inheritance Hierarchy
An entity can have a non-entity superclass, which may be either a concrete or abstract class.[28]
The non-entity superclass serves for inheritance of behavior only. The state of a non-entity superclass is not persistent. Any state inherited from non-entity superclasses is non-persistent in an inheriting entity class. This non-persistent state is not managed by the entity manager[29]. Any annotations on such superclasses are ignored.
Non-entity classes cannot be passed as
arguments to methods of the EntityManager
or Query
interfaces[30] and cannot bear mapping information.
The following example illustrates the use of a non-entity class as a superclass of an entity.
Example: Non-entity superclass
public class Cart {
protected Integer operationCount; // transient state
public Cart() {
operationCount = 0;
}
public Integer getOperationCount() {
return operationCount;
}
public void incrementOperationCount() {
operationCount++;
}
}
@Entity
public class ShoppingCart extends Cart {
Collection<Item> items = new Vector<Item>();
public ShoppingCart() {
super();
}
// ...
@OneToMany
public Collection<Item> getItems() {
return items;
}
public void addItem(Item item) {
items.add(item);
incrementOperationCount();
}
}
2.14. Inheritance Mapping Strategies
The mapping of class hierarchies is specified through metadata.
There are three basic strategies that are used when mapping a class or class hierarchy to a relational database:
-
a single table per class hierarchy
-
a joined subclass strategy, in which fields that are specific to a subclass are mapped to a separate table than the fields that are common to the parent class, and a join is performed to instantiate the subclass.
-
a table per concrete entity class
An implementation is required to support the single table per class hierarchy inheritance mapping strategy and the joined subclass strategy.
Support for the table per concrete class inheritance mapping strategy is optional in this release. Applications that use this mapping strategy will not be portable. Support for the combination of inheritance strategies within a single entity inheritance hierarchy is not required by this specification. |
2.14.1. Single Table per Class Hierarchy Strategy
In this strategy, all the classes in a hierarchy are mapped to a single table. The table has a column that serves as a “discriminator column”, that is, a column whose value identifies the specific subclass to which the instance that is represented by the row belongs.
This mapping strategy provides good support for polymorphic relationships between entities and for queries that range over the class hierarchy.
It has the drawback, however, that it requires that the columns that correspond to state specific to the subclasses be nullable.
2.14.2. Joined Subclass Strategy
In the joined subclass strategy, the root of the class hierarchy is represented by a single table. Each subclass is represented by a separate table that contains those fields that are specific to the subclass (not inherited from its superclass), as well as the column(s) that represent its primary key. The primary key column(s) of the subclass table serves as a foreign key to the primary key of the superclass table.
This strategy provides support for polymorphic relationships between entities.
It has the drawback that it requires that one or more join operations be performed to instantiate instances of a subclass. In deep class hierarchies, this may lead to unacceptable performance. Queries that range over the class hierarchy likewise require joins.
2.14.3. Table per Concrete Class Strategy
In this mapping strategy, each class is mapped to a separate table. All properties of the class, including inherited properties, are mapped to columns of the table for the class.
This strategy has the following drawbacks:
-
It provides poor support for polymorphic relationships.
-
It typically requires that SQL UNION queries (or a separate SQL query per subclass) be issued for queries that are intended to range over the class hierarchy.
2.15. Naming of Database Objects
Many annotations and annotation elements contain names of database objects or assume default names for database objects.
This specification requires the following with regard to the interpretation of the names referencing database objects. These names include the names of tables, columns, and other database elements. Such names also include names that result from defaulting (e.g., a table name that is defaulted from an entity name or a column name that is defaulted from a field or property name).
By default, the names of database objects must be treated as undelimited identifiers and passed to the database as such.
For example, assuming the use of an English locale, the following must be passed to the database as undelimited identifers so that they will be treated as equivalent for all databases that comply with the SQL Standard’s requirements for the treatment of “regular identifiers” (undelimited identifiers) and “delimited identifiers” [2]:
@Table(name="Customer")
@Table(name="customer")
@Table(name="cUsTomer")
Similarly, the following must be treated as equivalent:
@JoinColumn(name="CUSTOMER")
@ManyToOne Customer customer;
@JoinColumn(name="customer")
@ManyToOne Customer customer;
@ManyToOne Customer customer;
To specify delimited identifiers, one of the following approaches must be used:
-
It is possible to specify that all database identifiers in use for a persistence unit be treated as delimited identifiers by specifying the <delimited-identifiers/> element within the
persistence-unit-defaults
element of the object/relational xml mapping file. If the <delimited-identifiers/> element is specified, it cannot be overridden. -
It is possible to specify on a per-name basis that a name for a database object is to be interpreted as a delimited identifier as follows:
-
Using annotations, a name is specified as a delimited identifier by enclosing the name within double quotes, whereby the inner quotes are escaped, e.g.,
@Table(name="\"customer\"")
. -
When using XML, a name is specified as a delimited identifier by use of double quotes, e.g.,
<table name=""customer""/>
[31]
-
The following annotations contain elements whose values correspond to names of database identifiers and for which the above rules apply, including when their use is nested within that of other annotations:
-
EntityResult(discriminatorColumn element)
-
FieldResult(column element)
-
ColumnResult(name element)
-
CollectionTable(name, catalog, schema elements)
-
Column(name, columnDefinition, table elements)
-
DiscriminatorColumn(name, columnDefinition elements)
-
ForeignKey(name, foreignKeyDefinition elements)
-
Index(name, columnList elements)
-
JoinColumn(name, referencedColumnName, columnDefinition, table elements)
-
JoinTable(name, catalog, schema elements)
-
MapKeyColumn(name, columnDefinition, table elements)
-
MapKeyJoinColumn(name, referencedColumnName, columnDefinition, table elements)
-
NamedStoredProcedureQuery(procedureName element)
-
OrderColumn(name, columnDefinition elements)
-
PrimaryKeyJoinColumn(name, referencedColumnName, columnDefinition elements)
-
SecondaryTable(name, catalog, schema elements)
-
SequenceGenerator(sequenceName, catalog, schema elements)
-
StoredProcedureParameter(name element)
-
Table(name, catalog, schema elements)
-
TableGenerator(table, catalog, schema, pkColumnName, valueColumnName elements)
-
UniqueConstraint(name, columnNames elements)
The following XML elements and types contain elements or attributes whose values correspond to names of database identifiers and for which the above rules apply:
-
entity-mappings(schema, catalog elements)
-
persistence-unit-defaults(schema, catalog elements)
-
collection-table(name, catalog, schema attributes)
-
column(name, table, column-definition attributes)
-
column-result(name attribute)
-
discriminator-column(name, column-definition attributes)
-
entity-result(discriminator-column attribute)
-
field-result(column attribute)
-
foreign-key(name, foreign-key-definition attributes)
-
index(name attribute, column-list element)
-
join-column(name, referenced-column-name, column-definition, table attributes)
-
join-table(name, catalog, schema attributes)
-
map-key-column(name, column-definition, table attributes)
-
map-key-join-column(name, referenced-column-name, column-definition, table attributes)
-
named-stored-procedure-query(procedure-name attribute)
-
order-column(name, column-definition attributes)
-
primary-key-join-column(name, referenced-column-name, column-definition attributes)
-
secondary-table(name, catalog, schema attributes)
-
sequence-generator(sequence-name, catalog, schema attributes)
-
stored-procedure-parameter(name attribute)
-
table(name, catalog, schema attributes)
-
table-generator(table, catalog, schema, pk-column-name, value-column-name attributes)
-
unique-constraint(name attribute, column-name element)
3. Entity Operations
This chapter describes:
-
the use of the
EntityManager
andQuery
APIs to retrieve instances of entity classes representing persistent state held in the database, and ofEntityGraph
to control the limits of the object graph returned by such operations, -
the use of the
EntityManager
API to manage the lifecycle of entity instances associated with a persistence context, and to control the synchronization of state held in the persistence context with the database, -
the use of the second-level cache, and
-
entity listeners and lifeycle callbacks, attribute converters, and integration with Bean Validation.
3.1. Overview
Every instance of EntityManager
has an associated persistence context.
A persistence context is a set of entity instances in which for any given
persistent entity identity there is a unique entity instance. Within the
persistence context, the entity instances and their lifecycle are managed.
The entity instance lifecycle is defined in Section 3.3. The relationship
between entity managers and persistence contexts is described in Section 3.4,
and again in further detail in Chapter 7.
The EntityManager
interface defines the methods used to interact with
its persistence context. The EntityManager
API is used to create and
remove persistent entity instances, to find persistent entities by primary
key, and to query over persistent entity types. Section 3.2 describes the
EntityManager
interface. Section 3.5 describes mechanisms for concurrency
control and locking. Section 3.12 provides a summary of exceptions.
The EntityManager
acts as a factory for instances of Query
, which are
used to control query execution. Query
, TypedQuery
, StoredProcedureQuery
,
and related interfaces are described in Section 3.11. The Jakarta Persistence
query language is defined in Chapter 4 and APIs for the construction of
Criteria queries in Chapter 6. Section 3.8 describes the use of entity graphs
to control and limit the data fetched during find and query operations.
Each EntityManager
belongs to an EntityManagerFactory
with an associated
persistence unit. A persistence unit defines a set of related entities which
map to a single database. Entities belonging to the same persistence unit may
participate in associations. An EntityManager
may only manage instances of
entities belonging to its persistence unit. The definition of persistence
units is described in Chapter 8. An EntityManagerFactory
might have an
associated second-level cache. Section 3.10 describes mechanisms for portable
configuration of the second-level cache.
Jakarta Persistence features several mechanisms allowing user-written code to react to events occurring within the persistence context. Section 3.6 describes entity listeners and lifecycle callback methods for entities. Section 3.7 describes support for automatic use of Bean Validation. Section 3.8 describes mechanisms for defining conversions between entity and database representations for attributes of basic types.
3.2. EntityManager Interface
package jakarta.persistence;
import java.util.Map;
import java.util.List;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.criteria.CriteriaDelete;
/**
* Interface used to interact with the persistence context.
*
* <p> An <code>EntityManager</code> instance is associated with
* a persistence context. A persistence context is a set of entity
* instances in which for any persistent entity identity there is
* a unique entity instance. Within the persistence context, the
* entity instances and their lifecycle are managed.
* The <code>EntityManager</code> API is used
* to create and remove persistent entity instances, to find entities
* by their primary key, and to query over entities.
*
* <p> The set of entities that can be managed by a given
* <code>EntityManager</code> instance is defined by a persistence
* unit. A persistence unit defines the set of all classes that are
* related or grouped by the application, and which must be
* colocated in their mapping to a single database.
*
* @see Query
* @see TypedQuery
* @see CriteriaQuery
* @see PersistenceContext
* @see StoredProcedureQuery
*
* @since 1.0
*/
public interface EntityManager extends AutoCloseable {
/**
* Make an instance managed and persistent.
* @param entity entity instance
* @throws EntityExistsException if the entity already exists.
* (If the entity already exists, the <code>EntityExistsException</code> may
* be thrown when the persist operation is invoked, or the
* <code>EntityExistsException</code> or another <code>PersistenceException</code> may be
* thrown at flush or commit time.)
* @throws IllegalArgumentException if the instance is not an
* entity
* @throws TransactionRequiredException if there is no transaction when
* invoked on a container-managed entity manager of that is of type
* <code>PersistenceContextType.TRANSACTION</code>
*/
public void persist(Object entity);
/**
* Merge the state of the given entity into the
* current persistence context.
* @param entity entity instance
* @return the managed instance that the state was merged to
* @throws IllegalArgumentException if instance is not an
* entity or is a removed entity
* @throws TransactionRequiredException if there is no transaction when
* invoked on a container-managed entity manager of that is of type
* <code>PersistenceContextType.TRANSACTION</code>
*/
public <T> T merge(T entity);
/**
* Remove the entity instance.
* @param entity entity instance
* @throws IllegalArgumentException if the instance is not an
* entity or is a detached entity
* @throws TransactionRequiredException if invoked on a
* container-managed entity manager of type
* <code>PersistenceContextType.TRANSACTION</code> and there is
* no transaction
*/
public void remove(Object entity);
/**
* Find by primary key.
* Search for an entity of the specified class and primary key.
* If the entity instance is contained in the persistence context,
* it is returned from there.
* @param entityClass entity class
* @param primaryKey primary key
* @return the found entity instance or null if the entity does
* not exist
* @throws IllegalArgumentException if the first argument does
* not denote an entity type or the second argument is
* is not a valid type for that entity's primary key or
* is null
*/
public <T> T find(Class<T> entityClass, Object primaryKey);
/**
* Find by primary key, using the specified properties.
* Search for an entity of the specified class and primary key.
* If the entity instance is contained in the persistence
* context, it is returned from there.
* If a vendor-specific property or hint is not recognized,
* it is silently ignored.
* @param entityClass entity class
* @param primaryKey primary key
* @param properties standard and vendor-specific properties
* and hints
* @return the found entity instance or null if the entity does
* not exist
* @throws IllegalArgumentException if the first argument does
* not denote an entity type or the second argument is
* is not a valid type for that entity's primary key or
* is null
* @since 2.0
*/
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties);
/**
* Find by primary key and lock.
* Search for an entity of the specified class and primary key
* and lock it with respect to the specified lock type.
* If the entity instance is contained in the persistence context,
* it is returned from there, and the effect of this method is
* the same as if the lock method had been called on the entity.
* <p> If the entity is found within the persistence context and the
* lock mode type is pessimistic and the entity has a version
* attribute, the persistence provider must perform optimistic
* version checks when obtaining the database lock. If these
* checks fail, the <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if the database
* locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the database
* locking failure causes only statement-level rollback
* </ul>
* @param entityClass entity class
* @param primaryKey primary key
* @param lockMode lock mode
* @return the found entity instance or null if the entity does
* not exist
* @throws IllegalArgumentException if the first argument does
* not denote an entity type or the second argument is
* not a valid type for that entity's primary key or
* is null
* @throws TransactionRequiredException if there is no
* transaction and a lock mode other than <code>NONE</code> is
* specified or if invoked on an entity manager which has
* not been joined to the current transaction and a lock
* mode other than <code>NONE</code> is specified
* @throws OptimisticLockException if the optimistic version
* check fails
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call
* is made
* @since 2.0
*/
public <T> T find(Class<T> entityClass, Object primaryKey,
LockModeType lockMode);
/**
* Find by primary key and lock, using the specified properties.
* Search for an entity of the specified class and primary key
* and lock it with respect to the specified lock type.
* If the entity instance is contained in the persistence context,
* it is returned from there.
* <p> If the entity is found
* within the persistence context and the lock mode type
* is pessimistic and the entity has a version attribute, the
* persistence provider must perform optimistic version checks
* when obtaining the database lock. If these checks fail,
* the <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if the database
* locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the database
* locking failure causes only statement-level rollback
* </ul>
* <p>If a vendor-specific property or hint is not recognized,
* it is silently ignored.
* <p>Portable applications should not rely on the standard timeout
* hint. Depending on the database in use and the locking
* mechanisms used by the provider, the hint may or may not
* be observed.
* @param entityClass entity class
* @param primaryKey primary key
* @param lockMode lock mode
* @param properties standard and vendor-specific properties
* and hints
* @return the found entity instance or null if the entity does
* not exist
* @throws IllegalArgumentException if the first argument does
* not denote an entity type or the second argument is
* not a valid type for that entity's primary key or
* is null
* @throws TransactionRequiredException if there is no
* transaction and a lock mode other than <code>NONE</code> is
* specified or if invoked on an entity manager which has
* not been joined to the current transaction and a lock
* mode other than <code>NONE</code> is specified
* @throws OptimisticLockException if the optimistic version
* check fails
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call
* is made
* @since 2.0
*/
public <T> T find(Class<T> entityClass, Object primaryKey,
LockModeType lockMode,
Map<String, Object> properties);
/**
* Find an instance of the given entity class by primary key,
* using the specified {@linkplain FindOption options}.
* Search for an entity with the specified class and primary key.
* If the given options include a {@link LockModeType}, lock it
* with respect to the specified lock type.
* If the entity instance is contained in the persistence context,
* it is returned from there.
* <p>If the entity is found within the persistence context and
* the lock mode type is pessimistic and the entity has a version
* attribute, the persistence provider must perform optimistic
* version checks when obtaining the database lock. If these checks
* fail, the <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown
* if the database locking failure causes transaction-level
* rollback
* <li> the <code>LockTimeoutException</code> will be thrown if
* the database locking failure causes only statement-level
* rollback
* </ul>
* <p>If a vendor-specific {@linkplain FindOption option} is not
* recognized, it is silently ignored.
* <p>Portable applications should not rely on the standard
* {@linkplain Timeout timeout option}. Depending on the database
* in use and the locking mechanisms used by the provider, this
* option may or may not be observed.
* @param entityClass entity class
* @param primaryKey primary key
* @param options standard and vendor-specific options
* @return the found entity instance or null if the entity does
* not exist
* @throws IllegalArgumentException if there are contradictory
* options, if the first argument does not denote an entity
* type belonging to the persistence unit, or if the second
* argument is not a valid non-null instance of the entity
* primary key type
* @throws TransactionRequiredException if there is no transaction
* and a lock mode other than <code>NONE</code> is
* specified or if invoked on an entity manager which has
* not been joined to the current transaction and a lock
* mode other than <code>NONE</code> is specified
* @throws OptimisticLockException if the optimistic version check
* fails
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call is made
* @since 3.2
*/
public <T> T find(Class<T> entityClass, Object primaryKey,
FindOption... options);
/**
* Find an instance of the root entity of the given {@link EntityGraph}
* by primary key, using the specified {@linkplain FindOption options},
* and interpreting the {@code EntityGraph} as a load graph.
* Search for an entity with the specified type and primary key.
* If the given options include a {@link LockModeType}, lock it
* with respect to the specified lock type.
* If the entity instance is contained in the persistence context,
* it is returned from there.
* <p> If the entity is found within the persistence context and
* the lock mode type is pessimistic and the entity has a version
* attribute, the persistence provider must perform optimistic
* version checks when obtaining the database lock. If these checks
* fail, the <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown
* if the database locking failure causes transaction-level
* rollback
* <li> the <code>LockTimeoutException</code> will be thrown if
* the database locking failure causes only statement-level
* rollback
* </ul>
* <p>If a vendor-specific {@linkplain FindOption option} is not
* recognized, it is silently ignored.
* <p>Portable applications should not rely on the standard
* {@linkplain Timeout timeout option}. Depending on the database
* in use and the locking mechanisms used by the provider, this
* option may or may not be observed.
* @param entityGraph entity graph interpreted as a load graph
* @param primaryKey primary key
* @param options standard and vendor-specific options
* @return the found entity instance or null if the entity does
* not exist
* @throws IllegalArgumentException if there are contradictory
* options, if the first argument does not denote an entity
* type belonging to the persistence unit, or if the second
* argument is not a valid non-null instance of the entity
* primary key type
* @throws TransactionRequiredException if there is no transaction
* and a lock mode other than <code>NONE</code> is
* specified or if invoked on an entity manager which has
* not been joined to the current transaction and a lock
* mode other than <code>NONE</code> is specified
* @throws OptimisticLockException if the optimistic version check
* fails
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call is made
* @since 3.2
*/
public <T> T find(EntityGraph<T> entityGraph, Object primaryKey,
FindOption... options);
/**
* Obtain a reference to an instance of the given entity class
* with the given primary key, whose state may be lazily fetched.
* <p>If the requested instance does not exist in the database,
* the <code>EntityNotFoundException</code> is thrown when the
* instance state is first accessed.
* (The persistence provider runtime is permitted but not
* required to throw the <code>EntityNotFoundException</code>
* when <code>getReference</code> is called.)
* <p>The application should not expect the instance state to
* be available upon detachment, unless it was accessed by the
* application while the entity manager was open.
* @param entityClass entity class
* @param primaryKey primary key
* @return a reference to the entity instance
* @throws IllegalArgumentException if the first argument does
* not denote an entity type or the second argument is
* not a valid type for that entity's primary key or
* is null
* @throws EntityNotFoundException if the entity state cannot
* be accessed
*/
public <T> T getReference(Class<T> entityClass, Object primaryKey);
/**
* Obtain a reference to an instance of the entity class of the
* given object, with the same primary key as the given object,
* whose state may be lazily fetched. The given object may be
* persistent or detached, but may be neither new nor removed.
* <p>If the requested instance does not exist in the database,
* the <code>EntityNotFoundException</code> is thrown when the
* instance state is first accessed.
* (The persistence provider runtime is permitted but not
* required to throw the <code>EntityNotFoundException</code>
* when <code>getReference</code> is called.)
* <p>The application should not expect the instance state to
* be available upon detachment, unless it was accessed by the
* application while the entity manager was open.
* @param entity a persistent or detached entity instance
* @return a reference to the entity instance
* @throws IllegalArgumentException if the given object is not
* an entity, or if it is neither persistent nor detached
* @throws EntityNotFoundException if the entity state cannot be
* accessed
*/
public <T> T getReference(T entity);
/**
* Synchronize the persistence context to the
* underlying database.
* @throws TransactionRequiredException if there is
* no transaction or if the entity manager has not been
* joined to the current transaction
* @throws PersistenceException if the flush fails
*/
public void flush();
/**
* Set the flush mode that applies to all objects contained
* in the persistence context.
* @param flushMode flush mode
*/
public void setFlushMode(FlushModeType flushMode);
/**
* Get the flush mode that applies to all objects contained
* in the persistence context.
* @return flushMode
*/
public FlushModeType getFlushMode();
/**
* Lock an entity instance that is contained in the persistence
* context with the specified lock mode type.
* <p>If a pessimistic lock mode type is specified and the entity
* contains a version attribute, the persistence provider must
* also perform optimistic version checks when obtaining the
* database lock. If these checks fail, the
* <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if the database
* locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the database
* locking failure causes only statement-level rollback
* </ul>
* @param entity entity instance
* @param lockMode lock mode
* @throws IllegalArgumentException if the instance is not an
* entity or is a detached entity
* @throws TransactionRequiredException if there is no
* transaction or if invoked on an entity manager which
* has not been joined to the current transaction
* @throws EntityNotFoundException if the entity does not exist
* in the database when pessimistic locking is
* performed
* @throws OptimisticLockException if the optimistic version
* check fails
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call
* is made
*/
public void lock(Object entity, LockModeType lockMode);
/**
* Lock an entity instance that is contained in the persistence
* context with the specified lock mode type and with specified
* properties.
* <p>If a pessimistic lock mode type is specified and the entity
* contains a version attribute, the persistence provider must
* also perform optimistic version checks when obtaining the
* database lock. If these checks fail, the
* <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if the database
* locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the database
* locking failure causes only statement-level rollback
* </ul>
* <p>If a vendor-specific property or hint is not recognized,
* it is silently ignored.
* <p>Portable applications should not rely on the standard timeout
* hint. Depending on the database in use and the locking
* mechanisms used by the provider, the hint may or may not
* be observed.
* @param entity entity instance
* @param lockMode lock mode
* @param properties standard and vendor-specific properties
* and hints
* @throws IllegalArgumentException if the instance is not an
* entity or is a detached entity
* @throws TransactionRequiredException if there is no
* transaction or if invoked on an entity manager which
* has not been joined to the current transaction
* @throws EntityNotFoundException if the entity does not exist
* in the database when pessimistic locking is
* performed
* @throws OptimisticLockException if the optimistic version
* check fails
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call
* is made
* @since 2.0
*/
public void lock(Object entity, LockModeType lockMode,
Map<String, Object> properties);
/**
* Lock an entity instance that is contained in the persistence
* context with the specified lock mode type, using specified
* {@linkplain LockOption options}.
* <p>If a pessimistic lock mode type is specified and the entity
* contains a version attribute, the persistence provider must
* also perform optimistic version checks when obtaining the
* database lock. If these checks fail, the
* <code>OptimisticLockException</code> will be thrown.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown
* if the database locking failure causes transaction-level
* rollback
* <li> the <code>LockTimeoutException</code> will be thrown if
* the database locking failure causes only statement-level
* rollback
* </ul>
* <p>If a vendor-specific {@link LockOption} is not recognized,
* it is silently ignored.
* <p>Portable applications should not rely on the standard
* {@linkplain Timeout timeout option}. Depending on the database
* in use and the locking mechanisms used by the provider, the
* option may or may not be observed.
* @param entity entity instance
* @param lockMode lock mode
* @param options standard and vendor-specific options
* @throws IllegalArgumentException if the instance is not an
* entity or is a detached entity
* @throws TransactionRequiredException if there is no
* transaction or if invoked on an entity manager which
* has not been joined to the current transaction
* @throws EntityNotFoundException if the entity does not exist
* in the database when pessimistic locking is
* performed
* @throws OptimisticLockException if the optimistic version
* check fails
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call is made
* @since 3.2
*/
public void lock(Object entity, LockModeType lockMode,
LockOption... options);
/**
* Refresh the state of the instance from the database,
* overwriting changes made to the entity, if any.
* @param entity entity instance
* @throws IllegalArgumentException if the instance is not
* an entity or the entity is not managed
* @throws TransactionRequiredException if there is no
* transaction when invoked on a container-managed
* entity manager of type <code>PersistenceContextType.TRANSACTION</code>
* @throws EntityNotFoundException if the entity no longer
* exists in the database
*/
public void refresh(Object entity);
/**
* Refresh the state of the instance from the database, using
* the specified properties, and overwriting changes made to
* the entity, if any.
* <p> If a vendor-specific property or hint is not recognized,
* it is silently ignored.
* @param entity entity instance
* @param properties standard and vendor-specific properties
* and hints
* @throws IllegalArgumentException if the instance is not
* an entity or the entity is not managed
* @throws TransactionRequiredException if there is no
* transaction when invoked on a container-managed
* entity manager of type <code>PersistenceContextType.TRANSACTION</code>
* @throws EntityNotFoundException if the entity no longer
* exists in the database
* @since 2.0
*/
public void refresh(Object entity,
Map<String, Object> properties);
/**
* Refresh the state of the instance from the database,
* overwriting changes made to the entity, if any, and
* lock it with respect to given lock mode type.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if the database
* locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the
* database locking failure causes only statement-level
* rollback.
* </ul>
* @param entity entity instance
* @param lockMode lock mode
* @throws IllegalArgumentException if the instance is not
* an entity or the entity is not managed
* @throws TransactionRequiredException if invoked on a
* container-managed entity manager of type
* <code>PersistenceContextType.TRANSACTION</code> when there is
* no transaction; if invoked on an extended entity manager when
* there is no transaction and a lock mode other than <code>NONE</code>
* has been specified; or if invoked on an extended entity manager
* that has not been joined to the current transaction and a
* lock mode other than <code>NONE</code> has been specified
* @throws EntityNotFoundException if the entity no longer exists
* in the database
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call
* is made
* @since 2.0
*/
public void refresh(Object entity, LockModeType lockMode);
/**
* Refresh the state of the instance from the database,
* overwriting changes made to the entity, if any, and
* lock it with respect to given lock mode type and with
* specified properties.
* <p>If the lock mode type is pessimistic and the entity instance
* is found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if the database
* locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the database
* locking failure causes only statement-level rollback
* </ul>
* <p>If a vendor-specific property or hint is not recognized,
* it is silently ignored.
* <p>Portable applications should not rely on the standard timeout
* hint. Depending on the database in use and the locking
* mechanisms used by the provider, the hint may or may not
* be observed.
* @param entity entity instance
* @param lockMode lock mode
* @param properties standard and vendor-specific properties
* and hints
* @throws IllegalArgumentException if the instance is not
* an entity or the entity is not managed
* @throws TransactionRequiredException if invoked on a
* container-managed entity manager of type
* <code>PersistenceContextType.TRANSACTION</code> when there is
* no transaction; if invoked on an extended entity manager when
* there is no transaction and a lock mode other than <code>NONE</code>
* has been specified; or if invoked on an extended entity manager
* that has not been joined to the current transaction and a
* lock mode other than <code>NONE</code> has been specified
* @throws EntityNotFoundException if the entity no longer exists
* in the database
* @throws PessimisticLockException if pessimistic locking fails
* and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and
* only the statement is rolled back
* @throws PersistenceException if an unsupported lock call
* is made
* @since 2.0
*/
public void refresh(Object entity, LockModeType lockMode,
Map<String, Object> properties);
/**
* Refresh the state of the given entity instance from the
* database, using the specified {@linkplain RefreshOption options},
* overwriting changes made to the entity, if any. If the supplied
* options include a {@link LockModeType}, lock the given entity with
* respect to the specified lock type.
* <p>If the lock mode type is pessimistic and the entity instance is
* found but cannot be locked:
* <ul>
* <li> the <code>PessimisticLockException</code> will be thrown if
* the database locking failure causes transaction-level rollback
* <li> the <code>LockTimeoutException</code> will be thrown if the
* database locking failure causes only statement-level rollback
* </ul>
* <p>If a vendor-specific {@link RefreshOption} is not recognized,
* it is silently ignored.
* <p>Portable applications should not rely on the standard
* {@linkplain Timeout timeout option}. Depending on the database in
* use and the locking mechanisms used by the provider, the hint may
* or may not be observed.
* @param entity entity instance
* @param options standard and vendor-specific options
* @throws IllegalArgumentException if the instance is not an entity
* or the entity is not managed
* @throws TransactionRequiredException if invoked on a
* container-managed entity manager of type
* <code>PersistenceContextType.TRANSACTION</code> when there
* is no transaction; if invoked on an extended entity manager
* when there is no transaction and a lock mode other than
* <code>NONE</code> has been specified; or if invoked on an
* extended entity manager that has not been joined to the
* current transaction and a lock mode other than
* <code>NONE</code> has been specified
* @throws EntityNotFoundException if the entity no longer exists in
* the database
* @throws PessimisticLockException if pessimistic locking fails and
* the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking fails and only
* the statement is rolled back
* @throws PersistenceException if an unsupported lock call is made
* @since 3.2
*/
public void refresh(Object entity,
RefreshOption... options);
/**
* Clear the persistence context, causing all managed
* entities to become detached. Changes made to entities that
* have not been flushed to the database will not be
* persisted.
*/
public void clear();
/**
* Remove the given entity from the persistence context, causing
* a managed entity to become detached. Unflushed changes made
* to the entity if any (including removal of the entity),
* will not be synchronized to the database. Entities which
* previously referenced the detached entity will continue to
* reference it.
* @param entity entity instance
* @throws IllegalArgumentException if the instance is not an
* entity
* @since 2.0
*/
public void detach(Object entity);
/**
* Check if the instance is a managed entity instance belonging
* to the current persistence context.
* @param entity entity instance
* @return boolean indicating if entity is in persistence context
* @throws IllegalArgumentException if not an entity
*/
public boolean contains(Object entity);
/**
* Get the current lock mode for the entity instance.
* @param entity entity instance
* @return lock mode
* @throws TransactionRequiredException if there is no
* transaction or if the entity manager has not been
* joined to the current transaction
* @throws IllegalArgumentException if the instance is not a
* managed entity and a transaction is active
* @since 2.0
*/
public LockModeType getLockMode(Object entity);
/**
* Set the cache retrieval mode that is in effect during
* query execution. This cache retrieval mode overrides the
* cache retrieve mode in use by the entity manager.
* @param cacheRetrieveMode cache retrieval mode
* @since 3.2
*/
public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode);
/**
* Set the default cache storage mode for this persistence context.
* @param cacheStoreMode cache storage mode
* @since 3.2
*/
public void setCacheStoreMode(CacheStoreMode cacheStoreMode);
/**
* The cache retrieval mode for this persistence context.
* @since 3.2
*/
public CacheRetrieveMode getCacheRetrieveMode();
/**
* The cache storage mode for this persistence context.
* @since 3.2
*/
public CacheStoreMode getCacheStoreMode();
/**
* Set an entity manager property or hint.
* If a vendor-specific property or hint is not recognized, it is
* silently ignored.
* @param propertyName name of property or hint
* @param value value for property or hint
* @throws IllegalArgumentException if the second argument is
* not valid for the implementation
* @since 2.0
*/
public void setProperty(String propertyName, Object value);
/**
* Get the properties and hints and associated values that are in effect
* for the entity manager. Changing the contents of the map does
* not change the configuration in effect.
* @return map of properties and hints in effect for entity manager
* @since 2.0
*/
public Map<String, Object> getProperties();
/**
* Create an instance of <code>Query</code> for executing a
* Jakarta Persistence query language statement.
* @param qlString a Jakarta Persistence query string
* @return the new query instance
* @throws IllegalArgumentException if the query string is
* found to be invalid
*/
public Query createQuery(String qlString);
/**
* Create an instance of <code>TypedQuery</code> for executing a
* criteria query.
* @param criteriaQuery a criteria query object
* @return the new query instance
* @throws IllegalArgumentException if the criteria query is
* found to be invalid
* @since 2.0
*/
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery);
/**
* Create an instance of <code>TypedQuery</code> for executing a
* criteria query, which may be a union or intersection of
* top-level queries.
* @param criteriaQuery a criteria query object
* @return the new query instance
* @throws IllegalArgumentException if the criteria query is
* found to be invalid
* @since 3.2
*/
<T> TypedQuery<T> createQuery(CriteriaSelect<T> criteriaQuery);
/**
* Create an instance of <code>Query</code> for executing a criteria
* update query.
* @param updateQuery a criteria update query object
* @return the new query instance
* @throws IllegalArgumentException if the update query is
* found to be invalid
* @since 2.1
*/
public Query createQuery(CriteriaUpdate updateQuery);
/**
* Create an instance of <code>Query</code> for executing a criteria
* delete query.
* @param deleteQuery a criteria delete query object
* @return the new query instance
* @throws IllegalArgumentException if the delete query is
* found to be invalid
* @since 2.1
*/
public Query createQuery(CriteriaDelete deleteQuery);
/**
* Create an instance of <code>TypedQuery</code> for executing a
* Jakarta Persistence query language statement.
* The select list of the query must contain only a single
* item, which must be assignable to the type specified by
* the <code>resultClass</code> argument.
* @param qlString a Jakarta Persistence query string
* @param resultClass the type of the query result
* @return the new query instance
* @throws IllegalArgumentException if the query string is found
* to be invalid or if the query result is found to
* not be assignable to the specified type
* @since 2.0
*/
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass);
/**
* Create an instance of <code>Query</code> for executing a named query
* (in the Jakarta Persistence query language or in native SQL).
* @param name the name of a query defined in metadata
* @return the new query instance
* @throws IllegalArgumentException if a query has not been
* defined with the given name or if the query string is
* found to be invalid
*/
public Query createNamedQuery(String name);
/**
* Create an instance of <code>TypedQuery</code> for executing a
* Jakarta Persistence query language named query.
* The select list of the query must contain only a single
* item, which must be assignable to the type specified by
* the <code>resultClass</code> argument.
* @param name the name of a query defined in metadata
* @param resultClass the type of the query result
* @return the new query instance
* @throws IllegalArgumentException if a query has not been
* defined with the given name or if the query string is
* found to be invalid or if the query result is found to
* not be assignable to the specified type
* @since 2.0
*/
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass);
/**
* Create an instance of <code>Query</code> for executing
* a native SQL statement, e.g., for update or delete.
* If the query is not an update or delete query, query
* execution will result in each row of the SQL result
* being returned as a result of type Object[] (or a result
* of type Object if there is only one column in the select
* list.) Column values are returned in the order of their
* appearance in the select list and default JDBC type
* mappings are applied.
* @param sqlString a native SQL query string
* @return the new query instance
*/
public Query createNativeQuery(String sqlString);
/**
* Create an instance of <code>Query</code> for executing
* a native SQL query.
* @param sqlString a native SQL query string
* @param resultClass the class of the resulting instance(s)
* @return the new query instance
*/
public Query createNativeQuery(String sqlString, Class resultClass);
/**
* Create an instance of <code>Query</code> for executing
* a native SQL query.
* @param sqlString a native SQL query string
* @param resultSetMapping the name of the result set mapping
* @return the new query instance
*/
public Query createNativeQuery(String sqlString, String resultSetMapping);
/**
* Create an instance of <code>StoredProcedureQuery</code> for executing a
* stored procedure in the database.
* <p>Parameters must be registered before the stored procedure can
* be executed.
* <p>If the stored procedure returns one or more result sets,
* any result set will be returned as a list of type Object[].
* @param name name assigned to the stored procedure query
* in metadata
* @return the new stored procedure query instance
* @throws IllegalArgumentException if a query has not been
* defined with the given name
* @since 2.1
*/
public StoredProcedureQuery createNamedStoredProcedureQuery(String name);
/**
* Create an instance of <code>StoredProcedureQuery</code> for executing a
* stored procedure in the database.
* <p>Parameters must be registered before the stored procedure can
* be executed.
* <p>If the stored procedure returns one or more result sets,
* any result set will be returned as a list of type Object[].
* @param procedureName name of the stored procedure in the
* database
* @return the new stored procedure query instance
* @throws IllegalArgumentException if a stored procedure of the
* given name does not exist (or the query execution will
* fail)
* @since 2.1
*/
public StoredProcedureQuery createStoredProcedureQuery(String procedureName);
/**
* Create an instance of <code>StoredProcedureQuery</code> for executing a
* stored procedure in the database.
* <p>Parameters must be registered before the stored procedure can
* be executed.
* <p>The <code>resultClass</code> arguments must be specified in the order in
* which the result sets will be returned by the stored procedure
* invocation.
* @param procedureName name of the stored procedure in the
* database
* @param resultClasses classes to which the result sets
* produced by the stored procedure are to
* be mapped
* @return the new stored procedure query instance
* @throws IllegalArgumentException if a stored procedure of the
* given name does not exist (or the query execution will
* fail)
* @since 2.1
*/
public StoredProcedureQuery createStoredProcedureQuery(
String procedureName, Class... resultClasses);
/**
* Create an instance of <code>StoredProcedureQuery</code> for executing a
* stored procedure in the database.
* <p>Parameters must be registered before the stored procedure can
* be executed.
* <p>The <code>resultSetMapping</code> arguments must be specified in the order
* in which the result sets will be returned by the stored
* procedure invocation.
* @param procedureName name of the stored procedure in the
* database
* @param resultSetMappings the names of the result set mappings
* to be used in mapping result sets
* returned by the stored procedure
* @return the new stored procedure query instance
* @throws IllegalArgumentException if a stored procedure or
* result set mapping of the given name does not exist
* (or the query execution will fail)
*/
public StoredProcedureQuery createStoredProcedureQuery(
String procedureName, String... resultSetMappings);
/**
* Indicate to the entity manager that a JTA transaction is
* active and join the persistence context to it.
* <p>This method should be called on a JTA application
* managed entity manager that was created outside the scope
* of the active transaction or on an entity manager of type
* <code>SynchronizationType.UNSYNCHRONIZED</code> to associate
* it with the current JTA transaction.
* @throws TransactionRequiredException if there is
* no transaction
*/
public void joinTransaction();
/**
* Determine whether the entity manager is joined to the
* current transaction. Returns false if the entity manager
* is not joined to the current transaction or if no
* transaction is active
* @return boolean
* @since 2.1
*/
public boolean isJoinedToTransaction();
/**
* Return an object of the specified type to allow access to the
* provider-specific API. If the provider's <code>EntityManager</code>
* implementation does not support the specified class, the
* <code>PersistenceException</code> is thrown.
* @param cls the class of the object to be returned. This is
* normally either the underlying <code>EntityManager</code> implementation
* class or an interface that it implements.
* @return an instance of the specified class
* @throws PersistenceException if the provider does not
* support the call
* @since 2.0
*/
public <T> T unwrap(Class<T> cls);
/**
* Return the underlying provider object for the <code>EntityManager</code>,
* if available. The result of this method is implementation
* specific.
* <p>The <code>unwrap</code> method is to be preferred for new applications.
* @return underlying provider object for EntityManager
*/
public Object getDelegate();
/**
* Close an application-managed entity manager.
* After the close method has been invoked, all methods
* on the <code>EntityManager</code> instance and any
* <code>Query</code>, <code>TypedQuery</code>, and
* <code>StoredProcedureQuery</code> objects obtained from
* it will throw the <code>IllegalStateException</code>
* except for <code>getProperties</code>,
* <code>getTransaction</code>, and <code>isOpen</code> (which will return false).
* If this method is called when the entity manager is
* joined to an active transaction, the persistence
* context remains managed until the transaction completes.
* @throws IllegalStateException if the entity manager
* is container-managed
*/
public void close();
/**
* Determine whether the entity manager is open.
* @return true until the entity manager has been closed
*/
public boolean isOpen();
/**
* Return the resource-level <code>EntityTransaction</code> object.
* The <code>EntityTransaction</code> instance may be used serially to
* begin and commit multiple transactions.
* @return EntityTransaction instance
* @throws IllegalStateException if invoked on a JTA
* entity manager
*/
public EntityTransaction getTransaction();
/**
* Return the entity manager factory for the entity manager.
* @return EntityManagerFactory instance
* @throws IllegalStateException if the entity manager has
* been closed
* @since 2.0
*/
public EntityManagerFactory getEntityManagerFactory();
/**
* Return an instance of <code>CriteriaBuilder</code> for the creation of
* <code>CriteriaQuery</code> objects.
* @return CriteriaBuilder instance
* @throws IllegalStateException if the entity manager has
* been closed
* @since 2.0
*/
public CriteriaBuilder getCriteriaBuilder();
/**
* Return an instance of <code>Metamodel</code> interface for access to the
* metamodel of the persistence unit.
* @return Metamodel instance
* @throws IllegalStateException if the entity manager has
* been closed
* @since 2.0
*/
public Metamodel getMetamodel();
/**
* Return a mutable EntityGraph that can be used to dynamically create an
* EntityGraph.
* @param rootType class of entity graph
* @return entity graph
* @since 2.1
*/
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType);
/**
* Return a mutable copy of the named EntityGraph. If there
* is no entity graph with the specified name, null is returned.
* @param graphName name of an entity graph
* @return entity graph
* @since 2.1
*/
public EntityGraph<?> createEntityGraph(String graphName);
/**
* Return a named EntityGraph. The returned EntityGraph
* should be considered immutable.
* @param graphName name of an existing entity graph
* @return named entity graph
* @throws IllegalArgumentException if there is no EntityGraph of
* the given name
* @since 2.1
*/
public EntityGraph<?> getEntityGraph(String graphName);
/**
* Return all named EntityGraphs that have been defined for the provided
* class type.
* @param entityClass entity class
* @return list of all entity graphs defined for the entity
* @throws IllegalArgumentException if the class is not an entity
* @since 2.1
*/
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass);
/**
* Execute the given action using the database connection underlying this
* {@code EntityManager}. Usually, the connection is a JDBC connection, but a
* provider might support some other native connection type, and is not required
* to support {@code java.sql.Connection}. If this {@code EntityManager} is
* associated with a transaction, the action is executed in the context of the
* transaction. The given action should close any resources it creates, but should
* not close the connection itself, nor commit or roll back the transaction. If
* the given action throws an exception, the persistence provider must mark the
* transaction for rollback.
* @param action the action
* @param <C> the connection type, usually {@code java.sql.Connection}
* @throws PersistenceException wrapping the checked {@link Exception} thrown by
* {@link ConnectionConsumer#accept}, if any
* @since 3.2
*/
public <C> void runWithConnection(ConnectionConsumer<C> action);
/**
* Call the given function and return its result using the database connection
* underlying this {@code EntityManager}. Usually, the connection is a JDBC
* connection, but a provider might support some other native connection type,
* and is not required to support {@code java.sql.Connection}. If this
* {@code EntityManager} is associated with a transaction, the function is
* executed in the context of the transaction. The given function should close
* any resources it creates, but should not close the connection itself, nor
* commit or roll back the transaction. If the given action throws an exception,
* the persistence provider must mark the transaction for rollback.
* @param function the function
* @param <C> the connection type, usually {@code java.sql.Connection}
* @param <T> the type of result returned by the function
* @return the value returned by {@link ConnectionFunction#apply}.
* @throws PersistenceException wrapping the checked {@link Exception} thrown by
* {@link ConnectionFunction#apply}, if any
* @since 3.2
*/
public <C,T> T callWithConnection(ConnectionFunction<C,T> function);
}
The semantics of public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) method may be extended in a future release of this specification to support other result types. Applications that specify other result types (e.g., Tuple.class) will not be portable. |
The semantics public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) method may be extended in a future release of this specification to support other result types. Applications that specify other result types (e.g., Tuple.class) will not be portable. |
The persist
, merge
, remove
, and
refresh
methods must be invoked within a transaction context when an
entity manager with a transaction-scoped persistence context is used. If
there is no transaction context, the
jakarta.persistence.TransactionRequiredException
is thrown.
Methods that specify a lock mode other than
LockModeType.NONE
must be invoked within a transaction. If there is no
transaction or if the entity manager has not been joined to the
transaction, the jakarta.persistence.TransactionRequiredException
is
thrown.
The find
method (provided it is invoked
without a lock or invoked with LockModeType.NONE
) and the
getReference
method are not required to be invoked within a
transaction. If an entity manager with transaction-scoped persistence
context is in use, the resulting entities will be detached; if an entity
manager with an extended persistence context is used, they will be
managed. See Section 3.4 for entity manager use outside a
transaction.
The Query
, TypedQuery
,
StoredProcedureQuery
, CriteriaBuilder
, Metamodel
, and
EntityTransaction
objects obtained from an entity manager are valid
while that entity manager is open.
If the argument to the createQuery
method
is not a valid Jakarta Persistence query string or a valid CriteriaQuery
object, the IllegalArgumentException
may be thrown or the query
execution will fail and a PersistenceException
will be thrown. If the
result class specification of a Jakarta Persistence query language query is
incompatible with the result of the query, the
IllegalArgumentException
may be thrown when the createQuery
method
is invoked or the query execution will fail and a PersistenceException
will be thrown when the query is executed. If a native query is not a
valid query for the database in use or if the result set specification
is incompatible with the result of the query, the query execution will
fail and a PersistenceException
will be thrown when the query is
executed. The PersistenceException
should wrap the underlying database
exception when possible.
Runtime exceptions thrown by the methods of
the EntityManager
interface other than the LockTimeoutException
will
cause the current transaction to be marked for rollback if the
persistence context is joined to that transaction.
The methods close
, isOpen
,
joinTransaction
, and getTransaction
are used to manage
application-managed entity managers and their lifecycle. See Section 7.2.2.
The EntityManager
interface and other
interfaces defined by this specification contain methods that take
properties and/or hints as arguments. This specification distinguishes
between properties
and hints
as follows:
-
A property defined by this specification must be observed by the provider unless otherwise explicitly stated.
-
A hint specifies a preference on the part of the application. While a hint defined by this specification should be observed by the provider if possible, a hint may or may not always be observed. A portable application must not depend on the observance of a hint.
For example:
@Stateless
public class OrderEntryBean implements OrderEntry {
@PersistenceContext
EntityManager em;
public void enterOrder(int custID, Order newOrder) {
Customer cust = em.find(Customer.class, custID);
cust.getOrders().add(newOrder);
newOrder.setCustomer(cust);
em.persist(newOrder);
}
}
3.3. Entity Instance’s Life Cycle
This section describes the EntityManager
operations for managing an entity instance’s lifecycle. An entity
instance can be characterized as being new, managed, detached, or
removed.
-
A new entity instance has no persistent identity, and is not yet associated with a persistence context.
-
A managed entity instance is an instance with a persistent identity that is currently associated with a persistence context.
-
A detached entity instance is an instance with a persistent identity that is not (or no longer) associated with a persistence context.
-
A removed entity instance is an instance with a persistent identity, associated with a persistence context, that will be removed from the database upon transaction commit.
The following subsections describe the effect
of lifecycle operations upon entities. Use of the cascade
annotation
element may be used to propagate the effect of an operation to
associated entities. The cascade functionality is most typically used in
parent-child relationships.
3.3.1. Entity Instance Creation
Entity instances are created by means of the
new
operation. An entity instance, when first created by new
is not
yet persistent. An instance becomes persistent by means of the
EntityManager
API.
3.3.2. Persisting an Entity Instance
A new entity instance becomes both managed
and persistent by invoking the persist
method on it or by cascading
the persist operation.
The semantics of the persist operation,
applied to an entity X
are as follows:
-
If X is a new entity, it becomes managed. The entity X will be entered into the database at or before transaction commit or as a result of the flush operation.
-
If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities are annotated with the
cascade=PERSIST
orcascade=ALL
annotation element value or specified with the equivalent XML descriptor element. -
If X is a removed entity, it becomes managed.
-
If X is a detached object, the
EntityExistsException
may be thrown when the persist operation is invoked, or theEntityExistsException
or anotherPersistenceException
may
be thrown at flush or commit time. -
For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the
cascade
element valuecascade=PERSIST
orcascade=ALL
, the persist operation is applied to Y.
3.3.3. Removal
A managed entity instance becomes removed by
invoking the remove
method on it or by cascading the remove operation.
The semantics of the remove operation, applied to an entity X are as follows:
-
If X is a new entity, it is ignored by the remove operation. However, the remove operation is cascaded to entities referenced by X, if the relationship from X to these other entities is annotated with the
cascade=REMOVE
orcascade=ALL
annotation element value. -
If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to entities referenced by X, if the relationships from X to these other entities is annotated with the
cascade=REMOVE
orcascade=ALL
annotation element value. -
If X is a detached entity, an
IllegalArgumentException
will be thrown by the remove operation (or the transaction commit will fail). -
If X is a removed entity, it is ignored by the remove operation.
-
A removed entity X will be removed from the database at or before transaction commit or as a result of the flush operation.
After an entity has been removed, its state (except for generated state) will be that of the entity at the point at which the remove operation was called.
3.3.4. Synchronization to the Database
In general, a persistence context will be
synchronized to the database as described below. However, a persistence
context of type SynchronizationType.UNSYNCHRONIZED
or an
application-managed persistence context that has been created outside
the scope of the current transaction will only be synchronized to the
database if it has been joined to the current transaction by the
application’s use of the EntityManager
joinTransaction
method.
The state of persistent entities is synchronized to the database at transaction commit. This synchronization involves writing to the database any updates to persistent entities and their relationships as specified above.
An update to the state of an entity includes both the assignment of a new value to a persistent property or field of the entity as well as the modification of a mutable value of a persistent property or field[32].
Synchronization to the database does not
involve a refresh of any managed entities unless the refresh
operation
is explicitly invoked on those entities or cascaded to them as a result
of the specification of the cascade=REFRESH
or cascade=ALL
annotation element value.
Bidirectional relationships between managed entities will be persisted based on references held by the owning side of the relationship. It is the developer’s responsibility to keep the in-memory references held on the owning side and those held on the inverse side consistent with each other when they change. In the case of unidirectional one-to-one and one-to-many relationships, it is the developer’s responsibility to insure that the semantics of the relationships are adhered to.[33]
It is particularly important to ensure that changes to the inverse side of a relationship result in appropriate updates on the owning side, so as to ensure the changes are not lost when they are synchronized to the database. |
The persistence provider runtime is permitted
to perform synchronization to the database at other times as well when a
transaction is active and the persistence context is joined to the
transaction. The flush
method can be used by the application to force
synchronization. It applies to entities associated with the persistence
context. The setFlushMode
methods of the EntityManager
, Query
,
TypedQuery
, and StoredProcedureQuery
interfaces can be used to
control synchronization semantics. The effect of FlushModeType.AUTO
is
defined in Section 3.11.8. If FlushModeType.COMMIT
is specified, flushing will occur at
transaction commit; the persistence provider is permitted, but not
required, to perform to flush at other times. If there is no transaction
active or if the persistence context has not been joined to the current
transaction, the persistence provider must not flush to the database.
The semantics of the flush operation, applied
to an entity X
are as follows:
-
If X is a managed entity, it is synchronized to the database.
-
For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the
cascade
element valuecascade=PERSIST
orcascade=ALL
, the persist operation is applied to Y. -
For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the
cascade
element valuecascade=PERSIST
orcascade=ALL
:-
If Y is new or removed, an
IllegalStateException
will be thrown by the flush operation (and the transaction marked for rollback) or the transaction commit will fail. -
If Y is detached, the semantics depend upon the ownership of the relationship. If X owns the relationship, any changes to the relationship are synchronized with the database; otherwise, if Y owns the relationships, the behavior is undefined.
-
-
-
If X is a removed entity, it is removed from the database. No cascade options are relevant.
3.3.5. Refreshing an Entity Instance
The state of a managed entity instance is
refreshed from the database by invoking the refresh
method on it or by
cascading the refresh operation.
The semantics of the refresh operation, applied to an entity X are as follows:
-
If X is a managed entity, the state of X is refreshed from the database, overwriting changes made to the entity, if any. The refresh operation is cascaded to entities referenced by X if the relationship from X to these other entities is annotated with the
cascade=REFRESH
orcascade=ALL
annotation element value. -
If X is a new, detached, or removed entity, the
IllegalArgumentException
is thrown.
3.3.6. Evicting an Entity Instance from the Persistence Context
An entity instance is removed from the
persistence context by invoking the detach
method on it or cascading
the detach operation. Changes made to the entity, if any (including
removal of the entity), will not be synchronized to the database after
such eviction has taken place.
Applications must use the flush
method
prior to the detach
method to ensure portable semantics if changes
have been made to the entity (including removal of the entity). Because
the persistence provider may write to the database at times other than
the explicit invocation of the flush
method, portable applications
must not assume that changes have not been written to the database if
the flush
method has not been called prior to detach.
The semantics of the detach operation, applied to an entity X are as follows:
-
If X is a managed entity, the detach operation causes it to become detached. The detach operation is cascaded to entities referenced by X if the relationships from X to these other entities is annotated with the
cascade=DETACH
orcascade=ALL
annotation element value. Entities which previously referenced X will continue to reference X. -
If X is a new or detached entity, it is ignored by the detach operation.
-
If X is a removed entity, the detach operation causes it to become detached. The detach operation is cascaded to entities referenced by X if the relationships from X to these other entities is annotated with the
cascade=DETACH
orcascade=ALL
annotation element value. Entities which previously referenced X will continue to reference X. Portable applications should not pass removed entities that have been detached from the persistence context to further EntityManager operations.
3.3.7. Detached Entities
A detached entity results from transaction commit if a transaction-scoped persistence context is used (see Section 3.4); from transaction rollback (see Section 3.4.3); from detaching the entity from the persistence context; from clearing the persistence context; from closing an entity manager; or from serializing an entity or otherwise passing an entity by value—e.g., to a separate application tier, through a remote interface, etc.
Detached entity instances continue to live outside of the persistence context in which they were persisted or retrieved. Their state is no longer guaranteed to be synchronized with the database state.
The application may access the available state of available detached entity instances after the persistence context ends. The available state includes:
-
Any persistent field or property not marked
fetch=LAZY
-
Any persistent field or property that was accessed by the application or fetched by means of an entity graph
If the persistent field or property is an association, the available state of an associated instance may only be safely accessed if the associated instance is available. The available instances include:
-
Any entity instance retrieved using
find()
. -
Any entity instances retrieved using a query or explicitly requested in a fetch join.
-
Any entity instance for which an instance variable holding non-primary-key persistent state was accessed by the application.
-
Any entity instance that can be reached from another available instance by navigating associations marked
fetch=EAGER
.
3.3.7.1. Merging Detached Entity State
The merge operation allows for the propagation of state from detached entities onto persistent entities managed by the entity manager.
The semantics of the merge operation applied to an entity X are as follows:
-
If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.
-
If X is a new entity instance, a new managed entity instance X' is created and the state of X is
copied
into the new managed entity instance X'. -
If X is a removed entity instance, an
IllegalArgumentException
will be thrown by the merge operation (or the transaction commit will fail). -
If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the
cascade
element valuecascade=MERGE
orcascade=ALL
annotation. -
For all entities Y referenced by relationships from X having the
cascade
element valuecascade=MERGE
orcascade=ALL
, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.) -
If X is an entity merged to X', with a reference to another entity Y, where
cascade=MERGE
orcascade=ALL
is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.
The persistence provider must not merge fields marked LAZY that have not been fetched: it must ignore such fields when merging.
Any Version
columns used by the entity must
be checked by the persistence runtime implementation during the merge
operation and/or at flush or commit time. In the absence of Version
columns there is no additional version checking done by the persistence
provider runtime during the merge operation.
3.3.7.2. Detached Entities and Lazy Loading
Serializing entities and merging those entities back into a persistence context may not be interoperable across vendors when lazy properties or fields and/or relationships are used.
A vendor is required to support the serialization and subsequent deserialization and merging of detached entity instances (which may contain lazy properties or fields and/or relationships that have not been fetched) back into a separate JVM instance of that vendor’s runtime, where both runtime instances have access to the entity classes and any required vendor persistence implementation classes.
When interoperability across vendors is required, the application must not use lazy loading.
3.3.8. Managed Instances
It is the responsibility of the application to insure that an instance is managed in only a single persistence context. The behavior is undefined if the same Java instance is made managed in more than one persistence context.
The contains()
method can be used to
determine whether an entity instance is managed in the current
persistence context.
The contains
method returns true:
-
If the entity has been retrieved from the database or has been returned by
getReference
, and has not been removed or detached. -
If the entity instance is new, and the
persist
method has been called on the entity or the persist operation has been cascaded to it.
The contains
method returns false:
-
If the instance is detached.
-
If the
remove
method has been called on the entity, or the remove operation has been cascaded to it. -
If the instance is new, and the
persist
method has not been called on the entity or the persist operation has not been cascaded to it.
Note that the effect of the cascading of
persist, merge, remove, or detach is immediately visible to the
contains
method, whereas the actual insertion, modification, or
deletion of the database representation for the entity may be deferred
until the end of the transaction.
3.3.9. Load State
An entity is considered to be loaded if all
attributes with FetchType.EAGER
—whether explictly specified or by
default—(including relationship and other collection-valued attributes)
have been loaded from the database or assigned by the application.
Attributes with FetchType.LAZY
may or may not have been loaded. The
available state of the entity instance and associated instances is as
described in Section 3.3.7.
An attribute that is an embeddable is
considered to be loaded if the embeddable attribute was loaded from the
database or assigned by the application, and, if the attribute
references an embeddable instance (i.e., is not null), the embeddable
instance state is known to be loaded (i.e., all attributes of the
embeddable with FetchType.EAGER
have been loaded from the database or
assigned by the application).
A collection-valued attribute is considered to be loaded if the collection was loaded from the database or the value of the attribute was assigned by the application, and, if the attribute references a collection instance (i.e., is not null), each element of the collection (e.g. entity or embeddable) is considered to be loaded.
A single-valued relationship attribute is considered to be loaded if the relationship attribute was loaded from the database or assigned by the application, and, if the attribute references an entity instance (i.e., is not null), the entity instance state is known to be loaded.
A basic attribute is considered to be loaded if its state has been loaded from the database or assigned by the application.
The PersistenceUtil.isLoaded
methods can be
used to determine the load state of an entity and its attributes
regardless of the persistence unit with which the entity is associated.
The PersistenceUtil.isLoaded
methods return true if the above
conditions hold, and false otherwise. If the persistence unit is known,
the PersistenceUnitUtil.isLoaded
methods can be used instead. See Section 7.11.
Persistence provider contracts for determining the load state of an entity or entity attribute are described in Section 9.9.1.
3.4. Persistence Context Lifetime and Synchronization Type
The lifetime of a container-managed
persistence context can either be scoped to a transaction
(transaction-scoped persistence context), or have a lifetime scope that
extends beyond that of a single transaction (extended persistence
context). The enum PersistenceContextType
is used to define the
persistence context lifetime scope for container-managed entity
managers. The persistence context lifetime scope is defined when the
EntityManager instance is created (whether explicitly, or in conjunction
with injection or JNDI lookup). See Section 7.7.
package jakarta.persistence;
public enum PersistenceContextType {
TRANSACTION,
EXTENDED
}
By default, the lifetime of the persistence
context of a container-managed entity manager corresponds to the scope
of a transaction (i.e., it is of type
PersistenceContextType.TRANSACTION
).
When an extended persistence context is used, the extended persistence context exists from the time the EntityManager instance is created until it is closed. This persistence context might span multiple transactions and non-transactional invocations of the EntityManager.
An EntityManager with an extended persistence context maintains its references to the entity objects after a transaction has committed. Those objects remain managed by the EntityManager, and they can be updated as managed objects between transactions.[34] Navigation from a managed object in an extended persistence context results in one or more other managed objects regardless of whether a transaction is active.
When an EntityManager with an extended persistence context is used, the persist, remove, merge, and refresh operations can be called regardless of whether a transaction is active. The effects of these operations will be committed to the database when the extended persistence context is enlisted in a transaction and the transaction commits.
The scope of the persistence context of an application-managed entity manager is extended. It is the responsibility of the application to manage the lifecycle of the persistence context.
Container-managed persistence contexts are described further in Section 7.7. Persistence contexts managed by the application are described further in Section 7.8.
3.4.1. Synchronization with the Current Transaction
By default, a container-managed persistence
context is of SynchronizationType.SYNCHRONIZED
and is automatically
joined to the current transaction. A persistence context of
SynchronizationType.UNSYNCHRONIZED
will not be enlisted in the current
transaction, unless the EntityManager
joinTransaction
method is
invoked.
By default, an application-managed
persistence context that is associated with a JTA entity manager and
that is created within the scope of an active transaction is
automatically joined to that transaction. An application-managed JTA
persistence context that is created outside the scope of a transaction
or an application-managed persistence context of type
SynchronizationType.UNSYNCHRONIZED
will not be joined to that
transaction unless the EntityManager
joinTransaction
method is
invoked.
An application-managed persistence context associated with a resource-local entity manager is always automatically joined to any resource-local transaction that is begun for that entity manager.
Persistence context synchronization type is described further in Section 7.7.1.
3.4.2. Transaction Commit
The managed entities of a transaction-scoped persistence context become detached when the transaction commits; the managed entities of an extended persistence context remain managed.
3.4.3. Transaction Rollback
For both transaction-scoped persistence contexts and for extended persistence contexts that are joined to the current transaction, transaction rollback causes all pre-existing managed instances and removed instances[35] to become detached. The instances' state will be the state of the instances at the point at which the transaction was rolled back. Transaction rollback typically causes the persistence context to be in an inconsistent state at the point of rollback. In particular, the state of version attributes and generated state (e.g., generated primary keys) may be inconsistent. Instances that were formerly managed by the persistence context (including new instances that were made persistent in that transaction) may therefore not be reusable in the same manner as other detached objects—for example, they may fail when passed to the merge operation.[36]
Because a transaction-scoped persistence context’s lifetime is scoped to a transaction regardless of whether it is joined to that transaction, the container closes the persistence context upon transaction rollback. However, an extended persistence context that is not joined to a transaction is unaffected by transaction rollback. |
3.5. Locking and Concurrency
This specification assumes the use of
optimistic concurrency control. It assumes that the databases to which
persistence units are mapped will be accessed by the implementation
using read-committed isolation (or a vendor equivalent in which
long-term read locks are not held), and that writes to the database will
typically occur only when the flush
method has been invoked—whether
explicitly by the application, or by the persistence provider runtime in
accordance with the flush mode setting.
If a transaction is active and the persistence context is joined to the transaction, a compliant implementation of this specification is permitted to write to the database immediately (i.e., whenever a managed entity is updated, created, and/or removed), however, the configuration of an implementation to require such non-deferred database writes is outside the scope of this specification.[37] |
In addition, both pessimistic and optimistic locking are supported for selected entities by means of specified lock modes. Optimistic locking is described in Section 3.5.1 and Section 3.5.2; pessimistic locking in Section 3.5.3. Section 3.5.4 describes the setting of optimistic and pessimistic lock modes. The configuration of the setting of optimistic lock modes is described in Section 3.5.4.1, and the configuration of the setting of pessimistic lock modes is described in Section 3.5.4.2.
3.5.1. Optimistic Locking
Optimistic locking is a system of concurrency control where each revision of an item of data is assigned a version number or timestamp. When the data is read and then updated within a given unit of work, the version or timestamp is:
-
read from the database when the data itself is read, and
-
verified and then updated in the database when the data is updated.
Similarly, when the data is read and then deleted within a given unit of work, the version or timestamp is:
-
read from the database when the data itself is read, and
-
verified when the data is deleted.
An optimistic lock failure occurs when verification fails, that is, if the version or timestamp held in the database changes between reading the data (step 1), and attempting to update or delete the data (step 2).
Thus, the unit of work is prevented from updating the data and creating a new revision, or from deleting the data, unless the revision it previously obtained is still the current revision. Optimistic lock verification ensures that an update of a given item is successful only when no intervening transaction has already updated the item, preventing the loss of updates made by such intervening transactions.
The persistence provider is required to perform optimistic locking
automatically for every entity with a version, as defined in Section 2.5.
A portable application which wishes to take advantage of automatic
optimistic locking must specify a version field or property for each
optimistically-locked entity using the @Version
annotation defined in
Section 11.1.57 or equivalent XML element.
When an optimistic lock failure is detected, the persistence provider must:
-
throw an
OptimisticLockException
and -
mark the current transaction for rollback.
A persistence provider might offer alternative implementations of optimistic locking, which do not depend on the entity having a version, but such functionality is not portable between providers.[38]
Applications are strongly encouraged to enable optimistic locking for every entity which may be concurrently accessed or which may be merged from a detached state. Failure to make use of optimistic locking often leads to inconsistent entity state, lost updates, and other anomalies. If an entity does not have a version, the application itself must bear the burden of maintaining data consistency during optimistic units of work. |
For the purposes of versioning and optimistic locking, the state of a given entity is considered to include:
-
every persistent field or property which is not a relationship to another entity, and
-
every relationship owned by the entity, as defined by Section 2.11. [39]
Unowned relationships are not considered part of the state of the entity.
3.5.2. Entity Versions and Optimistic Locking
The entity version must be updated by the persistence provider each
time the state of an entity instance is written to the database.
[40]
Furthermore, if the current persistence context contains a revision
of the entity instance when the instance is written to the database,
the persistence provider must verify that the revision held in the
persistence context is identical to the revision held in the database
by comparing the versions held in memory and in the database.
[41] If the versions do not match, the persistence
provider must thow an OptimisticLockException
.
The persistence provider must examine the version field or property of
a detached entity instance when it is merged, as defined in Section 3.3.7.1,
and throw an OptimisticLockException
if the instance being merged
holds a stale revision of the state of the entity—that is, if the
entity was updated since the entity instance became detached. The
timing of this version check is provider-dependent:
-
the version check might occur synchronously with the call to
merge()
, or -
a provider might choose to delay the version check until a flush operation occurs, as defined in Section 3.3.4, or until the transaction commits.
If an update or merge operation involves entities with versions, and entities without versions, the persistence provider runtime is only required to perform optimistic lock verification for those entities which do have a version, and the consistency of the whole object graph is not guaranteed. The absence a version for some entity involved in the update or merge operation does not impede completion of the operation.
3.5.3. Pessimistic Locking
While optimistic locking is typically appropriate in dealing with moderate contention among concurrent transactions, in some applications it may be useful to immediately obtain long-term database locks for selected entities because of the often late failure of optimistic transactions. Such immediately obtained long-term database locks are referred to here as “pessimistic” locks.[42]
Pessimistic locking guarantees that once a transaction has obtained a pessimistic lock on an entity instance:
-
no other transaction (whether a transaction of an application using the Jakarta Persistence API or any other transaction using the underlying resource) may successfully modify or delete that instance until the transaction holding the lock has ended.
-
if the pessimistic lock is an exclusive lock[43], that same transaction may modify or delete that entity instance.
When an entity instance is locked using pessimistic locking, the persistence provider must lock the database row(s) that correspond to the non-collection-valued persistent state of that instance. If a joined inheritance strategy is used, or if the entity is otherwise mapped to a secondary table, this entails locking the row(s) for the entity instance in the additional table(s). Entity relationships for which the locked entity contains the foreign key will also be locked, but not the state of the referenced entities (unless those entities are explicitly locked). Element collections and relationships for which the entity does not contain the foreign key (such as relationships that are mapped to join tables or unidirectional one-to-many relationships for which the target entity contains the foreign key) will not be locked by default.
Element collections and relationships owned
by the entity that are contained in join tables will be locked if the
jakarta.persistence.lock.scope
property is specified with a value of
PessimisticLockScope.EXTENDED
. The state of entities referenced by
such relationships will not be locked (unless those entities are
explicitly locked). This property may be passed as an argument to the
methods of the EntityManager
, Query
, and TypedQuery
interfaces
that allow lock modes to be specified or used with the NamedQuery
annotation.
Locking such a relationship or element collection generally locks only the rows in the join table or collection table for that relationship or collection. This means that phantoms will be possible.
The values of the
jakarta.persistence.lock.scope
property are defined by the
PessimisticLockScope
enum.
package jakarta.persistence;
public enum PessimisticLockScope {
NORMAL,
EXTENDED
}
This specification does not define the mechanisms a persistence provider uses to obtain database locks, and a portable application should not rely on how pessimistic locking is achieved on the database.[44] In particular, a persistence provider or the underlying database management system may lock more rows than the ones selected by the application.
Whenever a pessimistically locked entity containing a version attribute is updated on the database, the persistence provider must also update (increment) the entity’s version column to enable correct interaction with applications using optimistic locking. See Section 3.5.2 and Section 3.5.4.
Pessimistic locking may be applied to entities that do not contain version attributes. However, in this case correct interaction with applications using optimistic locking cannot be ensured.
3.5.4. Lock Modes
Lock modes are intended to provide a facility that enables the effect of “repeatable read” semantics for the items read, whether “optimistically” (as described in Section 3.5.4.1) or “pessimistically” (as described in Section 3.5.4.2).
Lock modes can be specified by means of the
EntityManager lock
method, the methods of the EntityManager
,
Query
, and TypedQuery
interfaces that allow lock modes to be
specified, and the NamedQuery
annotation.
Lock mode values are defined by the
LockModeType
enum. Six distinct lock modes are defined. The lock mode
type values READ
and WRITE
are synonyms of OPTIMISTIC
and
OPTIMISTIC_FORCE_INCREMENT
respectively.[45] The
latter are to be preferred for new applications.
package jakarta.persistence;
public enum LockModeType {
READ,
WRITE,
OPTIMISTIC,
OPTIMISTIC_FORCE_INCREMENT,
PESSIMISTIC_READ,
PESSIMISTIC_WRITE,
PESSIMISTIC_FORCE_INCREMENT,
NONE
}
3.5.4.1. OPTIMISTIC, OPTIMISTIC_FORCE_INCREMENT
The lock modes OPTIMISTIC
and
OPTIMISTIC_FORCE_INCREMENT
are used for optimistic locking. The lock
mode type values READ
and WRITE
are synonymous with OPTIMISTIC
and
OPTIMISTIC_FORCE_INCREMENT
respectively.
The semantics of requesting locks of type
LockModeType.OPTIMISTIC
and LockModeType.OPTIMISTIC_FORCE_INCREMENT
are the following.
If transaction T1 calls lock(entity, LockModeType.OPTIMISTIC)
on a
versioned object, the entity manager
must ensure that neither of the following phenomena can occur:
-
P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and obtains the modified value, before T1 has committed or rolled back. Transaction T2 eventually commits successfully; it does not matter whether T1 commits or rolls back and whether it does so before or after T2 commits.
-
P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or deletes that row, before T1 has committed. Both transactions eventually commit successfully.
This will generally be achieved by the entity manager acquiring a lock on the underlying database row. While with optimistic concurrency concurrency, long-term database read locks are typically not obtained immediately, a compliant implementation is permitted to obtain an immediate lock (so long as it is retained until commit completes). If the lock is deferred until commit time, it must be retained until the commit completes. Any implementation that supports repeatable reads in a way that prevents the above phenomena is permissible.
The persistence implementation is not
required to support calling lock(entity, LockModeType.OPTIMISTIC)
on
a non-versioned object. When it cannot support such a lock call, it must
throw the PersistenceException
. When supported, whether for versioned
or non-versioned objects, LockModeType.OPTIMISTIC
must always prevent
the phenomena P1 and P2. Applications that call lock(entity,
LockModeType.OPTIMISTIC)
on non-versioned objects will not be portable.
If transaction T1 calls lock(entity, LockModeType.OPTIMISTIC_FORCE_INCREMENT)
on a versioned object, the entity manager must avoid the phenomena P1 and P2
(as with LockModeType.OPTIMISTIC
) and must also force an update (increment) to
the entity’s version column. A forced version update may be performed
immediately, or may be deferred until a flush or commit. If an entity is
removed before a deferred version update was to have been applied, the
forced version update is omitted.
The persistence implementation is not required to support calling
lock(entity, LockModeType.OPTIMISTIC_FORCE_INCREMENT)
on a non-versioned
object. When it cannot support such a lock call, it must throw the
PersistenceException
. When supported, whether for versioned or
non-versioned objects, LockModeType.OPTIMISTIC_FORCE_INCREMENT
must
always prevent the phenomena P1 and P2. For non-versioned objects,
whether or not LockModeType.OPTIMISTIC_FORCE_INCREMENT
has any
additional behavior is vendor-specific. Applications that call
`lock(entity, LockModeType.OPTIMISTIC_FORCE_INCREMENT)_ on non-versioned
objects will not be portable.
For versioned objects, it is permissible for
an implementation to use LockModeType.OPTIMISTIC_FORCE_INCREMENT
where
LockModeType.OPTIMISTIC
was requested, but not vice versa.
If a versioned object is otherwise updated or
removed, then the implementation must ensure that the requirements of
LockModeType.OPTIMISTIC_FORCE_INCREMENT
are met, even if no explicit
call to EntityManager.lock
was made.
For portability, an application should not
depend on vendor-specific hints or configuration to ensure repeatable
read for objects that are not updated or removed via any mechanism other
than the use of version attributes and the EntityManager lock
method.
However, it should be noted that if an implementation has acquired
up-front pessimistic locks on some database rows, then it is free to
ignore lock(entity, LockModeType.OPTIMISTIC)
calls on the entity
objects representing those rows.
3.5.4.2. PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT
The lock modes PESSIMISTIC_READ
,
PESSIMISTIC_WRITE
, and PESSIMISTIC_FORCE_INCREMENT
are used to
immediately obtain long-term database locks.[46]
The semantics of requesting locks of type
LockModeType.PESSIMISTIC_READ
, LockModeType.PESSIMISTIC_WRITE
, and
LockModeType.PESSIMISTIC_FORCE_INCREMENT
are the following.
If transaction T1 calls lock(entity, LockModeType.PESSIMISTIC_READ)
or
lock(entity, LockModeType.PESSIMISTIC_WRITE)
on an object, the entity
manager must ensure that neither of the following phenomena can occur:
-
P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and obtains the modified value, before T1 has committed or rolled back.
-
P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or deletes that row, before T1 has committed or rolled back.
Any such lock must be obtained immediately and retained until transaction T1 completes (commits or rolls back).
Avoidance of phenomena P1 and P2 is generally achieved by the entity manager acquiring a long-term lock on the underlying database row(s). Any implementation that supports pessimistic repeatable reads as described above is permissible.
A lock with |
The persistence implementation must support
calling lock(entity, LockModeType.PESSIMISTIC_READ)
and lock(entity,
LockModeType.PESSIMISTIC_WRITE)
on a non-versioned entity as well as on
a versioned entity.
It is permissible for an implementation to
use LockModeType.PESSIMISTIC_WRITE
where
LockModeType.PESSIMISTIC_READ
was requested, but not vice versa.
When the lock cannot be obtained, and the
database locking failure results in transaction-level rollback, the
provider must throw the PessimisticLockException
and ensure that the
JTA transaction or EntityTransaction has been marked for rollback.
When the lock cannot be obtained, and the
database locking failure results in only statement-level rollback, the
provider must throw the LockTimeoutException
(and must not mark the
transaction for rollback).
When an application locks an entity with
LockModeType.PESSIMISTIC_READ
and later updates that entity, the lock
must be converted to an exclusive lock when the entity is flushed to the
database.[47] If the lock conversion fails, and the
database locking failure results in transaction-level rollback, the
provider must throw the PessimisticLockException
and ensure that the
JTA transaction or EntityTransaction has been marked for rollback. When
the lock conversion fails, and the database locking failure results in
only statement-level rollback, the provider must throw the
LockTimeoutException
(and must not mark the transaction for
rollback).
When lock(entity, LockModeType.PESSIMISTIC_READ)
,
lock(entity, LockModeType.PESSIMISTIC_WRITE)
, or
lock(entity, LockModeType.PESSIMISTIC_FORCE_INCREMENT)
is invoked on a versioned
entity that is already in the persistence context, the provider must
also perform optimistic version checks when obtaining the lock. An
OptimisticLockException
must be thrown if the version checks fail.
Depending on the implementation strategy used by the provider, it is
possible that this exception may not be thrown until flush is called or
commit time, whichever occurs first.
If transaction T1 calls
lock(entity, LockModeType.PESSIMISTIC_FORCE_INCREMENT)
on a versioned
object, the entity manager must avoid the phenomenon P1 and P2 (as with
LockModeType.PESSIMISTIC_READ
and LockModeType.PESSIMISTIC_WRITE
)
and must also force an update (increment) to the entity’s version
column.
The persistence implementation is not required to support calling
lock(entity, LockModeType.PESSIMISTIC_FORCE_INCREMENT)
on a non-versioned
object. When it cannot support such a lock call, it must throw the
PersistenceException
. When supported, whether for versioned or
non-versioned objects, LockModeType.PESSIMISTIC_FORCE_INCREMENT
must
always prevent the phenomena P1 and P2. For non-versioned objects,
whether or not LockModeType.PESSIMISTIC_FORCE_INCREMENT
has any
additional behavior is vendor-specific. Applications that call
lock(entity, LockModeType.PESSIMISTIC_FORCE_INCREMENT)
on
non-versioned objects will not be portable.
For versioned objects, it is permissible for
an implementation to use LockModeType.PESSIMISTIC_FORCE_INCREMENT
where LockModeType.PESSIMISTIC_READ
or
LockModeType.PESSIMISTIC_WRITE
was requested, but not vice versa.
If a versioned object locked with
LockModeType.PESSIMISTIC_READ
or LockModeType.PESSIMISTIC_WRITE
is
updated, then the implementation must ensure that the requirements of
LockModeType.PESSIMISTIC_FORCE_INCREMENT
are met.
3.5.4.3. Lock Mode Properties and Uses
The following property is defined by this specification for use in pessimistic locking, as described in Section 3.5.3:
jakarta.persistence.lock.scope
This property may be used with the methods of
the EntityManager
interface that allow lock modes to be specified, the
Query
and TypedQuery
setLockMode
methods, and the NamedQuery
annotation. When specified, this property must be observed. The provider
is permitted to lock more (but not fewer) rows than requested.
The following hint is defined by this specification for use in pessimistic locking.
jakarta.persistence.lock.timeout // time in milliseconds
This hint may be used with the methods of the
EntityManager
interface that allow lock modes to be specified, the
Query.setLockMode
method and the NamedQuery
annotation. It may also
be passed as a property to the Persistence.createEntityManagerFactory
method and used in the properties
element of the persistence.xml
file. See Section 3.2, Section 3.11.9, Section 8.2.1.11, Section 9.7,
and Section 10.4.1. When used in
the createEntityManagerFactory
method, the persistence.xml
file, and
the NamedQuery
annotation, the timeout hint serves as a default value
which can be selectively overridden by use in the methods of the
EntityManager
, Query
, and TypedQuery
interfaces as specified
above. When this hint is not specified, database timeout values are
assumed to apply.
A timeout value of 0
is used to specify “no wait” locking.
Portable applications should not rely on this hint. Depending on the database in use and the locking mechanisms used by the persistence provider, the hint may or may not be observed.
Vendors are permitted to support the use of
additional, vendor-specific locking hints. Vendor-specific hints must
not use the jakarta.persistence
namespace. Vendor-specific hints must be
ignored if they are not understood.
If the same property or hint is specified more than once, the following order of overriding applies, in order of decreasing precedence:
-
argument to method of
EntityManager
,Query
, orTypedQuery
interface -
specification to
NamedQuery
(annotation or XML) -
argument to
createEntityManagerFactory
method -
specification in
persistence.xml
3.5.5. OptimisticLockException
Provider implementations may defer writing to
the database until the end of the transaction, when consistent with the
lock mode and flush mode settings in effect. In this case, an optimistic
lock check may not occur until commit time, and the
OptimisticLockException
may be thrown in the “before completion” phase
of the commit. If the OptimisticLockException
must be caught or
handled by the application, the flush
method should be used by the
application to force the database writes to occur. This will allow the
application to catch and handle optimistic lock exceptions.
The OptimisticLockException
provides an API
to return the object that caused the exception to be thrown. The object
reference is not guaranteed to be present every time the exception is
thrown but should be provided whenever the persistence provider can
supply it. Applications cannot rely upon this object being available.
In some cases an OptimisticLockException
will be thrown and wrapped by another exception, such as a
RemoteException
, when VM boundaries are crossed. Entities that may be
referenced in wrapped exceptions should implement Serializable
so that
marshalling will not fail.
An OptimisticLockException
always causes
the transaction to be marked for rollback.
Refreshing objects or reloading objects in a
new transaction context and then retrying the transaction is a potential
response to an OptimisticLockException
.
3.6. Entity Listeners and Callback Methods
A method may be designated as a lifecycle callback method to receive notification of entity lifecycle events. A lifecycle callback method can be defined on an entity class, a mapped superclass, or an entity listener class associated with an entity or mapped superclass. An entity listener class is a class whose methods are invoked in response to lifecycle events on an entity. Any number of entity listener classes can be defined for an entity class or mapped superclass.
Default entity listeners—entity listener classes whose callback methods apply to all entities in the persistence unit—can be specified by means of the XML descriptor.
Lifecycle callback methods and entity
listener classes are defined by means of metadata annotations or the XML
descriptor. When annotations are used, one or more entity listener
classes are denoted using the EntityListeners
annotation on the entity
class or mapped superclass. If multiple entity listeners are defined,
the order in which they are invoked is determined by the order in which
they are specified in the EntityListeners
annotation. The XML
descriptor may be used as an alternative to specify the invocation order
of entity listeners or to override the order specified in metadata
annotations.
Any subset or combination of annotations may be specified on an entity class, mapped superclass, or listener class. A single class must not have more than one lifecycle callback method for the same lifecycle event. The same method may be used for multiple callback events.
Multiple entity classes and mapped superclasses in an inheritance hierarchy may define listener classes and/or lifecycle callback methods directly on the class. Section 3.6.4 describes the rules that apply to method invocation order in this case.
3.6.1. Entity Listeners
The entity listener class must have a public no-arg constructor.
Entity listener classes in Jakarta EE
environments support dependency injection through the Contexts and
Dependency Injection API (CDI) [7] when CDI is
enabled[48]. An entity listener class that makes use
of CDI injection may also define lifecycle callback methods annotated
with the PostConstruct
and PreDestroy
annotations. These methods
will be invoked after injection has taken place and before the entity
listener instance is destroyed respectively.
The persistence provider is responsible for
using the CDI SPI to create instances of the entity listener class; to
perform injection upon such instances; to invoke their PostConstruct
and PreDestroy
methods, if any; and to dispose of the entity listener
instances.
The persistence provider is only required to support CDI injection into entity listeners in Jakarta EE container environments[49]. If the CDI is not enabled, the persistence provider must not invoke entity listeners that depend upon CDI injection.
An entity listener is a noncontextual object. In supporting injection into entity listeners, the persistence provider must behave as if it carries out the following steps involving the use of the CDI SPI. (See [7]).
-
Obtain a
BeanManager
instance. (See Section 9.1) -
Create an
AnnotatedType
instance for the entity listener class. -
Create an
InjectionTarget
instance for the annotated type. -
Create a
CreationalContext
. -
Instantiate the listener by calling the
InjectionTarget
produce
method. -
Inject the listener instance by calling the
InjectionTarget
inject
method on the instance. -
Invoke the
PostConstruct
callback, if any, by calling theInjectionTarget
postConstruct
method on the instance.
When the listener instance is to be destroyed, the persistence provider must behave as if it carries out the following steps.
-
Call the
InjectionTarget
preDestroy
method on the instance. -
Call the
InjectionTarget
dispose
method on the instance -
Call the
CreationalContext
release
method.
Persistence providers may optimize the steps above, e.g. by avoiding calls to the actual CDI SPI and relying on container-specific interfaces instead, as long as the outcome is the same.
Entity listeners that do not make use of CDI injection are stateless. The lifecycle of such entity listeners is unspecified.
When invoked from within a Jakarta EE environment, the callback listeners for an entity share the enterprise naming context of the invoking component, and the entity callback methods are invoked in the transaction and security contexts of the calling component at the time at which the callback method is invoked. [50]
3.6.2. Lifecycle Callback Methods
Entity lifecycle callback methods can be defined on an entity listener class and/or directly on an entity class or mapped superclass.
A lifecycle callback method must be either:
-
annotated with annotations designating the callback events for which it is invoked, or
-
mapped to a callback event type using the XML descriptor.
The same annotations (and XML elements) are used to declare:
-
callback methods of an entity class or mapped superclass, and
-
callback methods of an entity listener class.
The signatures of the callback methods differ between these two cases:
-
a callback method defined by an entity class or mapped superclass has the signature:
void <METHOD>()
-
a callback method defined by an entity listener class has the signature:
void <METHOD>(S)
where
S
is any supertype of the entity class or mapped superclass to which the entity listener is applied. At runtime, the argument to the entity listener callback method is the entity instance for which the callback method is being invoked.
Callback methods can have public, private, protected, or package level
access, but must not be static
or final
.
The following annotations designate lifecycle event callback methods of the corresponding types.
-
PrePersist
-
PostPersist
-
PreRemove
-
PostRemove
-
PreUpdate
-
PostUpdate
-
PostLoad
The following rules apply to lifecycle callback methods:
-
Lifecycle callback methods may throw unchecked/runtime exceptions. A runtime exception thrown by a callback method that executes within a transaction causes that transaction to be marked for rollback if the persistence context is joined to the transaction.
-
Lifecycle callbacks can invoke JNDI, JDBC, JMS, and enterprise beans.
-
A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.
-
In general, the lifecycle method of a portable application should not invoke
EntityManager
or query operations, access other entity instances, or modify relationships within the same persistence context[51].
3.6.3. Semantics of the Life Cycle Callback Methods for Entities
The PrePersist
and PreRemove
callback
methods are invoked for a given entity before the respective
EntityManager persist and remove operations for that entity are
executed. For entities to which the merge operation has been applied and
causes the creation of newly managed instances, the PrePersist
callback methods will be invoked for the managed instance after the
entity state has been copied to it. These PrePersist
and PreRemove
callbacks will also be invoked on all entities to which these operations
are cascaded. The PrePersist
and PreRemove
methods will always be
invoked as part of the synchronous persist, merge, and remove operations.
Primary key values generated using the SEQUENCE
, TABLE
, or UUID
strategy are available in the PrePersist
method. Primary key values
generated using the IDENTITY
strategy are not available in the
PrePersist
method.
The PostPersist
and PostRemove
callback
methods are invoked for an entity after the entity has been made
persistent or removed. These callbacks will also be invoked on all
entities to which these operations are cascaded. The PostPersist
and
PostRemove
methods will be invoked after the database insert and
delete operations respectively. These database operations may occur
directly after the persist, merge, or remove operations have been
invoked or they may occur directly after a flush operation has occurred
(which may be at the end of the transaction). Generated primary key
values are always available in the PostPersist
method.
The PreUpdate
and PostUpdate
callbacks
occur before and after the database update operations to entity data
respectively. These database operations may occur at the time the entity
state is updated or they may occur at the time state is flushed to the
database (which may be at the end of the transaction).
Note that it is implementation-dependent as
to whether |
The PostLoad
method for an entity is
invoked after the entity has been loaded into the current persistence
context from the database or after the refresh operation has been
applied to it. The PostLoad
method is invoked before a query result is
returned or accessed or before an association is traversed.
It is implementation-dependent as to whether callback methods are invoked before or after the cascading of the lifecycle events to related entities. Applications should not depend on this ordering.
For example:
@Entity
@EntityListeners(com.acme.AlertMonitor.class)
public class Account {
Long accountId;
Integer balance;
boolean preferred;
@Id
public Long getAccountId() { ... }
// ...
public Integer getBalance() { ... }
// ...
@Transient // because status depends upon non-persistent context
public boolean isPreferred() { ... }
// ...
public void deposit(Integer amount) { ... }
public Integer withdraw(Integer amount) throws NSFException { ... }
@PrePersist
protected void validateCreate() {
if (getBalance() < MIN_REQUIRED_BALANCE)
throw new AccountException("Insufficient balance to open an account");
}
@PostLoad
protected void adjustPreferredStatus() {
preferred = (getBalance() >= AccountManager.getPreferredStatusLevel());
}
}
public class AlertMonitor {
@PostPersist
public void newAccountAlert(Account acct) {
Alerts.sendMarketingInfo(acct.getAccountId(), acct.getBalance());
}
}
3.6.4. Multiple Lifecycle Callback Methods for an Entity Lifecycle Event
If multiple callback methods are defined for an entity lifecycle event, the ordering of the invocation of these methods is as follows.
Default listeners, if any, are invoked first,
in the order specified in the XML descriptor. Default listeners apply to
all entities in the persistence unit, unless explicitly excluded by
means of the ExcludeDefaultListeners
annotation or
exclude-default-listeners
XML element.
The lifecycle callback methods defined on the
entity listener classes for an entity class or mapped superclass are
invoked in the same order as the specification of the entity listener
classes in the EntityListeners
annotation.
If multiple classes in an inheritance
hierarchy—entity classes and/or mapped superclasses—define entity
listeners, the listeners defined for a superclass are invoked before the
listeners defined for its subclasses in this order. The
ExcludeSuperclassListeners
annotation or
exclude-superclass-listeners
XML element may be applied to an entity
class or mapped superclass to exclude the invocation of the listeners
defined by the entity listener classes for the superclasses of the
entity or mapped superclass. The excluded listeners are excluded from
the class to which the ExcludeSuperclassListeners
annotation or
element has been specified and its subclasses[52].
The ExcludeSuperclassListeners
annotation (or
exclude-superclass-listeners
XML element) does not cause default
entity listeners to be excluded from invocation.
If a lifecycle callback method for the same lifecycle event is also specified on the entity class and/or one or more of its entity or mapped superclasses, the callback methods on the entity class and/or superclasses are invoked after the other lifecycle callback methods, most general superclass first. A class is permitted to override an inherited callback method of the same callback type, and in this case, the overridden method is not invoked[53].
Callback methods are invoked by the persistence provider runtime in the order specified. If the callback method execution terminates normally, the persistence provider runtime then invokes the next callback method, if any.
The XML descriptor may be used to override the lifecycle callback method invocation order specified in annotations.
For example:
There are several entity classes and listeners for animals:
@Entity
public class Animal {
// ...
@PostPersist
protected void postPersistAnimal() {
// ...
}
}
@Entity
@EntityListeners(PetListener.class)
public class Pet extends Animal {
// ...
}
@Entity
@EntityListeners({CatListener.class, CatListener2.class})
public class Cat extends Pet {
// ...
}
public class PetListener {
@PostPersist
protected void postPersistPetListenerMethod(Object pet) {
// ...
}
}
public class CatListener {
@PostPersist
protected void postPersistCatListenerMethod(Object cat) {
// ...
}
}
public class CatListener2 {
@PostPersist
protected void postPersistCatListener2Method(Object cat) {
// ...
}
}
If a PostPersist
event occurs on an
instance of Cat
, the following methods are called in order:
-
postPersistPetListenerMethod
-
postPersistCatListenerMethod
-
postPersistCatListener2Method
-
postPersistAnimal
Assume that SiameseCat
is defined as a
subclass of Cat
:
@EntityListeners(SiameseCatListener.class)
@Entity
public class SiameseCat extends Cat {
// ...
@PostPersist
protected void postPersistSiameseCat() {
// ...
}
}
public class SiameseCatListener {
@PostPersist
protected void postPersistSiameseCatListenerMethod(Object cat) {
// ...
}
}
If a PostPersist
event occurs on an
instance of SiameseCat
, the following methods are called in order:
-
postPersistPetListenerMethod
-
postPersistCatListenerMethod
-
postPersistCatListener2Method
-
postPersistSiameseCatListenerMethod
-
postPersistAnimal
-
postPersistSiameseCat
Assume the definition of SiameseCat
were instead:
@EntityListeners(SiameseCatListener.class)
@Entity
public class SiameseCat extends Cat {
// ...
@PostPersist
protected void postPersistAnimal() {
// ...
}
}
In this case, the following methods would be
called in order, where postPersistAnimal
is the PostPersist
method
defined in the SiameseCat
class:
-
postPersistPetListenerMethod
-
postPersistCatListenerMethod
-
postPersistCatListener2Method
-
postPersistSiameseCatListenerMethod
-
postPersistAnimal
3.6.5. Exceptions
Lifecycle callback methods may throw runtime exceptions. A runtime exception thrown by a callback method that executes within a transaction causes that transaction to be marked for rollback if the persistence context is joined to the transaction. No further lifecycle callback methods will be invoked after a runtime exception is thrown.
3.6.6. Specification of Callback Listener Classes and Lifecycle Methods in the XML Descriptor
The XML descriptor can be used as an alternative to metadata annotations to specify entity listener classes and their binding to entities or to override the invocation order of lifecycle callback methods as specified in annotations.
3.6.6.1. Specification of Callback Listeners
The entity-listener
XML descriptor element
is used to specify the lifecycle listener methods of an entity listener
class. The lifecycle listener methods are specified by using the
pre-persist
, post-persist
, pre-remove
, post-remove
,
pre-update
, post-update
, and/or post-load
elements.
An entity listener class can define multiple callback methods. However, at most one method of an entity listener class can be designated as a pre-persist method, post-persist method, pre-remove method, post-remove method, pre-update method, post-update method, and/or post-load method, regardless of whether the XML descriptor is used to define entity listeners or whether some combination of annotations and XML descriptor elements is used.
3.6.6.2. Specification of the Binding of Entity Listener Classes to Entities
The entity-listeners
subelement of the
persistence-unit-defaults
element is used to specify the default
entity listeners for the persistence unit.
The entity-listeners
subelement of the
entity
or mapped-superclass
element is used to specify the entity
listener classes for the respective entity or mapped superclass and its
subclasses.
The binding of entity listeners to entity classes is additive. The entity listener classes bound to the superclasses of an entity or mapped superclass are applied to it as well.
The exclude-superclass-listeners
element
specifies that the listener methods for superclasses are not to be
invoked for an entity class (or mapped superclass) and its subclasses.
The exclude-default-listeners
element
specifies that default entity listeners are not to be invoked for an
entity class (or mapped superclass) and its subclasses.
Explicitly listing an excluded default or superclass listener for a given entity class or mapped superclass causes it to be applied to that entity or mapped superclass and its subclasses.
In the case of multiple callback methods for a single lifecycle event, the invocation order rules described in Section 3.6.4 apply.
3.7. Bean Validation
This specification defines support for use of Bean Validation [5] within Jakarta Persistence applications.
Managed classes (entities, mapped superclasses, and embeddable classes) may be configured to include Bean Validation constraints.
Automatic validation using these constraints is achieved by specifying that Jakarta Persistence delegate validation to the Bean Validation implementation upon the pre-persist, pre-update, and pre-remove entity lifecycle events described in Section 3.6.3.
Validation can also be achieved by the
application calling the validate
method of a Validator
instance upon
an instance of a managed class, as described in the Bean Validation
specification [5].
3.7.1. Automatic Validation Upon Lifecycle Events
This specification supports the use of bean
validation for the automatic validation of entities upon the
pre-persist, pre-update, and pre-remove lifecycle validation events.
These lifecycle validation events occur immediately after the point at
which all the PrePersist
, PreUpdate
, and PreRemove
lifecycle
callback method invocations respectively have been completed, or
immediately after the point at which such lifecycle callback methods
would have been completed (in the event that such callback methods are
not present).
In the case where an entity is persisted and subsequently modified in a single transaction or when an entity is modified and subsequently removed in a single transaction, it is implementation dependent as to whether the pre-update validation event occurs. Portable applications should not rely on this behavior. |
3.7.1.1. Enabling Automatic Validation
The validation-mode
element of the
persistence.xml
file determines whether the automatic lifecycle event
validation is in effect. The values of the validation-mode
element are
AUTO
, CALLBACK
, NONE
. The default validation mode is AUTO
.
If the application creates the entity manager
factory using the Persistence.createEntityManagerFactory
method, the
validation mode can be specified using the
jakarta.persistence.validation.mode
map key, which will override the
value specified (or defaulted) in the persistence.xml
file. The map
values for this key are "auto", "callback", "none".
If the auto validation mode is specified by
the validation-mode
element or the jakarta.persistence.validation.mode
property, or if neither the validation-mode
element nor the
jakarta.persistence.validation.mode
property is specified, and a Bean
Validation provider is present in the environment, the persistence
provider must perform the automatic validation of entities as described
in Section 3.7.1.2. If no Bean Validation provider is
present in the environment, no lifecycle event validation takes place.
If the callback validation mode is specified
by the validation-mode
element or the
jakarta.persistence.validation.mode
property, the persistence provider
must perform the lifecycle event validation as described in Section 3.7.1.2.
It is an error if there is no Bean Validation
provider present in the environment, and the provider must throw the
PersistenceException
if the jakarta.persistence.validation.mode
property value "callback" has been passed to the
Persistence.createEntityManagerFactory
method.
If the none validation mode is specified by
the validation-mode
element or the jakarta.persistence.validation.mode
property, the persistence provider must not perform lifecycle event
validation.
3.7.1.2. Requirements for Automatic Validation upon Lifecycle Events
For each event type, a list of groups is
targeted for validation. By default, the default Bean Validation group
(the group Default
) will be validated upon the pre-persist and
pre-update lifecycle validation events, and no group will be validated
upon the pre-remove event.
This default validation behavior can be
overridden by specifying the target groups using the following
validation properties in the persistence.xml
file or by passing these
properties in the configuration of the entity manager factory through
the createEntityManagerFactory
method:
-
jakarta.persistence.validation.group.pre-persist
-
jakarta.persistence.validation.group.pre-update
-
jakarta.persistence.validation.group.pre-remove
The value of a validation property must be a list of the targeted groups. A targeted group must be specified by its fully qualified class name. Names must be separated by a comma.
When one of the above events occurs for an
entity, the persistence provider must validate that entity by obtaining
a Validator
instance from the validator factory in use (see Section 3.7.2) and
invoking its validate
method with the targeted groups. If the list of
targeted groups is empty, no validation is performed. If the set of
ConstraintViolation
objects returned by the validate
method is not
empty, the persistence provider must throw the
jakarta.validation.ConstraintViolationException
containing a reference
to the returned set of ConstraintViolation
objects, and must mark the
transaction for rollback if the persistence context is joined to the
transaction.
The validator instance that is used for
automatic validation upon lifecycle events must use a
TraversableResolver
that has the following behavior:
-
Attributes that have not been loaded must not be loaded.
-
Validation cascade (
@Valid
) must not occur for entity associations (single- or multi-valued).
These requirements guarantee that no unloaded attribute or association will be loaded by side effect and that no entity will be validated more than once during a given flush cycle.
Embeddable attributes must be validated only
if the Valid
annotation has been specified on them.
It is the responsibility of the persistence
provider to pass an instance implementing the
jakarta.validation.TraversableResolver
interface to the Bean Validation
provider by calling
ValidatorFactory.usingContext().traversableResolver(tr).getValidator()
where tr
is the resolver having the behavior described above.
3.7.2. Providing the ValidatorFactory
In Jakarta EE environments, a ValidatorFactory
instance is made available by the Jakarta EE container. The container is
responsible for passing this validator factory to the persistence
provider via the map that is passed as an argument to the
createContainerEntityManagerFactory
call. The map key used by the
container must be the standard property name
jakarta.persistence.validation.factory
.
In Java SE environments, the application can
pass the ValidatorFactory
instance via the map that is passed as an
argument to the Persistence.createEntityManagerFactory
call. The map
key used must be the standard property name
jakarta.persistence.validation.factory
. If no ValidatorFactory
instance is provided by the application, and if a Bean Validation
provider is present in the classpath, the persistence provider must
instantiate the ValidatorFactory
using the default bootstrapping
approach defined by the Bean Validation specification
[5], namely Validation.buildDefaultValidatorFactory()
.
3.8. Entity Graphs
An entity graph is a template that captures
the path and boundaries for an operation or query. It is defined in the
form of metadata or an object created by the dynamic EntityGraph
API.
Entity graphs are used in the specification
of “fetch plans” for query or find
operations.
The EntityGraph
, AttributeNode
, and
Subgraph
interfaces are used to dynamically construct entity graphs.
The annotations to statically define entity graphs, namely
NamedEntityGraph
, NamedAttributeNode
, and NamedSubgraph
, are
described in Section 10.3.
The named-entity-graph
XML element and its subelements may be used to
override these annotations or to define additional named entity graphs.
The semantics of entity graphs with regard to find and query operations are described in Section 3.8.5.
3.8.1. Graph Interface
package jakarta.persistence;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.PluralAttribute;
import java.util.List;
/**
* Declares operations common to {@link EntityGraph} and {@link Subgraph}.
*
* @see EntityGraph
* @see Subgraph
*
* @since 3.2
*/
public interface Graph<T> {
/**
* Add an attribute nodes to the entity graph.
*
* @param attributeName name of the attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this entity.
* @throws IllegalStateException if the EntityGraph has been
* statically defined
*
* @since 3.2
*/
public void addAttributeNode(String attributeName);
/**
* Add an attribute node to the entity graph.
*
* @param attribute attribute
* @throws IllegalStateException if the EntityGraph has been
* statically defined
*
* @since 3.2
*/
public void addAttributeNode(Attribute<? super T, ?> attribute);
/**
* Remove an attribute node from the entity graph.
* When this graph is interpreted as a load graph, this operation
* suppresses inclusion of an attribute mapped for eager fetching.
* The effect of this call may be overridden by subsequent
* invocations of {@link #addAttributeNode} or {@link #addSubgraph}.
* @param attributeName name of the attribute
* @since 3.2
*/
public void removeAttributeNode(String attributeName);
/**
* Remove an attribute node from the entity graph.
* When this graph is interpreted as a load graph, this operation
* suppresses inclusion of an attribute mapped for eager fetching.
* The effect of this call may be overridden by subsequent
* invocations of {@link #addAttributeNode} or {@link #addSubgraph}.
* @param attribute attribute
* @since 3.2
*/
public void removeAttributeNode(Attribute<? super T, ?> attribute);
/**
* Remove all attribute nodes of the given attribute types.
* When this graph is interpreted as a load graph, this operation
* suppresses inclusion of attributes mapped for eager fetching.
* The effect of this call may be overridden by subsequent
* invocations of {@link #addAttributeNode} or {@link #addSubgraph}.
* @since 3.2
*/
public void removeAttributeNodes(Attribute.PersistentAttributeType nodeTypes);
/**
* Add one or more attribute nodes to the entity graph.
*
* @param attributeName name of the attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this managed type.
* @throws IllegalStateException if the EntityGraph has been
* statically defined
*/
public void addAttributeNodes(String ... attributeName);
/**
* Add one or more attribute nodes to the entity graph.
* @param attribute attribute
*
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public void addAttributeNodes(Attribute<? super T, ?>... attribute);
/**
* Add a node to the graph that corresponds to a managed
* type. This allows for construction of multi-node entity graphs
* that include related managed types.
*
* @param attribute attribute
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if the EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addSubgraph(Attribute<? super T, X> attribute);
/**
* Add a node to the graph that corresponds to a managed
* type with inheritance. This allows for multiple subclass
* subgraphs to be defined for this node of the entity
* graph. Subclass subgraphs will automatically include the
* specified attributes of superclass subgraphs.
*
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if the EntityGraph has been
* statically defined
*
* @since 3.2
*/
public <Y> Subgraph<Y> addTreatedSubgraph(Attribute<? super T, ? super Y> attribute, Class<Y> type);
/**
* Add a node to the graph that corresponds to a managed
* type with inheritance. This allows for multiple subclass
* subgraphs to be defined for this node of the entity
* graph. Subclass subgraphs will automatically include the specified
* attributes of superclass subgraphs
*
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
* @deprecated use {@link #addTreatedSubgraph(Attribute, Class)}
*/
@Deprecated(since = "3.2", forRemoval = true)
public <X> Subgraph<? extends X> addSubgraph(Attribute<? super T, X> attribute, Class<? extends X> type);
/**
* Add a node to the graph that corresponds to a managed
* type. This allows for construction of multi-node entity graphs
* that include related managed types.
*
* @param attributeName name of the attribute
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this managed type.
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addSubgraph(String attributeName);
/**
* Add a node to the graph that corresponds to a managed
* type with inheritance. This allows for multiple subclass
* subgraphs to be defined for this node of the entity
* graph. Subclass subgraphs will automatically include the
* specified attributes of superclass subgraphs
*
* @param attributeName name of the attribute
* @param type entity subclass
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute is not
* an attribute of this managed type.
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type);
/**
* Add a node to the graph that corresponds to a collection element
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attribute attribute
* @return subgraph for the element attribute
* @throws IllegalArgumentException if the attribute's target type
* is not an entity
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*
* @since 3.2
*/
public <E> Subgraph<E> addElementSubgraph(PluralAttribute<? super T, ?, E> attribute);
/**
* Add a node to the graph that corresponds to a collection element
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attribute attribute
* @return subgraph for the element attribute
* @throws IllegalArgumentException if the attribute's target type
* is not an entity
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*
* @since 3.2
*/
public <E> Subgraph<E> addTreatedElementSubgraph(PluralAttribute<? super T, ?, ? super E> attribute, Class<E> type);
/**
* Add a node to the graph that corresponds to a collection element
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attributeName name of the attribute
* @return subgraph for the element attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this entity.
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addElementSubgraph(String attributeName);
/**
* Add a node to the graph that corresponds to a collection element
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attributeName name of the attribute
* @param type entity subclass
* @return subgraph for the element attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this entity.
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addElementSubgraph(String attributeName, Class<X> type);
/**
* Add a node to the graph that corresponds to a map key
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attribute attribute
* @return subgraph for the key attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type entity
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <K> Subgraph<K> addMapKeySubgraph(MapAttribute<? super T, K, ?> attribute);
/**
* Add a node to the graph that corresponds to a map key
* that is a managed type with inheritance. This allows for
* construction of multi-node entity graphs that include related
* managed types. Subclass subgraphs will automatically include
* the specified attributes of superclass subgraphs
*
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type entity
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <K> Subgraph<K> addTreatedMapKeySubgraph(MapAttribute<? super T, ? super K, ?> attribute, Class<K> type);
/**
* Add a node to the graph that corresponds to a map key
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attribute attribute
* @return subgraph for the key attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type entity
* @throws IllegalStateException if this EntityGraph has been
* statically defined
* @deprecated use {@link #addMapKeySubgraph(MapAttribute)}
*/
@Deprecated(since = "3.2", forRemoval = true)
public <X> Subgraph<X> addKeySubgraph(Attribute<? super T, X> attribute);
/**
* Add a node to the graph that corresponds to a map key
* that is a managed type with inheritance. This allows for
* construction of multi-node entity graphs that include related
* managed types. Subclass subgraphs will automatically include
* the specified attributes of superclass subgraphs
*
* @param attribute attribute
* @param type entity subclass
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type entity
* @throws IllegalStateException if this EntityGraph has been
* statically defined
* @deprecated use {@link #addTreatedMapKeySubgraph(MapAttribute, Class)}
*/
@Deprecated(since = "3.2", forRemoval = true)
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<? super T, X> attribute, Class<? extends X> type);
/**
* Add a node to the graph that corresponds to a map key
* that is a managed type. This allows for construction of
* multi-node entity graphs that include related managed types.
*
* @param attributeName name of the attribute
* @return subgraph for the key attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this entity.
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addKeySubgraph(String attributeName);
/**
* Add a node to the graph that corresponds to a map key
* that is a managed type with inheritance. This allows for
* construction of multi-node entity graphs that include related
* managed types. Subclass subgraphs will include the specified
* attributes of superclass subgraphs
*
* @param attributeName name of the attribute
* @param type entity subclass
* @return subgraph for the attribute
* @throws IllegalArgumentException if the attribute is not an
* attribute of this entity.
* @throws IllegalArgumentException if the attribute's target
* type is not a managed type
* @throws IllegalStateException if this EntityGraph has been
* statically defined
*/
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type);
/**
* Return the attribute nodes corresponding to the attributes of
* this managed type that are included in the graph.
* @return list of attribute nodes included in the graph or an
* empty list if none have been defined
*/
public List<AttributeNode<?>> getAttributeNodes();
}
The deprecated methods of this interface will be removed in a future major release of this specification.
3.8.2. EntityGraph Interface
package jakarta.persistence;
/**
* This type represents the root of an entity graph that will be used
* as a template to define the attribute nodes and boundaries of a
* graph of entities and entity relationships. The root must be an
* entity type.
* <p>
* The methods to add subgraphs implicitly create the
* corresponding attribute nodes as well; such attribute nodes
* should not be redundantly specified.
*
* @param <T> The type of the root entity.
*
* @see AttributeNode
* @see Subgraph
* @see NamedEntityGraph
*
* @since 2.1
*/
public interface EntityGraph<T> extends Graph<T> {
/**
* Return the name of a named EntityGraph (an entity graph
* defined by means of the <code>NamedEntityGraph</code>
* annotation, XML descriptor element, or added by means of the
* <code>addNamedEntityGraph</code> method. Returns null if the
* EntityGraph is not a named EntityGraph.
*/
public String getName();
/**
* Add additional attributes to this entity graph that
* correspond to attributes of subclasses of this EntityGraph's
* entity type. Subclass subgraphs will automatically include the
* specified attributes of superclass subgraphs.
*
* @param type entity subclass
* @return subgraph for the subclass
* @throws IllegalArgumentException if the type is not an entity type
* @throws IllegalStateException if the EntityGraph has been
* statically defined
*/
public <S extends T> Subgraph<S> addTreatedSubgraph(Class<S> type);
/**
* Add additional attributes to this entity graph that
* correspond to attributes of subclasses of this EntityGraph's
* entity type. Subclass subgraphs will automatically include the
* specified attributes of superclass subgraphs.
*
* @param type entity subclass
* @return subgraph for the subclass
* @throws IllegalArgumentException if the type is not an entity type
* @throws IllegalStateException if the EntityGraph has been
* statically defined
* @deprecated use {@link #addTreatedSubgraph(Class)}
*/
@Deprecated(since = "3.2", forRemoval = true)
public <T> Subgraph<? extends T> addSubclassSubgraph(Class<? extends T> type);
}
The deprecated method of this interface will be removed in a future major release of this specification.
3.8.3. AttributeNode Interface
package jakarta.persistence;
import java.util.Map;
/**
* Represents an attribute node of an entity graph.
*
* @param <T> The type of the attribute.
*
* @see EntityGraph
* @see Subgraph
* @see NamedAttributeNode
*
* @since 2.1
*/
public interface AttributeNode<T> {
/**
* Return the name of the attribute corresponding to the
* attribute node.
* @return name of the attribute
*/
public String getAttributeName();
/**
* Return the Map<Class, Subgraph> of subgraphs associated
* with this attribute node.
* @return Map of subgraphs associated with this attribute node
* or empty Map if none have been defined
*/
public Map<Class, Subgraph> getSubgraphs();
/**
* Return the Map<Class, Subgraph> of subgraphs associated
* with this attribute node's map key.
* @return Map of subgraphs associated with this attribute
* node's map key or empty Map if none have been defined
*/
public Map<Class, Subgraph> getKeySubgraphs();
}
3.8.4. Subgraph Interface
package jakarta.persistence;
/**
* This type represents a subgraph for an attribute node that
* corresponds to a Managed Type. Using this class, an entity subgraph
* can be embedded within an EntityGraph.
*
* @param <T> The type of the attribute.
*
* @see EntityGraph
* @see AttributeNode
* @see NamedSubgraph
*
* @since 2.1
*/
public interface Subgraph<T> extends Graph<T> {
/**
* Return the type for which this subgraph was defined.
* @return managed type referenced by the subgraph
*/
public Class<T> getClassType();
}
3.8.5. Use of Entity Graphs in find and query operations
An entity graph can be used with the find
method or as a query hint to override or augment FetchType
semantics.
The standard properties
jakarta.persistence.fetchgraph
and jakarta.persistence.loadgraph
are
used to specify such graphs to queries and find
operations.
The default fetch graph for an entity or
embeddable is defined to consist of the transitive closure of all of its
attributes that are specified as FetchType.EAGER
(or defaulted as
such).
The persistence provider is permitted to fetch additional entity state beyond that specified by a fetch graph or load graph. It is required, however, that the persistence provider fetch all state specified by the fetch or load graph.
3.8.5.1. Fetch Graph Semantics
When the jakarta.persistence.fetchgraph
property is used to specify an entity graph, attributes that are
specified by attribute nodes of the entity graph are treated as
FetchType.EAGER
and attributes that are not specified are treated as
FetchType.LAZY
.
The following rules apply, depending on attribute type. The rules of this section are applied recursively.
A primary key or version attribute never needs to be specified in an attribute node of a fetch graph. (This applies to composite primary keys as well, including embedded id primary keys.) When an entity is fetched, its primary key and version attributes are always fetched. It is not incorrect, however, to specify primary key attributes or version attributes.
Attributes other than primary key and version attributes are assumed not to be fetched unless the attribute is specified. The following rules apply to the specification of attributes.
-
If the attribute is an embedded attribute, and the attribute is specified in an attribute node, but a subgraph is not specified for the attribute, the default fetch graph for the embeddable is fetched. If a subgraph is specified for the attribute, the attributes of the embeddable are fetched according to their specification in the corresponding subgraph.
-
If the attribute is an element collection of basic type, and the attribute is specified in an attribute node, the element collection together with its basic elements is fetched.
-
If the attribute is an element collection of embeddables, and the attribute is specified in an attribute node, but a subgraph is not specified for the attribute, the element collection together with the default fetch graph of its embeddable elements is fetched. If a subgraph is specified for the attribute, the attributes of the embeddable elements are fetched according to the corresponding subgraph specification.
-
If the attribute is a one-to-one or many-to-one relationship, and the attribute is specified in an attribute node, but a subgraph is not specified for the attribute, the default fetch graph of the target entity is fetched. If a subgraph is specified for the attribute, the attributes of the target entity are fetched according to the corresponding subgraph specification.
-
If the attribute is a one-to-many or many-to-many relationship, and the attribute is specified in an attribute node, but a subgraph is not specified, the collection is fetched and the default fetch graphs of the referenced entities are fetched. If a subgraph is specified for the attribute, the entities in the collection are fetched according to the corresponding subgraph specification.
-
If the key of a map which has been specified in an attribute node is a basic type, it is fetched. If the key of a map which has been specified in an attribute node is an embedded type, the default fetch graph is fetched for the embeddable. Otherwise, if the key of the map is an entity, and a map key subgraph is not specified for the attribute node, the map key is fetched according to its default fetch graph. If a key subgraph is specified for the map key attribute, the map key attribute is fetched according to the map key subgraph specification.
Examples:
@NamedEntityGraph
@Entity
public class Phonenumber {
@Id
protected String number;
protected PhoneTypeEnum type;
// ...
}
In the above example, only the number
attribute would be eagerly fetched.
@NamedEntityGraph(
attributeNodes={@NamedAttributeNode("projects")}
)
@Entity
public class Employee {
@Id
@GeneratedValue
protected long id;
@Basic
protected String name;
@Basic
protected String employeeNumber;
@OneToMany()
protected List<Dependents> dependents;
@OneToMany()
protected List<Project> projects;
@OneToMany()
protected List<PhoneNumber> phoneNumbers;
// ...
}
@Entity
@Inheritance
public class Project {
@Id
@GeneratedValue
protected long id;
String name;
@OneToOne(fetch=FetchType.EAGER)
protected Requirements doc;
// ...
}
@Entity
public class LargeProject extends Project {
@OneToOne(fetch=FetchType.LAZY)
protected Employee approver;
// ...
}
@Entity
public class Requirements {
@Id
protected long id;
@Lob
protected String description;
@OneToOne(fetch=FetchType.LAZY)
protected Approval approval
// ...
}
In the above example, the Employee
entity’s
primary key will be fetched as well as the related Project
instances,
whose default fetch graph (id
, name
, and doc
attributes) will
be fetched. The related Requirements
object will be fetched according
to its default fetch graph.
If the approver
attribute of LargeProject
were FetchType.EAGER
, and if any of the projects were instances of
LargeProject
, their approver
attributes would also be fetched.
Since the type of the approver
attribute is Employee
, the
approver’s default fetch graph (id
, name
, and employeeNumber
attributes) would also be fetched.
3.8.5.2. Load Graph Semantics
When the jakarta.persistence.loadgraph
property is used to specify an entity graph, attributes that are
specified by attribute nodes of the entity graph are treated as
FetchType.EAGER
and attributes that are not specified are treated
according to their specified or default FetchType.
The following rules apply. The rules of this section are applied recursively.
-
A primary key or version attribute never needs to be specified in an attribute node of a load graph. (This applies to composite primary keys as well, including embedded id primary keys.) When an entity is fetched, its primary key and version attributes are always fetched. It is not incorrect, however, to specify primary key attributes or version attributes.
-
If the attribute is an embedded attribute, and the attribute is specified in an attribute node, but a subgraph is not specified for the attribute, the default fetch graph for the embeddable is fetched. If a subgraph is specified for the attribute, attributes that are specified by the subgraph are also fetched.
-
If the attribute is an element collection of basic type, and the attribute is specified in an attribute node, the element collection together with its basic elements is fetched.
-
If the attribute is an element collection of embeddables, and the attribute is specified in an attribute node, the element collection together with the default fetch graph of its embeddable elements is fetched. If a subgraph is specified for the attribute, attributes that are specified by the subgraph are also fetched.
-
If the attribute is a one-to-one or many-to-one relationship, and the attribute is specified in an attribute node, the default fetch graph of the target entity is fetched. If a subgraph is specified for the attribute, attributes that are specified by the subgraph are also fetched.
-
If the attribute is a one-to-many or many-to-many relationship, and the attribute is specified in an attribute node, the collection is fetched and the default fetch graphs of the referenced entities are fetched. If a subgraph is specified for the attribute, attributes that are specified by the subgraph are also fetched.
-
If the key of a map which has been specified in an attribute node is a basic type, it is fetched. If the key of a map which has been specified in an attribute node is an embedded type, the default fetch graph is fetched for the embeddable. Otherwise, if the key of the map is an entity, the map key is fetched according to its default fetch graph. If a key subgraph is specified for the map key attribute, additional attributes are fetched as specified in the key subgraph.
Examples:
@NamedEntityGraph
@Entity
public class Phonenumber {
@Id
protected String number;
protected PhoneTypeEnum type;
// ...
}
In the above example, the number
and type
attributes are fetched.
@NamedEntityGraph(
attributeNodes={@NamedAttributeNode("projects")}
)
@Entity
public class Employee {
@Id
@GeneratedValue
protected long id;
@Basic
protected String name;
@Basic
protected String employeeNumber;
@OneToMany()
protected List<Dependents> dependents;
@OneToMany()
protected List<Project> projects;
@OneToMany()
protected List<PhoneNumber> phoneNumbers;
// ...
}
@Entity
@Inheritance
public class Project {
@Id
@GeneratedValue
protected long id;
String name;
@OneToOne(fetch=FetchType.EAGER)
protected Requirements doc;
// ...
}
@Entity
public class LargeProject extends Project {
@OneToOne(fetch=FetchType.LAZY)
protected Employee approver;
// ...
}
@Entity
public class Requirements {
@Id
protected long id;
@Lob
protected String description;
@OneToOne(fetch=FetchType.LAZY)
protected Approval approval
// ...
}
In the above example, the default fetch graph
(id
, name
, employeeNumber
attributes) of Employee
is fetched.
The default fetch graphs of the related Project
instances (id
,
name
, and doc
attributes) and their Requirements
instances (id
and description
attributes) are also fetched.
3.9. Type Conversion of Basic Attributes
The attribute conversion facility allows the developer to define custom
attribute converters. A converter
is a class whose methods convert
between:
-
the target type of the converter, an arbitrary Java type which may be used as the type of a persistent field or property, and
-
a basic type (see Section 2.6) used as an intermediate step in mapping to the database representation.
A converter can be used to convert attributes defined by entity classes, mapped superclasses, or embeddable classes.[54] A converted attribute is considered a basic attribute, since, with the aid of the converter, its values can be represented as instances of a basic type.
Every attribute converter class must implement the interface
jakarta.persistence.AttributeConverter
and must be annotated with the
Converter
annotation or declared as a converter in the XML descriptor.
If the value of the autoApply
element of the Converter
annotation is
true
, the converter is automatically applied to all attributes of the
target type, including to basic attribute values that are contained within
other, more complex attribute types. See Section 10.6.
package jakarta.persistence;
/**
* A class that implements this interface can be used to convert
* entity attribute state into database column representation
* and back again.
* Note that the X and Y types may be the same Java type.
*
* @param <X> the type of the entity attribute
* @param <Y> the type of the database column
*/
public interface AttributeConverter<X,Y> {
/**
* Converts the value stored in the entity attribute into the
* data representation to be stored in the database.
*
* @param attribute the entity attribute value to be converted
* @return the converted data to be stored in the database
* column
*/
public Y convertToDatabaseColumn (X attribute);
/**
* Converts the data stored in the database column into the
* value to be stored in the entity attribute.
* Note that it is the responsibility of the converter writer to
* specify the correct <code>dbData</code> type for the corresponding
* column for use by the JDBC driver: i.e., persistence providers are
* not expected to do such type conversion.
*
* @param dbData the data from the database column to be
* converted
* @return the converted value to be stored in the entity
* attribute
*/
public X convertToEntityAttribute (Y dbData);
}
Attribute converter classes in Jakarta EE
environments support dependency injection through the Contexts and
Dependency Injection API (CDI) [7] when CDI is
enabled[55]. An attribute converter class that makes
use of CDI injection may also define lifecycle callback methods
annotated with the PostConstruct
and PreDestroy
annotations. These
methods will be invoked after injection has taken place and before the
attribute converter instance is destroyed respectively.
The persistence provider is responsible for
using the CDI SPI to create instances of the attribute converter class;
to perform injection upon such instances; to invoke their
PostConstruct
and PreDestroy
methods, if any; and to dispose of the
attribute converter instances.
The persistence provider is only required to support CDI injection into attribute converters in Jakarta EE container environments[56]. If CDI is not enabled, the persistence provider must not invoke attribute converters that depend upon CDI injection.
An attribute converter is a noncontextual object. In supporting injection into attribute converters, the persistence provider must behave as if it carries out the following steps involving the use of the CDI SPI. (See [7]).
-
Obtain a
BeanManager
instance. (See Section 9.1.) -
Create an
AnnotatedType
instance for the attribute converter class. -
Create an
InjectionTarget
instance for the annotated type. -
Create a
CreationalContext
. -
Instantiate the listener by calling the
InjectionTarget
produce
method. -
Inject the listener instance by calling the
InjectionTarget
inject
method on the instance. -
Invoke the
PostConstruct
callback, if any, by calling theInjectionTarget
postConstruct
method on the instance.
When the listener instance is to be destroyed, the persistence provider must behave as if it carries out the following steps.
-
Call the
InjectionTarget
preDestroy
method on the instance. -
Call the
InjectionTarget
dispose
method on the instance. -
Call the
CreationalContext
release
method.
Persistence providers may optimize the steps above, e.g. by avoiding calls to the actual CDI SPI and relying on container-specific interfaces instead, as long as the outcome is the same.
Attribute converters that do not make use of CDI injection are stateless. The lifecycle of such attribute converters is unspecified.
The conversion of all basic types is
supported except for the following: Id attributes (including the
attributes of embedded ids and derived identities), version attributes,
relationship attributes, and attributes explicitly annotated as
Enumerated
or Temporal
or designated as such in the XML descriptor.
Auto-apply converters will not be applied to such attributes, and
applications that apply converters to such attributes through use of the
Convert
annotation will not be portable.
Type conversion may be specified at the level
of individual attributes by means of the Convert
annotation. The
Convert
annotation may also be used to override or disable an
auto-apply conversion. See Section 11.1.10.
The Convert
annotation may be applied
directly to an attribute of an entity, mapped superclass, or embeddable
class to specify conversion of the attribute or to override the use of a
converter that has been specified as autoApply=true
. When persistent
properties are used, the Convert
annotation is applied to the getter
method.
The Convert
annotation may be applied to an
entity that extends a mapped superclass to specify or override the
conversion mapping for an inherited basic or embedded attribute.
The persistence provider runtime is responsible for invoking the specified conversion methods for the target attribute type when loading the entity attribute from the database and before storing the entity attribute state to the database. The persistence provider must apply any conversion methods to instances of attribute values in path expressions used within Jakarta Persistence query language queries or criteria queries (such as in comparisons, bulk updates, etc.) before sending them to the database for the query execution. When such converted attributes are used in comparison operations with literals or parameters, the value of the literal or parameter to which they are compared must also be converted. If the result of a Jakarta Persistence query language query or criteria query includes one or more entity attributes for which conversion mappings have been specified, the persistence provider must apply the specified conversions to the corresponding values in the query result before returning them to the application. The use of functions, including aggregates, on converted attributes is undefined. If an exception is thrown from a conversion method, the persistence provider must wrap the exception in a PersistenceException and, if the persistence context is joined to a transaction, mark the transaction for rollback.
3.10. Second-Level Cache
A persistence provider may support the use of a second-level cache, that is, it might have a way to store data read in one persistence context for use in subsequent persistence contexts. A second-level cache might enhance performance, but tends to undermine the semantics of transaction processing, possibly exposing the application to stale data or similar anomalies.
Access to the second-level cache, if enabled, is mediated via the
persistence context, and is largely transparent to the application.
As an exception, the Cache
interface described below in Section 3.10.3
allows the application to directly evict data from the second-level cache.
The persistence provider is not required to support use of a second-level cache.
3.10.1. The Shared Cache Mode and Cacheable Annotation
Whether a given entity is eligible for storage in the second level cache is determined by:
-
the annotations of the entity class, and
-
the value specified for the
shared-cache-mode
element of thepersistence.xml
file or by the configuration propertyjakarta.persistence.sharedCache.mode
.
The value of the property jakarta.persistence.sharedCache.mode
takes
precedence over the value of the shared-cache-mode
element.
The shared-cache-mode
element takes one of five possible values,
which are enumerated by jakarta.persistence.SharedCacheMode
:
-
ALL
specifies that every entity and all its state may be cached. -
NONE
specifies that caching is disabled for the persistence unit, and that the persistence provider must not cache any entity data. -
ENABLE_SELECTIVE
specifies that an entity may be cached if the entity class is explicitly annotated@Cacheable
or@Cacheable(true)
, or if the equivalent setting is specified in XML. -
DISABLE_SELECTIVE
specifies that an entity may be cached unless the entity class is explicitly annotated@Cacheable(false)
, or unless the equivalent setting is specified in XML. -
UNSPECIFIED
selects the provider-specific default behavior.
If neither the shared-cache-mode
element nor the property
jakarta.persistence.sharedCache.mode
is specified, or if the specified
value is UNSPECIFIED
, the behavior is not defined, and provider-specific
defaults may apply. In particular, the semantics of the Cacheable
annotation (and XML equivalent) is undefined.
If the persistence provider does not support use of a second-level cache, or if a second-level cache is not installed or not enabled, this setting may be ignored and no caching will occur.
A persistence provider may support additional vendor-specific mechanisms for configuring the cache and marking entities eligible (or not) for storage in the second-level cache. However, if a second-level cache is supported, and enabled, the provider must respect the configuration options defined in this section, if specified by the application.
3.10.2. Cache Modes
The cache retrieve mode and cache store mode control how a given persistence context by interacts with the second-level cache.
-
The cache retrieve mode may be set by calling
setCacheRetrieveMode()
onEntityManager
orQuery
. -
The cache store mode may be set by calling
setCacheStoreMode()
onEntityManager
orQuery
. -
A cache store mode or cache retrieve mode, or both, may be passed to the
find()
method ofEntityManager
as aFindOption
. -
A cache store mode may be passed to the
refresh()
method ofEntityManager
as aRefreshOption
.
A cache mode specified for a given Query
instance applies only to
executions of that query, but takes precedence over the current cache
mode of the EntityManager
to which the Query
belongs. A cache mode
passed to find()
or refresh()
applies only to the method invocation,
and takes precedence over the current cache mode of the EntityManager
.
Alternatively, a cache mode may be specified using the property name
jakarta.persistence.cache.retrieveMode
or
jakarta.persistence.cache.storeMode
by:
-
calling the
setProperty()
method ofEntityManager
, -
calling the
setHint()
method ofQuery
, or -
passing a map containing one of these properties to
find()
orrefresh()
.
If second-level caching is not enabled (for example, if the
shared-cache-mode
element is set to NONE
), cache modes must be
ignored. Similarly, if a given entity is not eligible for storage in
the second-level cache (for example, if the shared-cache-mode
element
is set to ENABLE_SELECTIVE
, and the entity is not annotated @Cacheable
),
cache modes are ignored for operations applying to that entity.
Cache modes must be respected when caching is enabled, regardless of whether caching is enabled via the configuration options defined by this specification or via provider-specific mechanisms.
Applications which depend on the cache retrieve mode or cache store mode
but which do not specify the shared-cache-mode
element are not portable.
CacheRetrieveMode
enumerates the cache retrieve modes recognized by this
specification. The semantics of each mode is defined by its Javadoc.
package jakarta.persistence;
/**
* Used as the value of the
* <code>jakarta.persistence.cache.retrieveMode</code> property to
* specify the behavior when data is retrieved by the
* <code>find</code> methods and by queries.
*
* @since 2.0
*/
public enum CacheRetrieveMode {
/**
* Read entity data from the cache: this is
* the default behavior.
*/
USE,
/**
* Bypass the cache: get data directly from
* the database.
*/
BYPASS
}
CacheStoreMode
enumerates the cache store modes recognized by this
specification. The semantics of each mode is defined by its Javadoc.
package jakarta.persistence;
/**
* Used as the value of the
* <code>jakarta.persistence.cache.storeMode</code> property to specify
* the behavior when data is read from the database and when data is
* committed into the database.
*
* @since 2.0
*/
public enum CacheStoreMode {
/**
* Insert entity data into cache when read from database
* and insert/update entity data when committed into database:
* this is the default behavior. Does not force refresh
* of already cached items when reading from database.
*/
USE,
/**
* Don't insert into cache.
*/
BYPASS,
/**
* Insert/update entity data into cache when read
* from database and when committed into database.
* Forces refresh of cache for items read from database.
*/
REFRESH
}
3.10.3. Cache Interface
The Cache
interface allows the application to request eviction of
entity data from the second-level cache directly and immediately,
outside the scope of any persistence context.
package jakarta.persistence;
/**
* Interface used to interact with the second-level cache.
* If a cache is not in use, the methods of this interface have
* no effect, except for <code>contains</code>, which returns false.
*
* @since 2.0
*/
public interface Cache {
/**
* Whether the cache contains data for the given entity.
* @param cls entity class
* @param primaryKey primary key
* @return boolean indicating whether the entity is in the cache
*/
public boolean contains(Class cls, Object primaryKey);
/**
* Remove the data for the given entity from the cache.
* @param cls entity class
* @param primaryKey primary key
*/
public void evict(Class cls, Object primaryKey);
/**
* Remove the data for entities of the specified class (and its
* subclasses) from the cache.
* @param cls entity class
*/
public void evict(Class cls);
/**
* Clear the cache.
*/
public void evictAll();
/**
* Return an object of the specified type to allow access to the
* provider-specific API. If the provider's Cache
* implementation does not support the specified class, the
* PersistenceException is thrown.
* @param cls the class of the object to be returned. This is
* normally either the underlying Cache implementation
* class or an interface that it implements.
* @return an instance of the specified class
* @throws PersistenceException if the provider does not
* support the call
* @since 2.1
*/
public <T> T unwrap(Class<T> cls);
}
3.11. Query APIs
The Query
and TypedQuery
APIs are used
for the execution of both static queries and dynamic queries. These APIs
also support parameter binding and pagination control. The
StoredProcedureQuery
API is used for the execution of queries that
invoke stored procedures defined in the database.
3.11.1. Query Interface
package jakarta.persistence;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.stream.Stream;
/**
* Interface used to control query execution.
*
* @see TypedQuery
* @see StoredProcedureQuery
* @see Parameter
*
* @since 1.0
*/
public interface Query {
/**
* Execute a SELECT query and return the query results
* as an untyped List.
* @return a list of the results
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
List getResultList();
/**
* Execute a SELECT query and return the query results
* as an untyped <code>java.util.stream.Stream</code>.
* By default this method delegates to <code>getResultList().stream()</code>,
* however persistence provider may choose to override this method
* to provide additional capabilities.
*
* @return a stream of the results
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
* @see Stream
* @see #getResultList()
* @since 2.2
*/
default Stream getResultStream() {
return getResultList().stream();
}
/**
* Execute a SELECT query that returns a single untyped result.
* @return the result
* @throws NoResultException if there is no result
* @throws NonUniqueResultException if more than one result
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
Object getSingleResult();
/**
* Execute a SELECT query that returns a single untyped result.
* @return the result, or null if there is no result
* @throws NonUniqueResultException if more than one result
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
Object getSingleResultOrNull();
/**
* Execute an update or delete statement.
* @return the number of entities updated or deleted
* @throws IllegalStateException if called for a Jakarta
* Persistence query language SELECT statement or for
* a criteria query
* @throws TransactionRequiredException if there is
* no transaction or the persistence context has not
* been joined to the transaction
* @throws QueryTimeoutException if the statement execution
* exceeds the query timeout value set and only
* the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
int executeUpdate();
/**
* Set the maximum number of results to retrieve.
* @param maxResult maximum number of results to retrieve
* @return the same query instance
* @throws IllegalArgumentException if the argument is negative
*/
Query setMaxResults(int maxResult);
/**
* The maximum number of results the query object was set to
* retrieve. Returns <code>Integer.MAX_VALUE</code> if <code>setMaxResults</code> was not
* applied to the query object.
* @return maximum number of results
* @since 2.0
*/
int getMaxResults();
/**
* Set the position of the first result to retrieve.
* @param startPosition position of the first result,
* numbered from 0
* @return the same query instance
* @throws IllegalArgumentException if the argument is negative
*/
Query setFirstResult(int startPosition);
/**
* The position of the first result the query object was set to
* retrieve. Returns 0 if <code>setFirstResult</code> was not applied to the
* query object.
* @return position of the first result
* @since 2.0
*/
int getFirstResult();
/**
* Set a query property or hint. The hints elements may be used
* to specify query properties and hints. Properties defined by
* this specification must be observed by the provider.
* Vendor-specific hints that are not recognized by a provider
* must be silently ignored. Portable applications should not
* rely on the standard timeout hint. Depending on the database
* in use and the locking mechanisms used by the provider,
* this hint may or may not be observed.
* @param hintName name of the property or hint
* @param value value for the property or hint
* @return the same query instance
* @throws IllegalArgumentException if the second argument is not
* valid for the implementation
*/
Query setHint(String hintName, Object value);
/**
* Get the properties and hints and associated values that are
* in effect for the query instance.
* @return query properties and hints
* @since 2.0
*/
Map<String, Object> getHints();
/**
* Bind the value of a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if the parameter
* does not correspond to a parameter of the
* query
* @since 2.0
*/
<T> Query setParameter(Parameter<T> param, T value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
* @since 2.0
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
Query setParameter(Parameter<Calendar> param, Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
* @since 2.0
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
Query setParameter(Parameter<Date> param, Date value,
TemporalType temporalType);
/**
* Bind an argument value to a named parameter.
* @param name parameter name
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if
* the argument is of incorrect type
*/
Query setParameter(String name, Object value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a named parameter.
* @param name parameter name
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if
* the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
Query setParameter(String name, Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a named parameter.
* @param name parameter name
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if
* the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
Query setParameter(String name, Date value,
TemporalType temporalType);
/**
* Bind an argument value to a positional parameter.
* @param position position
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the
* query or if the argument is of incorrect type
*/
Query setParameter(int position, Object value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a positional
* parameter.
* @param position position
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query or
* if the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
Query setParameter(int position, Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a positional parameter.
* @param position position
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query or
* if the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
Query setParameter(int position, Date value,
TemporalType temporalType);
/**
* Get the parameter objects corresponding to the declared
* parameters of the query.
* Returns empty set if the query has no parameters.
* This method is not required to be supported for native
* queries.
* @return set of the parameter objects
* @throws IllegalStateException if invoked on a native
* query when the implementation does not support
* this use
* @since 2.0
*/
Set<Parameter<?>> getParameters();
/**
* Get the parameter object corresponding to the declared
* parameter of the given name.
* This method is not required to be supported for native
* queries.
* @param name parameter name
* @return parameter object
* @throws IllegalArgumentException if the parameter of the
* specified name does not exist
* @throws IllegalStateException if invoked on a native
* query when the implementation does not support
* this use
* @since 2.0
*/
Parameter<?> getParameter(String name);
/**
* Get the parameter object corresponding to the declared
* parameter of the given name and type.
* This method is required to be supported for criteria queries
* only.
* @param name parameter name
* @param type type
* @return parameter object
* @throws IllegalArgumentException if the parameter of the
* specified name does not exist or is not assignable
* to the type
* @throws IllegalStateException if invoked on a native
* query or Jakarta Persistence query language query when
* the implementation does not support this use
* @since 2.0
*/
<T> Parameter<T> getParameter(String name, Class<T> type);
/**
* Get the parameter object corresponding to the declared
* positional parameter with the given position.
* This method is not required to be supported for native
* queries.
* @param position position
* @return parameter object
* @throws IllegalArgumentException if the parameter with the
* specified position does not exist
* @throws IllegalStateException if invoked on a native
* query when the implementation does not support
* this use
* @since 2.0
*/
Parameter<?> getParameter(int position);
/**
* Get the parameter object corresponding to the declared
* positional parameter with the given position and type.
* This method is not required to be supported by the provider.
* @param position position
* @param type type
* @return parameter object
* @throws IllegalArgumentException if the parameter with the
* specified position does not exist or is not assignable
* to the type
* @throws IllegalStateException if invoked on a native
* query or Jakarta Persistence query language query when
* the implementation does not support this use
* @since 2.0
*/
<T> Parameter<T> getParameter(int position, Class<T> type);
/**
* Return a boolean indicating whether a value has been bound
* to the parameter.
* @param param parameter object
* @return boolean indicating whether parameter has been bound
* @since 2.0
*/
boolean isBound(Parameter<?> param);
/**
* Return the input value bound to the parameter.
* (Note that OUT parameters are unbound.)
* @param param parameter object
* @return parameter value
* @throws IllegalArgumentException if the parameter is not
* a parameter of the query
* @throws IllegalStateException if the parameter has not been
* been bound
* @since 2.0
*/
<T> T getParameterValue(Parameter<T> param);
/**
* Return the input value bound to the named parameter.
* (Note that OUT parameters are unbound.)
* @param name parameter name
* @return parameter value
* @throws IllegalStateException if the parameter has not been
* been bound
* @throws IllegalArgumentException if the parameter of the
* specified name does not exist
* @since 2.0
*/
Object getParameterValue(String name);
/**
* Return the input value bound to the positional parameter.
* (Note that OUT parameters are unbound.)
* @param position position
* @return parameter value
* @throws IllegalStateException if the parameter has not been
* been bound
* @throws IllegalArgumentException if the parameter with the
* specified position does not exist
* @since 2.0
*/
Object getParameterValue(int position);
/**
* Set the flush mode type to be used for the query execution.
* The flush mode type applies to the query regardless of the
* flush mode type in use for the entity manager.
* @param flushMode flush mode
* @return the same query instance
*/
Query setFlushMode(FlushModeType flushMode);
/**
* Get the flush mode in effect for the query execution.
* If a flush mode has not been set for the query object,
* returns the flush mode in effect for the entity manager.
* @return flush mode
* @since 2.0
*/
FlushModeType getFlushMode();
/**
* Set the lock mode type to be used for the query execution.
* @param lockMode lock mode
* @return the same query instance
* @throws IllegalStateException if the query is found not to be
* a Jakarta Persistence query language SELECT query
* or a CriteriaQuery query
* @since 2.0
*/
Query setLockMode(LockModeType lockMode);
/**
* Get the current lock mode for the query. Returns null if a lock
* mode has not been set on the query object.
* @return lock mode
* @throws IllegalStateException if the query is found not to be
* a Jakarta Persistence query language SELECT query or
* a Criteria API query
* @since 2.0
*/
LockModeType getLockMode();
/**
* Set the cache retrieval mode that is in effect during
* query execution. This cache retrieval mode overrides the
* cache retrieve mode in use by the entity manager.
* @param cacheRetrieveMode cache retrieval mode
* @return the same query instance
* @since 3.2
*/
Query setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode);
/**
* Set the cache storage mode that is in effect during
* query execution. This cache storage mode overrides the
* cache storage mode in use by the entity manager.
* @param cacheStoreMode cache storage mode
* @return the same query instance
* @since 3.2
*/
Query setCacheStoreMode(CacheStoreMode cacheStoreMode);
/**
* The cache retrieval mode that will be in effect during
* query execution.
* @since 3.2
*/
CacheRetrieveMode getCacheRetrieveMode();
/**
* The cache storage mode that will be in effect during
* query execution.
* @since 3.2
*/
CacheStoreMode getCacheStoreMode();
/**
* Set the query timeout, in milliseconds. This is a hint,
* and is an alternative to {@linkplain #setHint setting
* the hint} {@code jakarta.persistence.query.timeout}.
* @param timeout the timeout, in milliseconds, or null to
* indicate no timeout
* @return the same query instance
* @since 3.2
*/
Query setTimeout(Integer timeout);
/**
* The query timeout.
* @since 3.2
*/
Integer getTimeout();
/**
* Return an object of the specified type to allow access to
* the provider-specific API. If the provider's query
* implementation does not support the specified class, the
* <code>PersistenceException</code> is thrown.
* @param cls the class of the object to be returned. This is
* normally either the underlying query
* implementation class or an interface that it
* implements.
* @return an instance of the specified class
* @throws PersistenceException if the provider does not support
* the call
* @since 2.0
*/
<T> T unwrap(Class<T> cls);
}
3.11.2. TypedQuery Interface
package jakarta.persistence;
import java.util.List;
import java.util.Date;
import java.util.Calendar;
import java.util.stream.Stream;
/**
* Interface used to control the execution of typed queries.
* @param <X> query result type
*
* @see Query
* @see Parameter
*
* @since 2.0
*/
public interface TypedQuery<X> extends Query {
/**
* Execute a SELECT query and return the query results
* as a typed List.
* @return a list of the results
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the
* transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
List<X> getResultList();
/**
* Execute a SELECT query and return the query results
* as a typed <code>java.util.stream.Stream</code>.
* By default this method delegates to <code>getResultList().stream()</code>,
* however persistence provider may choose to override this method
* to provide additional capabilities.
*
* @return a stream of the results
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
* @see Stream
* @see #getResultList()
* @since 2.2
*/
default Stream<X> getResultStream() {
return getResultList().stream();
}
/**
* Execute a SELECT query that returns a single result.
* @return the result
* @throws NoResultException if there is no result
* @throws NonUniqueResultException if more than one result
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the
* transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
X getSingleResult();
/**
* Execute a SELECT query that returns a single untyped result.
* @return the result, or null if there is no result
* @throws NonUniqueResultException if more than one result
* @throws IllegalStateException if called for a Jakarta
* Persistence query language UPDATE or DELETE statement
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws TransactionRequiredException if a lock mode other than
* <code>NONE</code> has been set and there is no transaction
* or the persistence context has not been joined to the transaction
* @throws PessimisticLockException if pessimistic locking
* fails and the transaction is rolled back
* @throws LockTimeoutException if pessimistic locking
* fails and only the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
X getSingleResultOrNull();
/**
* Set the maximum number of results to retrieve.
* @param maxResult maximum number of results to retrieve
* @return the same query instance
* @throws IllegalArgumentException if the argument is negative
*/
TypedQuery<X> setMaxResults(int maxResult);
/**
* Set the position of the first result to retrieve.
* @param startPosition position of the first result,
* numbered from 0
* @return the same query instance
* @throws IllegalArgumentException if the argument is negative
*/
TypedQuery<X> setFirstResult(int startPosition);
/**
* Set a query property or hint. The hints elements may be used
* to specify query properties and hints. Properties defined by
* this specification must be observed by the provider.
* Vendor-specific hints that are not recognized by a provider
* must be silently ignored. Portable applications should not
* rely on the standard timeout hint. Depending on the database
* in use and the locking mechanisms used by the provider,
* this hint may or may not be observed.
* @param hintName name of property or hint
* @param value value for the property or hint
* @return the same query instance
* @throws IllegalArgumentException if the second argument is not
* valid for the implementation
*/
TypedQuery<X> setHint(String hintName, Object value);
/**
* Bind the value of a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if the parameter
* does not correspond to a parameter of the
* query
*/
<T> TypedQuery<X> setParameter(Parameter<T> param, T value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
TypedQuery<X> setParameter(Parameter<Calendar> param,
Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
TypedQuery<X> setParameter(Parameter<Date> param, Date value,
TemporalType temporalType);
/**
* Bind an argument value to a named parameter.
* @param name parameter name
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if
* the argument is of incorrect type
*/
TypedQuery<X> setParameter(String name, Object value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a named parameter.
* @param name parameter name
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if
* the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
TypedQuery<X> setParameter(String name, Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a named parameter.
* @param name parameter name
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if
* the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
TypedQuery<X> setParameter(String name, Date value,
TemporalType temporalType);
/**
* Bind an argument value to a positional parameter.
* @param position position
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the
* query or if the argument is of incorrect type
*/
TypedQuery<X> setParameter(int position, Object value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a positional
* parameter.
* @param position position
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query
* or if the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
TypedQuery<X> setParameter(int position, Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a positional parameter.
* @param position position
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query
* or if the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
TypedQuery<X> setParameter(int position, Date value,
TemporalType temporalType);
/**
* Set the flush mode type to be used for the query execution.
* The flush mode type applies to the query regardless of the
* flush mode type in use for the entity manager.
* @param flushMode flush mode
* @return the same query instance
*/
TypedQuery<X> setFlushMode(FlushModeType flushMode);
/**
* Set the lock mode type to be used for the query execution.
* @param lockMode lock mode
* @return the same query instance
* @throws IllegalStateException if the query is found not to
* be a Jakarta Persistence query language SELECT query
* or a CriteriaQuery query
*/
TypedQuery<X> setLockMode(LockModeType lockMode);
/**
* Set the cache retrieval mode that is in effect during
* query execution. This cache retrieval mode overrides the
* cache retrieve mode in use by the entity manager.
* @param cacheRetrieveMode cache retrieval mode
* @return the same query instance
* @since 3.2
*/
TypedQuery<X> setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode);
/**
* Set the cache storage mode that is in effect during
* query execution. This cache storage mode overrides the
* cache storage mode in use by the entity manager.
* @param cacheStoreMode cache storage mode
* @return the same query instance
* @since 3.2
*/
TypedQuery<X> setCacheStoreMode(CacheStoreMode cacheStoreMode);
/**
* Set the query timeout, in milliseconds. This is a hint,
* and is an alternative to {@linkplain #setHint setting
* the hint} {@code jakarta.persistence.query.timeout}.
* @param timeout the timeout, in milliseconds, or null to
* indicate no timeout
* @return the same query instance
* @since 3.2
*/
TypedQuery<X> setTimeout(Integer timeout);
}
3.11.3. Tuple Interface
package jakarta.persistence;
import java.util.List;
/**
* Interface for extracting the elements of a query result tuple.
*
* @see TupleElement
*
* @since 2.0
*/
public interface Tuple {
/**
* Get the value of the specified tuple element.
* @param tupleElement tuple element
* @return value of tuple element
* @throws IllegalArgumentException if tuple element
* does not correspond to an element in the
* query result tuple
*/
<X> X get(TupleElement<X> tupleElement);
/**
* Get the value of the tuple element to which the
* specified alias has been assigned.
* @param alias alias assigned to tuple element
* @param type of the tuple element
* @return value of the tuple element
* @throws IllegalArgumentException if alias
* does not correspond to an element in the
* query result tuple or element cannot be
* assigned to the specified type
*/
<X> X get(String alias, Class<X> type);
/**
* Get the value of the tuple element to which the
* specified alias has been assigned.
* @param alias alias assigned to tuple element
* @return value of the tuple element
* @throws IllegalArgumentException if alias
* does not correspond to an element in the
* query result tuple
*/
Object get(String alias);
/**
* Get the value of the element at the specified
* position in the result tuple. The first position is 0.
* @param i position in result tuple
* @param type type of the tuple element
* @return value of the tuple element
* @throws IllegalArgumentException if i exceeds
* length of result tuple or element cannot be
* assigned to the specified type
*/
<X> X get(int i, Class<X> type);
/**
* Get the value of the element at the specified
* position in the result tuple. The first position is 0.
* @param i position in result tuple
* @return value of the tuple element
* @throws IllegalArgumentException if i exceeds
* length of result tuple
*/
Object get(int i);
/**
* Return the values of the result tuple elements as an array.
* @return tuple element values
*/
Object[] toArray();
/**
* Return the tuple elements.
* @return tuple elements
*/
List<TupleElement<?>> getElements();
}
3.11.4. TupleElement Interface
package jakarta.persistence;
/**
* The <code>TupleElement</code> interface defines an element that is returned in
* a query result tuple.
* @param <X> the type of the element
*
* @see Tuple
*
* @since 2.0
*/
public interface TupleElement<X> {
/**
* Return the Java type of the tuple element.
* @return the Java type of the tuple element
*/
Class<? extends X> getJavaType();
/**
* Return the alias assigned to the tuple element or null,
* if no alias has been assigned.
* @return alias
*/
String getAlias();
}
3.11.5. Parameter Interface
package jakarta.persistence;
/**
* Type for query parameter objects.
* @param <T> the type of the parameter
*
* @see Query
* @see TypedQuery
*
* @since 2.0
*/
public interface Parameter<T> {
/**
* Return the parameter name, or null if the parameter is
* not a named parameter or no name has been assigned.
* @return parameter name
*/
String getName();
/**
* Return the parameter position, or null if the parameter
* is not a positional parameter.
* @return position of parameter
*/
Integer getPosition();
/**
* Return the Java type of the parameter. Values bound to the
* parameter must be assignable to this type.
* This method is required to be supported for criteria queries
* only. Applications that use this method for Jakarta
* Persistence query language queries and native queries will
* not be portable.
* @return the Java type of the parameter
* @throws IllegalStateException if invoked on a parameter
* obtained from a query language
* query or native query when the implementation does
* not support this use
*/
Class<T> getParameterType();
}
3.11.6. StoredProcedureQuery Interface
package jakarta.persistence;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* Interface used to control stored procedure query execution.
*
* <p>
* Stored procedure query execution may be controlled in accordance with
* the following:
* <ul>
* <li>The <code>setParameter</code> methods are used to set the values of
* all required <code>IN</code> and <code>INOUT</code> parameters.
* It is not required to set the values of stored procedure parameters
* for which default values have been defined by the stored procedure.</li>
* <li>
* When <code>getResultList</code> and <code>getSingleResult</code> are
* called on a <code>StoredProcedureQuery</code> object, the provider
* will call <code>execute</code> on an unexecuted stored procedure
* query before processing <code>getResultList</code> or
* <code>getSingleResult</code>.</li>
* <li>
* When <code>executeUpdate</code> is called on a
* <code>StoredProcedureQuery</code> object, the provider will call
* <code>execute</code> on an unexecuted stored procedure query
* followed by <code>getUpdateCount</code>. The results of
* <code>executeUpdate</code> will be those of <code>getUpdateCount</code>.</li>
* <li>
* The <code>execute</code> method supports both the simple case where
* scalar results are passed back only via <code>INOUT</code> and
* <code>OUT</code> parameters as well as the most general case
* (multiple result sets and/or update counts, possibly also in
* combination with output parameter values).</li>
* <li>
* The <code>execute</code> method returns true if the first result is a
* result set, and false if it is an update count or there are no results
* other than through <code>INOUT</code> and <code>OUT</code> parameters,
* if any.</li>
* <li>
* If the <code>execute</code> method returns true, the pending result set
* can be obtained by calling <code>getResultList</code> or
* <code>getSingleResult</code>.</li>
* <li>
* The <code>hasMoreResults</code> method can then be used to test
* for further results.</li>
* <li>
* If <code>execute</code> or <code>hasMoreResults</code> returns false,
* the <code>getUpdateCount</code> method can be called to obtain the
* pending result if it is an update count. The <code>getUpdateCount</code>
* method will return either the update count (zero or greater) or -1
* if there is no update count (i.e., either the next result is a result set
* or there is no next update count).</li>
* <li>
* For portability, results that correspond to JDBC result sets and
* update counts need to be processed before the values of any
* <code>INOUT</code> or <code>OUT</code> parameters are extracted.</li>
* <li>
* After results returned through <code>getResultList</code> and
* <code>getUpdateCount</code> have been exhausted, results returned through
* <code>INOUT</code> and <code>OUT</code> parameters can be retrieved.</li>
* <li>
* The <code>getOutputParameterValue</code> methods are used to retrieve
* the values passed back from the procedure through <code>INOUT</code>
* and <code>OUT</code> parameters.</li>
* <li>
* When using <code>REF_CURSOR</code> parameters for result sets the
* update counts should be exhausted before calling <code>getResultList</code>
* to retrieve the result set. Alternatively, the <code>REF_CURSOR</code>
* result set can be retrieved through <code>getOutputParameterValue</code>.
* Result set mappings will be applied to results corresponding to
* <code>REF_CURSOR</code> parameters in the order the <code>REF_CURSOR</code>
* parameters were registered with the query.</li>
* <li>
* In the simplest case, where results are returned only via
* <code>INOUT</code> and <code>OUT</code> parameters, <code>execute</code>
* can be followed immediately by calls to
* <code>getOutputParameterValue</code>.</li>
* </ul>
*
* @see Query
* @see Parameter
*
* @since 2.1
*/
public interface StoredProcedureQuery extends Query {
/**
* Set a query property or hint. The hints elements may be used
* to specify query properties and hints. Properties defined by
* this specification must be observed by the provider.
* Vendor-specific hints that are not recognized by a provider
* must be silently ignored. Portable applications should not
* rely on the standard timeout hint. Depending on the database
* in use, this hint may or may not be observed.
* @param hintName name of the property or hint
* @param value value for the property or hint
* @return the same query instance
* @throws IllegalArgumentException if the second argument is not
* valid for the implementation
*/
StoredProcedureQuery setHint(String hintName, Object value);
/**
* Bind the value of a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
*/
<T> StoredProcedureQuery setParameter(Parameter<T> param,
T value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
StoredProcedureQuery setParameter(Parameter<Calendar> param,
Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a <code>Parameter</code> object.
* @param param parameter object
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter does not
* correspond to a parameter of the query
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
StoredProcedureQuery setParameter(Parameter<Date> param,
Date value,
TemporalType temporalType);
/**
* Bind an argument value to a named parameter.
* @param name parameter name
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if the
* argument is of incorrect type
*/
StoredProcedureQuery setParameter(String name, Object value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a named parameter.
* @param name parameter name
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if the
* value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
StoredProcedureQuery setParameter(String name,
Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a named parameter.
* @param name parameter name
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or if the
* value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
StoredProcedureQuery setParameter(String name,
Date value,
TemporalType temporalType);
/**
* Bind an argument value to a positional parameter.
* @param position position
* @param value parameter value
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query
* or if the argument is of incorrect type
*/
StoredProcedureQuery setParameter(int position, Object value);
/**
* Bind an instance of <code>java.util.Calendar</code> to a positional
* parameter.
* @param position position
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query or
* if the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
StoredProcedureQuery setParameter(int position,
Calendar value,
TemporalType temporalType);
/**
* Bind an instance of <code>java.util.Date</code> to a positional parameter.
* @param position position
* @param value parameter value
* @param temporalType temporal type
* @return the same query instance
* @throws IllegalArgumentException if position does not
* correspond to a positional parameter of the query or
* if the value argument is of incorrect type
* @deprecated Newly-written code should use the date/time types
* defined in {@link java.time}.
*/
@Deprecated(since = "3.2")
StoredProcedureQuery setParameter(int position,
Date value,
TemporalType temporalType);
/**
* Set the flush mode type to be used for the query execution.
* The flush mode type applies to the query regardless of the
* flush mode type in use for the entity manager.
* @param flushMode flush mode
* @return the same query instance
*/
StoredProcedureQuery setFlushMode(FlushModeType flushMode);
/**
* Set the cache retrieval mode that is in effect during
* query execution. This cache retrieval mode overrides the
* cache retrieve mode in use by the entity manager.
* @param cacheRetrieveMode cache retrieval mode
* @return the same query instance
* @since 3.2
*/
StoredProcedureQuery setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode);
/**
* Set the cache storage mode that is in effect during
* query execution. This cache storage mode overrides the
* cache storage mode in use by the entity manager.
* @param cacheStoreMode cache storage mode
* @return the same query instance
* @since 3.2
*/
StoredProcedureQuery setCacheStoreMode(CacheStoreMode cacheStoreMode);
/**
* Set the query timeout, in milliseconds. This is a hint,
* and is an alternative to {@linkplain #setHint setting
* the hint} {@code jakarta.persistence.query.timeout}.
* @param timeout the timeout, in milliseconds, or null to
* indicate no timeout
* @return the same query instance
* @since 3.2
*/
StoredProcedureQuery setTimeout(Integer timeout);
/**
* Register a positional parameter.
* All parameters must be registered.
* @param position parameter position
* @param type type of the parameter
* @param mode parameter mode
* @return the same query instance
*/
StoredProcedureQuery registerStoredProcedureParameter(
int position,
Class type,
ParameterMode mode);
/**
* Register a named parameter.
* @param parameterName name of the parameter as registered or
* specified in metadata
* @param type type of the parameter
* @param mode parameter mode
* @return the same query instance
*/
StoredProcedureQuery registerStoredProcedureParameter(
String parameterName,
Class type,
ParameterMode mode);
/**
* Retrieve a value passed back from the procedure
* through an INOUT or OUT parameter.
* For portability, all results corresponding to result sets
* and update counts must be retrieved before the values of
* output parameters.
* @param position parameter position
* @return the result that is passed back through the parameter
* @throws IllegalArgumentException if the position does
* not correspond to a parameter of the query or is
* not an INOUT or OUT parameter
*/
Object getOutputParameterValue(int position);
/**
* Retrieve a value passed back from the procedure
* through an INOUT or OUT parameter.
* For portability, all results corresponding to result sets
* and update counts must be retrieved before the values of
* output parameters.
* @param parameterName name of the parameter as registered or
* specified in metadata
* @return the result that is passed back through the parameter
* @throws IllegalArgumentException if the parameter name does
* not correspond to a parameter of the query or is
* not an INOUT or OUT parameter
*/
Object getOutputParameterValue(String parameterName);
/**
* Return true if the first result corresponds to a result set,
* and false if it is an update count or if there are no results
* other than through INOUT and OUT parameters, if any.
* @return true if first result corresponds to result set
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
boolean execute();
/**
* Return the update count of -1 if there is no pending result or
* if the first result is not an update count. The provider will
* call <code>execute</code> on the query if needed.
* @return the update count or -1 if there is no pending result
* or if the next result is not an update count.
* @throws TransactionRequiredException if there is
* no transaction or the persistence context has not
* been joined to the transaction
* @throws QueryTimeoutException if the statement execution
* exceeds the query timeout value set and only
* the statement is rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
int executeUpdate();
/**
* Retrieve the list of results from the next result set.
* The provider will call <code>execute</code> on the query
* if needed.
* A <code>REF_CURSOR</code> result set, if any, will be retrieved
* in the order the <code>REF_CURSOR</code> parameter was
* registered with the query.
* @return a list of the results or null is the next item is not
* a result set
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
List getResultList();
/**
* Retrieve a single result from the next result set.
* The provider will call <code>execute</code> on the query
* if needed.
* A <code>REF_CURSOR</code> result set, if any, will be retrieved
* in the order the <code>REF_CURSOR</code> parameter was
* registered with the query.
* @return the result or null if the next item is not a result set
* @throws NoResultException if there is no result in the next
* result set
* @throws NonUniqueResultException if more than one result
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
Object getSingleResult();
/**
* Retrieve a single result from the next result set.
* The provider will call <code>execute</code> on the query
* if needed.
* A <code>REF_CURSOR</code> result set, if any, will be retrieved
* in the order the <code>REF_CURSOR</code> parameter was
* registered with the query.
* @return the result or null if the next item is not a result set
* or if there is no result in the next result set
* @throws NonUniqueResultException if more than one result
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
Object getSingleResultOrNull();
/**
* Return true if the next result corresponds to a result set,
* and false if it is an update count or if there are no results
* other than through INOUT and OUT parameters, if any.
* @return true if next result corresponds to result set
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
boolean hasMoreResults();
/**
* Return the update count or -1 if there is no pending result
* or if the next result is not an update count.
* @return update count or -1 if there is no pending result or if
* the next result is not an update count
* @throws QueryTimeoutException if the query execution exceeds
* the query timeout value set and only the statement is
* rolled back
* @throws PersistenceException if the query execution exceeds
* the query timeout value set and the transaction
* is rolled back
*/
int getUpdateCount();
}
3.11.7. Query Execution
Jakarta Persistence query language, Criteria API, and native SQL
select queries are executed using the methods getResultList
,
getSingleResult
, and getSingleResultOrNull
.
Update and delete operations (update and delete “queries”) are
executed using the executeUpdate
method.
-
For
TypedQuery
instances, the query result type is determined in the case of criteria queries by the type of the query specified when theCriteriaQuery
object is created, as described in Section 6.5.1. In the case of Jakarta Persistence query language queries, the type of the result is determined by theresultClass
argument to thecreateQuery
orcreateNamedQuery
method, and the select list of the query must contain only a single item which must be assignable to the specified type. -
For
Query
instances, the elements of a query result whose select list consists of more than one select expression are of typeObject[]
. If the select list consists of only one select expression, the elements of the query result are of typeObject
. When native SQL queries are used, the SQL result set mapping (see Section 3.11.17), determines how many items (entities, scalar values, etc.) are returned. If multiple items are returned, the elements of the query result are of typeObject[]
. If only a single item is returned as a result of the SQL result set mapping or if a result class is specified, the elements of the query result are of typeObject
.
Stored procedure queries can be executed using the getResultList
,
getSingleResult
, getSingleResultOrNull
, and execute
methods.
Stored procedures that perform only updates or deletes can be executed
using the executeUpdate
method. Stored procedure query execution is
described in detail in Section 3.11.18.3.
An IllegalArgumentException
is thrown if a
parameter instance is specified that does not correspond to a parameter
of the query, if a parameter name is specified that does not correspond
to a named parameter of the query, if a positional value is specified
that does not correspond to a positional parameter of the query, or if
the type of the parameter is not valid for the query. This exception may
be thrown when the parameter is bound, or the execution of the query may
fail. See Section 3.11.11, Section 3.11.12, and Section 3.11.13 for supported
parameter usage.
The effect of applying setMaxResults
or
setFirstResult
to a query involving fetch joins over collections is
undefined. The use of setMaxResults
and setFirstResult
is not
supported for stored procedure queries.
Query
and TypedQuery
methods other than
the executeUpdate
method are not required to be invoked within a
transaction context, unless a lock mode other than LockModeType.NONE
has been specified for the query. In particular, the getResultList
,
getSingleResult
, and getSingleResultOrNull
methods are not required
to be invoked within a transaction context unless such a lock mode has
been specified for the query[57]. If an entity manager with
transaction-scoped persistence context is in use, the resulting entities
will be detached; if an entity manager with an extended persistence
context is used, they will be managed. See Chapter 7 for further
discussion of entity manager use outside a transaction and persistence context types.
Whether a StoredProcedureQuery
should be
invoked in a transaction context should be determined by the
transactional semantics and/or requirements of the stored procedure
implementation and the database in use. In particular, problems may
occur if the stored procedure initiates a transaction and a transaction
is already in effect. The state of any entities returned by the stored
procedure query invocation is determined as decribed above.
Runtime exceptions other than the
NoResultException
, NonUniqueResultException
,
QueryTimeoutException
, and LockTimeoutException
thrown by the
methods of the Query
, TypedQuery
, and StoredProcedureQuery
interfaces other than those methods specified below cause the current
transaction to be marked for rollback if the persistence context is
joined to the transaction. On database platforms on which a query
timeout causes transaction rollback, the persistence provider must throw
the PersistenceException
instead of the QueryTimeoutException
.
Runtime exceptions thrown by the following
methods of the Query
, TypedQuery
, and StoredProcedureQuery
interfaces do not cause the current transaction to be marked for
rollback: getParameters
, getParameter
, getParameterValue
,
getOutputParameterValue
, getLockMode
.
Runtime exceptions thrown by the methods of
the Tuple
, TupleElement
, and Parameter
interfaces do not cause
the current transaction to be marked for rollback.
For example:
public List findWithName(String name) {
return em.createQuery("SELECT c FROM Customer c WHERE c.name LIKE :custName")
.setParameter("custName", name)
.setMaxResults(10)
.getResultList();
}
3.11.8. Queries and Flush Mode
The flush mode setting affects the result of a query as follows.
When queries are executed within a
transaction, if FlushModeType.AUTO
is set on the Query
,
TypedQuery
, or StoredProcedureQuery
object, or if the flush mode
setting for the persistence context is AUTO
(the default) and a flush
mode setting has not been specified for the query object, the
persistence provider is responsible for ensuring that all updates to the
state of all entities in the persistence context which could potentially
affect the result of the query are visible to the processing of the
query. The persistence provider implementation may achieve this by
flushing those entities to the database or by some other means. If
FlushModeType.COMMIT
is set, the effect of updates made to entities in
the persistence context upon queries is unspecified.
If the persistence context has not been joined to the current transaction, the persistence provider must not flush to the database regardless of the flush mode setting.
package jakarta.persistence;
public enum FlushModeType {
/**
* Flushing to occur at transaction commit. The provider may flush
* at other times, but is not required to.
*/
COMMIT,
/**
* (Default) Flushing to occur at query execution.
*/
AUTO
}
If there is no transaction active, the persistence provider must not flush to the database.
3.11.9. Queries and Lock Mode
The setLockMode
method of the
Query
or TypedQuery
interface or the lockMode
element of the
NamedQuery
annotation may be used to lock the results of a query. A
lock is obtained for each entity specified in the query result
(including entities passed to constructors in the query SELECT
clause).[58]
If the lock mode type is PESSIMISTIC_READ
,
PESSIMISTIC_WRITE
, or PESSIMISTIC_FORCE_INCREMENT
, and the query
returns scalar data (e.g., the values of entity field or properties,
including scalar data passed to constructors in the query SELECT
clause), the underlying database rows will be
locked[59], but the version columns (if any) for any
entities corresponding to such scalar data will not be updated unless
the entities themselves are also otherwise retrieved and updated.
If the lock mode type is OPTIMISTIC
or
OPTIMISTIC_FORCE_INCREMENT
, and the query returns scalar data, any
entities returned by the query will be locked, but no locking will occur
for scalar data that does not correspond to the state of any entity
instance in the query result.
If a lock mode other than NONE
is specified
for a query, the query must be executed within a transaction (and the
persistence context must be joined to the transaction) or the
TransactionRequiredException
will be thrown.
Locking is supported for Jakarta Persistence
query language queries and criteria queries only. If the setLockMode
or getLockMode
method is invoked on a query that is not a Jakarta
Persistence query language select query or a criteria query, the
IllegalStateException
may be thrown or the query execution will fail.
3.11.10. Query Hints
The following hint is defined by this specification for use in query configuration.
jakarta.persistence.query.timeout // time in milliseconds
This hint may be used with the Query
,
TypedQuery
, or StoredProcedureQuery
setHint
method or the
NamedQuery
, NamedNativeQuery
, and NamedStoredProcedureQuery
annotations. It may also be passed as a property to the
Persistence.createEntityManagerFactory
method and used in the
properties
element of the persistence.xml
file. See Section 3.11.1,
Section 8.2.1.11, Section 9.7, Section 10.4. When used in
the createEntityManagerFactory
method, the persistence.xml
file, and
annotations, the timeout
hint serves as a default value which can be
selectively overridden by use in the setHint
method.
Portable applications should not rely on this hint. Depending on the persistence provider and database in use, the hint may or may not be observed.
Vendors are permitted to support the use of
additional, vendor-specific hints. Vendor-specific hints must not use
the jakarta.persistence
namespace. Vendor-specific hints must be ignored
if they are not understood.
3.11.11. Parameter Objects
Parameter
objects can be used for criteria
queries and for Jakarta Persistence query language queries.
Implementations may support the use of
Parameter
objects for native queries, however support for Parameter
objects with native queries is not required by this specification. The
use of Parameter
objects for native queries will not be portable. The
mixing of parameter objects with named or positional parameters is invalid.
Portable applications should not attempt to
reuse a Parameter
object obtained from a Query
or TypedQuery
instance in the context of a different Query
or TypedQuery
instance.
3.11.12. Named Parameters
Named parameters can be used for Jakarta
Persistence query language queries, for criteria queries (although use
of Parameter
objects is to be preferred), and for stored procedure
queries that support named parameters.
Named parameters follow the rules for identifiers defined in Section 4.4.1. Named parameters are case-sensitive. The mixing of named and positional parameters is invalid.
A named parameter of a Jakarta Persistence query
language query is an identifier that is prefixed by the " : " symbol.
The parameter names passed to the setParameter
methods of the Query
and TypedQuery
interfaces do not include this " : " prefix.
3.11.13. Positional Parameters
Only positional parameter binding and
positional access to result items may be portably used for native
queries, except for stored procedure queries for which named parameters
have been defined. When binding the values of positional parameters, the
numbering starts as “ 1
”. It is assumed that for native queries the
parameters themselves use the SQL syntax (i.e., “ ? ”, rather than “
?1 ”).
The use of positional parameters is not supported for criteria queries.
3.11.14. Arguments to query parameters
Arguments are assigned to query parameters by calling Query.setParameter()
.
The first parameter of setParameter()
identifies the named or positional
parameter of the query.
An argument may be assigned to a single-valued parameter of a JPQL or
native SQL query by passing the argument to the second parameter of
setParameter()
.
query.setParameter("name", name)
A list of arguments may be assigned to a collection-valued parameter
of a JPQL query by packaging the arguments in a non-null instance of
java.util.List
and passing the list as an argument to the second
parameter of setParameter()
. The list should contain at least one
element. If the list is empty the behavior is undefined. Portable
applications should not pass an empty list to a collection-valued
parameter.
query.setParameter("names", List.of(name1, name2, name3))
3.11.15. Named Queries
Named queries are static queries expressed in
metadata or queries registered by means of the EntityManagerFactory
addNamedQuery
method. Named queries can be defined in the Jakarta
Persistence query language or in SQL. Query names are scoped to the
persistence unit.
The following is an example of the definition of a named query defined in metadata:
@NamedQuery(
name="findAllCustomersWithName",
query="SELECT c FROM Customer c WHERE c.name LIKE :custName"
)
The following is an example of the use of a named query:
@PersistenceContext
public EntityManager em;
// ...
customers = em.createNamedQuery("findAllCustomersWithName")
.setParameter("custName", "Smith")
.getResultList();
3.11.16. Polymorphic Queries
By default, all queries are polymorphic. That is, the FROM clause of a query designates not only instances of the specific entity class(es) to which it explicitly refers, but subclasses as well. The instances returned by a query include instances of the subclasses that satisfy the query conditions.
For example, the following query returns the
average salary of all employees, including subtypes of Employee
, such
as Manager
and Exempt
.
select avg(e.salary) from Employee e where e.salary > 80000
Entity type expressions, described in Section 4.7.7, as well as the use of downcasting, described in Section 4.4.9, can be used to restrict query polymorphism.
3.11.17. SQL Queries
Queries may be expressed in native SQL. The result of a native SQL query may consist of entities, unmanaged instances created via constructors, scalar values, or some combination of these.
The SQL query facility is intended to provide support for those cases where it is necessary to use the native SQL of the target database in use (and/or where the Jakarta Persistence query language cannot be used). Native SQL queries are not expected to be portable across databases. |
3.11.17.1. Returning Managed Entities from Native Queries
The persistence provider is responsible for performing the mapping between the values returned by the SQL query and entity attributes in accordance with the object/relational mapping metadata for the entity or entities. In particular, the names of the columns in the SQL result are used to map to the entity attributes as defined by this metadata. This mapping includes the mapping of the attributes of any embeddable classes that are part of the non-collection-valued entity state and attributes corresponding to foreign keys contained as part of the entity state[60].
When an entity is to be returned from a native query, the SQL statement should select all of the columns that are mapped to the entity object. This should include foreign key columns to related entities. The results obtained when insufficient data is available are undefined.
In the simplest case—i.e., when the results of the query are limited to entities of a single entity class and the mapping information can be derived from the columns of the SQL result and the object/relational mapping metadata—it is sufficient to specify only the expected class of the entity result.
The following example illustrates the case
where a native SQL query is created dynamically using the
createNativeQuery
method and the entity class that specifies the type
of the result is passed in as an argument.
Query q = em.createNativeQuery(
"SELECT o.id, o.quantity, o.item " +
"FROM Order o, Item i " +
"WHERE (o.item = i.id) AND (i.name = 'widget')",
com.acme.Order.class);
When executed, this query will return a
collection of all Order
entities for items named “widget”.
The SqlResultSetMapping
metadata
annotation—which is designed to handle more complex cases—can be used as
an alternative here. See Section 10.4.4 for the definition of the
SqlResultSetMapping
metadata annotation and related annotations.
For the query shown above, the
SqlResultSetMapping
metadata for the query result type might be
specified as follows:
@SqlResultSetMapping(
name="WidgetOrderResults",
entities=@EntityResult(entityClass=com.acme.Order.class))
The same results as produced by the query above can then obtained by the following:
Query q = em.createNativeQuery(
"SELECT o.id, o.quantity, o.item " +
"FROM Order o, Item i " +
"WHERE (o.item = i.id) AND (i.name = 'widget')",
"WidgetOrderResults");
When multiple entities are returned by a SQL
query or when the column names of the SQL result do not correspond to
those of the object/relational mapping metadata, a SqlResultSetMapping
metadata definition must be provided to specify the entity mapping.
The following query and SqlResultSetMapping
metadata illustrates the return of multiple entity types. It assumes
default metadata and column name defaults.
Query q = em.createNativeQuery(
"SELECT o.id, o.quantity, o.item, i.id, i.name, i.description " +
"FROM Order o, Item i " +
"WHERE (o.quantity > 25) AND (o.item = i.id)",
"OrderItemResults");
@SqlResultSetMapping(name="OrderItemResults", entities={
@EntityResult(entityClass=com.acme.Order.class),
@EntityResult(entityClass=com.acme.Item.class)
})
When the column names of the SQL result do
not correspond to those of the object/relational mapping metadata
or introduce a conflict in mapping column defaults as in the example code above,
more explicit SQL result mapping metadata must be provided to enable the
persistence provider runtime to map the JDBC results into the expected
objects. This might arise, for example, when column aliases must be used
in the SQL SELECT clause when the SQL result would otherwise contain
multiple columns of the same name or when columns in the SQL result are
the results of operators or functions. The FieldResult
annotation
element within the EntityResult
annotation is used to specify the
mapping of such columns to entity attributes.
The following example combining multiple
entity types includes aliases in the SQL statement. This requires that
the column names be explicitly mapped to the entity fields corresponding
to those columns. The FieldResult
annotation is used for this purpose.
Query q = em.createNativeQuery(
"SELECT o.id AS order_id, " +
"o.quantity AS order_quantity, " +
"o.item AS order_item, " +
"i.id, i.name, i.description " +
"FROM Order o, Item i " +
"WHERE (order_quantity > 25) AND (order_item = i.id)",
"OrderItemResults");
@SqlResultSetMapping(name="OrderItemResults", entities={
@EntityResult(entityClass=com.acme.Order.class, fields={
@FieldResult(name="id", column="order_id"),
@FieldResult(name="quantity", column="order_quantity"),
@FieldResult(name="item", column="order_item")}),
@EntityResult(entityClass=com.acme.Item.class)
})
When the returned entity type contains an
embeddable class, the FieldResult
element must use a dot (“ .
”)
notation to indicate which column maps to which field or property of the
contained embeddable.
Example:
Query q = em.createNativeQuery(
"SELECT c.id AS customer_id, " +
"c.street AS customer_street, " +
"c.city AS customer_city, " +
"c.state AS customer_state, " +
"c.status AS customer_status " +
"FROM Customer c " +
"WHERE c.status = 'GOLD' ",
"CustomerResults");
@SqlResultSetMapping(name=”CustomerResults”, entities={
@EntityResult(entityClass=com.acme.Customer.class, fields={
@FieldResult(name="id", column="customer_id"),
@FieldResult(name="address.street", column="customer_street"),
@FieldResult(name="address.city", column="customer_city"),
@FieldResult(name="address.state", column="customer_state"),
@FieldResult(name="status", column="customer_status")
})
})
When the returned entity type is the owner of
a single-valued relationship and the foreign key is a composite foreign
key (composed of multiple columns), a FieldResult
element should be
used for each of the foreign key columns. The FieldResult
element must
use the dot (“ .
”) notation form to indicate the column that maps to
each property or field of the target entity primary key.
If the target entity has a primary key of
type IdClass
, this specification takes the form of the name of the
field or property for the relationship, followed by a dot (“ .
”),
followed by the name of the field or property of the primary key in the
target entity. The latter will be annotated with Id
, as specified in
Section 11.1.23.
Example:
Query q = em.createNativeQuery(
"SELECT o.id AS order_id, " +
"o.quantity AS order_quantity, " +
"o.item_id AS order_item_id, " +
"o.item_name AS order_item_name, " +
"i.id, i.name, i.description " +
"FROM Order o, Item i " +
"WHERE (order_quantity > 25) AND (order_item_id = i.id) " +
"AND (order_item_name = i.name)",
"OrderItemResults");
@SqlResultSetMapping(name="OrderItemResults", entities={
@EntityResult(entityClass=com.acme.Order.class, fields={
@FieldResult(name="id", column="order_id"),
@FieldResult(name="quantity", column="order_quantity"),
@FieldResult(name="item.id", column="order_item_id")}),
@FieldResult(name="item.name", column="order_item_name")}),
@EntityResult(entityClass=com.acme.Item.class)
})
If the target entity has a primary key of
type EmbeddedId
, this specification is composed of the name of the
field or property for the relationship, followed by a dot (“ .
”),
followed by the name or the field or property of the primary key (i.e.,
the name of the field or property annotated as EmbeddedId
), followed
by the name of the corresponding field or property of the embedded
primary key class.
Example:
Query q = em.createNativeQuery(
"SELECT o.id AS order_id, " +
"o.quantity AS order_quantity, " +
"o.item_id AS order_item_id, " +
"o.item_name AS order_item_name, " +
"i.id, i.name, i.description " +
"FROM Order o, Item i " +
"WHERE (order_quantity > 25) AND (order_item_id = i.id) AND (order_item_name = i.name)",
"OrderItemResults");
@SqlResultSetMapping(name="OrderItemResults", entities={
@EntityResult(entityClass=com.acme.Order.class, fields={
@FieldResult(name="id", column="order_id"),
@FieldResult(name="quantity", column="order_quantity"),
@FieldResult(name="item.itemPk.id", column="order_item_id")}),
@FieldResult(name="item.itemPk.name", column="order_item_name")}),
@EntityResult(entityClass=com.acme.Item.class)
})
The FieldResult
elements for the composite
foreign key are combined to form the primary key EmbeddedId
class for
the target entity. This may then be used to subsequently retrieve the
entity if the relationship is to be eagerly loaded.
The dot-notation form is not required to be supported for any usage other than for embeddables, composite foreign keys, or composite primary keys.
3.11.17.2. Returning Unmanaged Instances
Instances of other classes (including non-managed entity instances) as well as scalar results can be returned by a native query. These can be used singly, or in combination, including with entity results.
Scalar Results
Scalar results can be included in the query
result by specifying the ColumnResult
annotation element of the
SqlResultSetMapping
annotation. The intended type of the result can be
specified using the type
element of the ColumnResult
annotation.
Query q = em.createNativeQuery(
"SELECT o.id AS order_id, " +
"o.quantity AS order_quantity, " +
"o.item AS order_item, " +
"i.name AS item_name, " +
"i.availabilityDate AS item_shipdate " +
"FROM Order o, Item i " +
"WHERE (order_quantity > 25) AND (order_item = i.id)",
"OrderResults");
@SqlResultSetMapping(
name="OrderResults",
entities={
@EntityResult(entityClass=com.acme.Order.class, fields={
@FieldResult(name="id", column="order_id"),
@FieldResult(name="quantity", column="order_quantity"),
@FieldResult(name="item", column="order_item")}
)},
columns={
@ColumnResult(name="item_name"),
@ColumnResult(name="item_shipdate", type=java.util.Date.class)
})
Constructor Results
The mapping to constructors is specified
using the ConstructorResult
annotation element of the
SqlResultSetMapping
annotation. The targetClass
element of the
ConstructorResult
annotation specifies the class whose constructor
corresponds to the specified columns. All columns corresponding to
arguments of the intended constructor must be specified using the
columns
element of the ConstructorResult
annotation in the same
order as that of the argument list of the constructor. Any entities
returned as constructor results will be in either the new or the
detached state, depending on whether a primary key is retrieved for the
constructed object.
Example:
Query q = em.createNativeQuery(
"SELECT c.id, c.name, COUNT(o) as orderCount, AVG(o.price) AS avgOrder " +
"FROM Customer c, Orders o " +
"WHERE o.cid = c.id " +
"GROUP BY c.id, c.name",
"CustomerDetailsResult");
@SqlResultSetMapping(name="CustomerDetailsResult", classes={
@ConstructorResult(targetClass=com.acme.CustomerDetails.class, columns={
@ColumnResult(name="id"),
@ColumnResult(name="name"),
@ColumnResult(name="orderCount"),
@ColumnResult(name="avgOrder", type=Double.class)})
})
3.11.17.3. Combinations of Result Types
When a SqlResultSetMapping
specifies more
than one mapping type (i.e., more than one of EntityResult
,
ConstructorResult
, ColumnResult
), then for each row in the SQL
result, the query execution will result in an Object[]
instance whose
elements are as follows, in order: any entity results (in the order in
which they are defined in the entities
element); any instances of
classes corresponding to constructor results (in the order defined in
the classes
element); and any instances corresponding to column
results (in the order defined in the columns
element). If there are
any columns whose result mappings have not been specified, they are
ignored.
3.11.17.4. Restrictions
When an entity is being returned, the SQL statement should select all of the columns that are mapped to the entity object. This should include foreign key columns to related entities. The results obtained when insufficient data is available are undefined. A SQL result set mapping must not be used to map results to the non-persistent state of an entity.
The use of named parameters is not defined for native SQL queries. Only positional parameter binding for SQL queries may be used by portable applications.
3.11.18. Stored Procedures
The StoredProcedureQuery
interface supports
the use of database stored procedures.
Stored procedures can be specified either by
means of the NamedStoredProcedureQuery
annotation or dynamically.
Annotations for the specification of stored procedures are described in
Section 10.4.3.
3.11.18.1. Named Stored Procedure Queries
Unlike in the case of a named native query,
the NamedStoredProcedureQuery
annotation names a stored procedure that
exists in the database rather than providing a stored procedure
definition. The NamedStoredProcedureQuery
annotation specifies the
types of all parameters to the stored procedure, their corresponding
parameter modes (IN, OUT, INOUT, REF_CURSOR[61]), and
how result sets, if any, are to be mapped. The name that is assigned to
the stored procedure in the NamedStoredProcedureQuery
annotation is
passed as an argument to the createNamedStoredProcedureQuery
method to
create an executable StoredProcedureQuery
object.
A stored procedure may return more than one
result set. As with native queries, the mapping of result sets can be
specified either in terms of a resultClasses
or as a
resultSetMappings
annotation element. If there are multiple result
sets, it is assumed that they will be mapped using the same mechanism —
e.g., all via a set of result class mappings or all via a set of result
set mappings. The order of the specification of these mappings must be
the same as the order in which the result sets will be returned by the
stored procedure invocation. If the stored procedure returns one or more
result sets and no resultClasses
or resultSetMappings
element has
been specified, any result set will be returned as a list of type
Object[]
. The combining of different strategies for the mapping of
stored procedure result sets is undefined.
StoredProcedureParameter
metadata needs to
be provided for all parameters. Parameters must be specified in the
order in which they occur in the parameter list of the stored procedure.
If parameter names are used, the parameter name is used to bind the
parameter value and to extract the output value (if the parameter is an
INOUT or OUT parameter). If parameter names are not specified, it is
assumed that positional parameters are used. The mixing of named and
positional parameters is invalid.
3.11.18.2. Dynamically-specified Stored Procedure Queries
If the stored procedure is not defined using metadata, parameter and result set information must be provided dynamically.
All parameters of a dynamically-specified
stored procedure query must be registered using the
registerStoredProcedureParameter
method of the StoredProcedureQuery
interface.
Result set mapping information can be
provided by means of the createStoredProcedureQuery
method.
3.11.18.3. Stored Procedure Query Execution
Stored procedure query execution can be controlled as described below.
The setParameter
methods are used to set
the values of all required IN and INOUT parameters. It is not required
to set the values of stored procedure parameters for which default
values have been defined by the stored procedure.
When getResultList
, getSingleResult
, and getSingleResultOrNull
are called on a StoredProcedureQuery
object, the persistence provider
will call execute
on an unexecuted stored procedure query before
processing getResultList
, getSingleResult
or getSingleResultOrNull
.
When executeUpdate
is called on a
StoredProcedureQuery
object, the persistence provider will call
execute
on an unexecuted stored procedure query followed by
getUpdateCount
. The results of executeUpdate
will be those of
getUpdateCount
.
The execute
method supports both the simple
case where scalar results are passed back only via INOUT and OUT
parameters as well as the most general case (multiple result sets and/or
update counts, possibly also in combination with output parameter
values).
The execute
method returns true
if the
first result is a result set, and false
if it is an update count or
there are no results other than through INOUT and OUT parameters, if
any.
If the execute
method returns true
, the pending result set can be
obtained by calling getResultList
, getSingleResult
, or
getSingleResultOrNull
. The hasMoreResults
method can then be used to
test for further results.
If execute
or hasMoreResults
returns
false
, the getUpdateCount
method can be called to obtain the
pending result if it is an update count. The getUpdateCount
method
will return either the update count (zero or greater) or -1 if there is
no update count (i.e., either the next result is a result set or there
is no next update count).
For portability, results that correspond to JDBC result sets and update counts need to be processed before the values of any INOUT or OUT parameters are extracted.
After results returned through
getResultList
and getUpdateCount
have been exhausted, results
returned through INOUT and OUT parameters can be retrieved.
The getOutputParameterValue
methods are
used to retrieve the values passed back from the procedure through INOUT
and OUT parameters.
When using REF_CURSOR
parameters for result
sets, the update counts should be exhausted before calling
getResultList
to retrieve the result set. Alternatively, the
REF_CURSOR
result set can be retrieved through
getOutputParameterValue
. Result set mappings will be applied to
results corresponding to REF_CURSOR
parameters in the order the
REF_CURSOR
parameters were registered with the query.
In the simplest case, where results are
returned only via INOUT and OUT parameters, execute
can be followed
immediately by calls to getOutputParameterValue
.
3.12. Summary of Exceptions
The following is a summary of the exceptions defined by this specification:
PersistenceException
The PersistenceException
is thrown by the
persistence provider when a problem occurs. It may be thrown to report
that the invoked operation could not complete because of an unexpected
error (e.g., failure of the persistence provider to open a database
connection).
All other exceptions defined by this
specification are subclasses of the PersistenceException
. All
instances of PersistenceException
except for instances of
NoResultException
, NonUniqueResultException
, LockTimeoutException
, and QueryTimeoutException
will cause the current transaction, if one
is active and the persistence context has been joined to it, to be
marked for rollback.
TransactionRequiredException
The TransactionRequiredException
is thrown
by the persistence provider when a transaction is required but is not
active.
OptimisticLockException
The OptimisticLockException
is thrown by
the persistence provider when an optimistic locking conflict occurs.
This exception may be thrown as part of an API call, at flush, or at
commit time. The current transaction, if one is active, will be marked
for rollback.
PessimisticLockException
The PessimisticLockException
is thrown by
the persistence provider when a pessimistic locking conflict occurs. The
current transaction will be marked for rollback. Typically the
PessimisticLockException
occurs because the database transaction has
been rolled back due to deadlock or because the database uses
transaction-level rollback when a pessimistic lock cannot be granted.
LockTimeoutException
The LockTimeoutException
is thrown by the
persistence provider when a pessimistic locking conflict occurs that
does not result in transaction rollback. Typically this occurs because
the database uses statement-level rollback when a pessimistic lock
cannot be granted (and there is no deadlock). The LockTimeoutException
does not cause the current transaction to be marked for rollback.
RollbackException
The RollbackException
is thrown by the
persistence provider when EntityTransaction.commit
fails.
EntityExistsException
The EntityExistsException
may thrown by the
persistence provider when the persist
operation is invoked and the
entity already exists. The EntityExistsException
may be thrown when
the persist operation is invoked, or the EntityExistsException
or
another PersistenceException
may be thrown at commit time. The current
transaction, if one is active and the persistence context has been
joined to it, will be marked for rollback.
EntityNotFoundException
The EntityNotFoundException
is thrown by
the persistence provider when an entity reference obtained by
getReference
is accessed but the entity does not exist. It is thrown
by the refresh
operation when the entity no longer exists in the
database. It is also thrown by the lock
operation when pessimistic
locking is used and the entity no longer exists in the database. The
current transaction, if one is active and the persistence context has
been joined to it, will be marked for rollback.
NoResultException
The NoResultException
is thrown by the persistence provider when
Query.getSingleResult
is invoked and there is no result to return.
This exception will not cause the current transaction, if one is
active, to be marked for rollback.
NonUniqueResultException
The NonUniqueResultException
is thrown by the persistence provider
when Query.getSingleResult
or Query.getSingleResultOrNull
is
invoked and there is more than one result from the query. This
exception will not cause the current transaction, if one is active,
to be marked for rollback.
QueryTimeoutException
The QueryTimeoutException
is thrown by the
persistence provider when a query times out and only the statement is
rolled back. The QueryTimeoutException
does not cause the current
transaction, if one is active, to be marked for rollback.
4. Query Language
The Jakarta Persistence query language is a string-based query language used to define queries over entities and their persistent state. It enables the application developer to specify the semantics of queries in a portable way, independent of the particular database schema in use in an enterprise environment. The full range of the language may be used in both static and dynamic queries.
This chapter provides the full definition of the Jakarta Persistence query language.
4.1. Overview
The Jakarta Persistence query language is a query specification language for string-based dynamic queries and static queries expressed through metadata. It is used to define queries over the persistent entities defined by this specification and their persistent state and relationships.
The Jakarta Persistence query language can be compiled to a target language, such as SQL, of a database or other persistent store. This allows the execution of queries to be shifted to the native language facilities provided by the database, instead of requiring queries to be executed on the runtime representation of the entity state. As a result, query methods can be optimizable as well as portable.
The query language uses the abstract persistence schema of entities, including their embedded objects and relationships, for its data model, and it defines operators and expressions based on this data model. It uses a SQL-like syntax to select objects or values based on abstract schema types and relationships. It is possible to parse and validate queries before entities are deployed.
The term abstract persistence schema refers to the persistent schema abstraction (persistent entities, their state, and their relationships) over which Jakarta Persistence queries operate. Queries over this persistent schema abstraction are translated into queries that are executed over the database schema to which entities are mapped. |
Queries may be defined in metadata annotations or the XML descriptor. The abstract schema types of a set of entities can be used in a query if the entities are defined in the same persistence unit as the query. Path expressions allow for navigation over relationships defined in the persistence unit.
A persistence unit defines the set of all classes that are related or grouped by the application and which must be colocated in their mapping to a single database. |
4.2. Statement Types
A Jakarta Persistence query language statement may be either a select statement, an update statement, or a delete statement.
This chapter refers to all such statements as “queries”. Where it is important to distinguish among statement types, the specific statement type is referenced. |
In BNF syntax, a query language statement is defined as:
QL_statement ::= select_statement | update_statement | delete_statement
Any Jakarta Persistence query language statement may be constructed dynamically or may be statically defined in a metadata annotation or XML descriptor element.
All statement types may have parameters.
4.2.1. Select Statements
A select query is a string with the following clauses:
-
a SELECT clause, which determines the type of the objects or values to be selected.
-
a FROM clause, which provides declarations that designate the domain to which the expressions specified in the other clauses of the query apply.
-
an optional WHERE clause, which may be used to restrict the results that are returned by the query.
-
an optional GROUP BY clause, which allows query results to be aggregated in terms of groups.
-
an optional HAVING clause, which allows filtering over aggregated groups.
-
an optional ORDER BY clause, which may be used to order the results that are returned by the query.
In BNF syntax, a select query is defined by:
select_query ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]
A select statement must always have a SELECT and a FROM clause. The square brackets [] indicate that the other clauses are optional.
4.2.1.1. Set Operators in Select Statements
A select statement may be a single select query, or it may combine
multiple select queries using the binary left-associative operators
UNION
, UNION ALL
, INTERSECT
, INTERSECT ALL
, EXCEPT
, and
EXCEPT ALL
. The semantics of these operators are identical to SQL.
[62]
The full syntax for a select statement is defined by:
select_statement ::= union union ::= intersection | union {UNION [ALL] | EXCEPT [ALL]} intersection intersection ::= query_expression | intersection INTERSECT [ALL] query_expression query_expression ::= select_query | (union)
A provider is only required to support select statements where every constituent select query has the same number of items in the select clause, and where corresponding items in the select clauses of the constituent select queries either:
-
have exactly the same type, as defined by Section 4.9.1, or
-
are entity types which inherit a common entity type, as defined by Section 2.13.
4.2.2. Update and Delete Statements
Update and delete statements provide bulk operations over sets of entities.
In BNF syntax, these operations are defined by:
update_statement ::= update_clause [where_clause] delete_statement ::= delete_clause [where_clause]
The update and delete clauses determine the type of the entities to be updated or deleted. The WHERE clause may be used to restrict the scope of the update or delete operation.
Update and delete statements are described further in Section 4.11.
4.3. Abstract Schema Types and Query Domains
The Jakarta Persistence query language is a typed language, and every expression has a type. The type of an expression is derived from the structure of the expression, the abstract schema types of the identification variable declarations, the types to which the persistent attributes evaluate, and the types of literals.
The abstract schema type of an entity or embeddable is derived from its class and the metadata information provided by Java language annotations or in the XML descriptor.
Informally, the abstract schema type of an entity or embeddable can be characterized as follows:
-
For every non-relationship persistent field or get accessor method (for a persistent property) of the class, there is a field (“state field”) whose abstract schema type corresponds to that of the field or the result type of the accessor method.
-
For every persistent relationship field or get accessor method (for a persistent relationship property) of the class, there is a field (“association field”) whose type is the abstract schema type of the related entity (or, if the relationship is a one-to-many or many-to-many, a collection of such).
Abstract schema types are specific to the query language data model. The persistence provider is not required to implement or otherwise materialize an abstract schema type.
The domain of a query consists of the abstract schema types of all entities and embeddables that are defined in the same persistence unit.
The domain of a query may be restricted by
the navigability
of the relationships of the entity and associated
embeddable classes on which it is based. The association fields of an
entity’s or embeddable’s abstract schema type determine navigability.
Using the association fields and their values, a query can select
related entities and use their abstract schema types in the query.
4.3.1. Naming
Entities are designated in query strings by
their entity names. The entity name is defined by the name
element of
the Entity
annotation (or the entity-name
XML descriptor element),
and defaults to the unqualified name of the entity class. Entity names
are scoped within the persistence unit and must be unique within the
persistence unit.
4.3.2. Example
This example assumes that the application
developer provides several entity classes, representing orders,
products, and line items, and an embeddable address class representing
shipping addresses and billing addresses. The abstract schema types for
the entities are Order
, Product
, and LineItem
respectively.
There is a one-to-many relationship between Order
and LineItem
. The
entity LineItem
is related to Product
in a many-to-one relationship.
The classes are logically in the same persistence unit, as shown in
Figure 1.
Queries to select orders can be defined by
navigating over the association fields and state fields defined by
Order
and LineItem
. A query to find all orders with pending line
items might be written as follows:
SELECT DISTINCT o
FROM Order AS o JOIN o.lineItems AS l
WHERE l.shipped = FALSE
This query navigates over the association
field lineItems
of the abstract schema type Order
to find line
items, and uses the state field shipped
of LineItem
to select those
orders that have at least one line item that has not yet shipped. (Note
that this query does not select orders that have no line items.)
Although reserved identifiers, such as DISTINCT, FROM, AS, JOIN, WHERE, and FALSE appear in upper case in this example, reserved identifiers are case insensitive.[63]
The SELECT clause of this example designates the return type of this query to be of type Order.
Because the same persistence unit defines the
abstract persistence schema of the related entities, the developer can
also specify a query over orders that utilizes the abstract schema type
for products, and hence the state fields and association fields of both
the abstract schema types Order
and Product
. For example, if the
abstract schema type Product
has a state field named productType
, a
query over orders can be specified using this state field. Such a query
might be to find all orders for products with product type office
supplies. A query for this might be as follows.
SELECT DISTINCT o
FROM Order o JOIN o.lineItems l JOIN l.product p
WHERE p.productType = 'office_supplies'
Because Order
is related to Product
by
means of the relationships between Order
and LineItem
and between
LineItem
and Product
, navigation using the association fields
lineItems
and product
is used to express the query. This query is
specified by using the entity name Order
, which designates the
abstract schema type over which the query ranges. The basis for the
navigation is provided by the association fields lineItems
and
product
of the abstract schema types Order and LineItem respectively.
4.4. The FROM Clause and Navigational Declarations
The FROM clause of a query defines the domain of the query by declaring identification variables. An identification variable is an identifier declared in the FROM clause of a query. The domain of the query may be constrained by path expressions. (See Section 4.4.4.)
Identification variables designate instances
of a particular abstract schema type. The FROM clause can contain
multiple identification variable declarations separated by a comma (,
).
from_clause ::= FROM identification_variable_declaration {, {identification_variable_declaration | collection_member_declaration}}* identification_variable_declaration ::= range_variable_declaration {join | fetch_join}* range_variable_declaration ::= entity_name [AS] identification_variable join ::= range_join | path_join range_join ::= join_spec range_variable_declaration [join_condition] path_join ::= join_spec join_association_path_expression [AS] identification_variable [join_condition] fetch_join ::= join_spec FETCH join_association_path_expression join_spec ::= [INNER | LEFT [OUTER]] JOIN join_association_path_expression ::= join_collection_valued_path_expression | join_single_valued_path_expression | TREAT(join_collection_valued_path_expression AS subtype) | TREAT(join_single_valued_path_expression AS subtype) join_collection_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}*collection_valued_field join_single_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}*single_valued_object_field join_condition ::= ON conditional_expression collection_member_declaration ::= IN (collection_valued_path_expression) [AS] identification_variable
The following subsections discuss the constructs used in the FROM clause.
4.4.1. Identifiers
An identifier is a character sequence of
unlimited length. The character sequence must begin with a Java
identifier start character, and all other characters must be Java
identifier part characters. An identifier start character is any
character for which the method Character.isJavaIdentifierStart
returns
true. This includes the underscore (_
) character and the dollar sign
($
) character. An identifier part character is any character for
which the method Character.isJavaIdentifierPart
returns true. The
question mark (?
) character is reserved for use by the Jakarta
Persistence query language.
The following[64] are reserved identifiers: ABS, ALL, AND, ANY, AS, ASC, AVG, BETWEEN, BIT_LENGTH, BOTH, BY, CASE, CEILING, CHAR_LENGTH, CHARACTER_LENGTH, CLASS, COALESCE, CONCAT, COUNT, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DELETE, DESC, DISTINCT, ELSE, EMPTY, END, ENTRY, ESCAPE, EXISTS, EXP, EXTRACT, FALSE, FETCH, FIRST, FLOOR, FROM, FUNCTION, GROUP, HAVING, IN, INDEX, INNER, IS, JOIN, KEY, LEADING, LAST, LEFT, LENGTH, LIKE, LOCAL, LN, LOCATE, LOWER, MAX, MEMBER, MIN, MOD, NEW, NOT, NULL, NULLS, NULLIF, OBJECT, OF, ON, OR, ORDER, OUTER, POSITION, POWER, REPLACE, RIGHT, ROUND, SELECT, SET, SIGN, SIZE, SOME, SQRT, SUBSTRING, SUM, THEN, TRAILING, TREAT, TRIM, TRUE, TYPE, UNKNOWN, UPDATE, UPPER, VALUE, WHEN, WHERE.
Reserved identifiers are case-insensitive. Reserved identifiers must not be used as identification variables or result variables (see Section 4.9).
It is recommended that SQL key words other than those listed above not be used as identification variables in queries because they may be used as reserved identifiers in future releases of this specification. |
4.4.2. Identification Variables
An identification variable is a valid identifier declared in the FROM clause of a query.
All identification variables must be declared in the FROM clause. Identification variables cannot be declared in other clauses.
An identification variable must not be a reserved identifier.
An identification variable may have the same name as an entity.
Identification variables are case-insensitive.
An identification variable evaluates to a value of the type of the expression used in declaring the variable. For example, consider the previous query:
SELECT DISTINCT o
FROM Order o JOIN o.lineItems l JOIN l.product p
WHERE p.productType = 'office_supplies'
In the FROM clause declaration o.lineItems
l
, the identification variable l
evaluates to any LineItem value
directly reachable from Order. The association field lineItems
is a
collection of instances of the abstract schema type LineItem and the
identification variable l
refers to an element of this collection. The
type of l
is the abstract schema type of LineItem
.
An identification variable can range over an entity, embeddable, or basic abstract schema type. An identification variable designates an instance of an abstract schema type or an element of a collection of abstract schema type instances.
Note that for identification variables
referring to an instance of an association or collection represented as
a java.util.Map
, the identification variable is of the abstract
schema type of the map value
.
An identification variable always designates a reference to a single value. It is declared in one of three ways: in a range variable declaration, in a join clause, or in a collection member declaration. The identification variable declarations are evaluated from left to right in the FROM clause, and an identification variable declaration can use the result of a preceding identification variable declaration of the query string.
All identification variables used in the SELECT, WHERE, ORDER BY, GROUP BY, or HAVING clause of a SELECT or DELETE statement must be declared in the FROM clause. The identification variables used in the WHERE clause of an UPDATE statement must be declared in the UPDATE clause.
Identification variables are existentially quantified in these clauses. This means that an identification variable represents a member of a collection or an instance of an entity’s abstract schema type. An identification variable never designates a collection in its entirety.
An identification variable is scoped to the query (or subquery) in which it is defined and is also visible to any subqueries within that query scope that do not define an identification variable of the same name.
4.4.3. Range Variable Declarations
The syntax for declaring an identification variable as a range variable is similar to that of SQL; optionally, it uses the AS keyword. A range variable designates an entity abstract schema type.[65]
range_variable_declaration ::= entity_name [AS] identification_variable
Range variable declarations allow the developer to designate a “root” for objects which may not be reachable by navigation.
In order to select values by comparing more than one instance of an entity abstract schema type, more than one identification variable ranging over the abstract schema type is needed in the FROM clause.
The following query returns orders whose quantity is greater than the order quantity for John Smith. This example illustrates the use of two different identification variables in the FROM clause, both of the abstract schema type Order. The SELECT clause of this query determines that it is the orders with quantities larger than John Smith’s that are returned.
SELECT DISTINCT o1
FROM Order o1, Order o2
WHERE o1.quantity > o2.quantity AND
o2.customer.lastname = 'Smith' AND
o2.customer.firstname= 'John'
The entity name in a range variable declaration is case-sensitive.
4.4.4. Path Expressions
An identification variable followed by the
navigation operator (.
) and a state field or association field is a
path expression. The type of the path expression is the type computed as
the result of navigation; that is, the type of the state field or
association field to which the expression navigates. The type of a path
expression that navigates to an association field may be specified as a
subtype of the declared type of the association field by means of the
TREAT operator. See Section 4.4.9.
A reference to a state field or association field in a path expression is case-sensitive.
An identification variable qualified by the KEY, VALUE, or ENTRY operator is a path expression. The KEY, VALUE, and ENTRY operators may only be applied to identification variables that correspond to map-valued associations or map-valued element collections. The type of the path expression is the type computed as the result of the operation; that is, the abstract schema type of the field that is the value of the KEY, VALUE, or ENTRY operator (the map key, map value, or map entry respectively).[66]
In the following query, photos is a map from photo label to filename.
SELECT i.name, VALUE(p)
FROM Item i JOIN i.photos p
WHERE KEY(p) LIKE '%egret'
In the above query the identification
variable p
designates an abstract schema type corresponding to the map
value
. The results of VALUE(p)
and KEY(p)
are the map value and
the map key associated with p
, respectively. The following query is
equivalent:
SELECT i.name, p
FROM Item i JOIN i.photos p
WHERE KEY(p) LIKE '%egret'
A path expression using the KEY or VALUE operator can be further composed. A path expression using the ENTRY operator is terminal. It cannot be further composed and can only appear in the SELECT list of a query.
The syntax for qualified identification variables is as follows.
qualified_identification_variable ::= map_field_identification_variable | ENTRY(identification_variable) map_field_identification_variable ::= KEY(identification_variable) | VALUE(identification_variable)
Depending on navigability, a path expression that leads to an association field or to a field whose type is an embeddable class may be further composed. Path expressions can be composed from other path expressions if the original path expression evaluates to a single-valued type (not a collection).
In the following example, simple data model with Employee
, ContactInfo
,
Address
and Phone
classes is used:
@Entity
public class Employee {
@Id int id;
@Embedded
private ContactInfo contactInfo;
}
@Entity
public class Phone {
@Id
private int id;
private String vendor;
}
@Embeddable
public class ContactInfo {
@Embedded
private Address address;
@ManyToMany
private List<Phone> phones;
}
@Embeddable
public class Address {
private String street;
private String city;
private String state;
private String zipcode;
}
The contactInfo
field denotes an embeddable class consisting of an address and set of phones.
SELECT p.vendor
FROM Employee e JOIN e.contactInfo.phones p
WHERE e.contactInfo.address.zipcode = '95054'
Path expression navigability is composed using “inner join” semantics. That is, if the value of a non-terminal field in the path expression is null, the path is considered to have no value, and does not participate in the determination of the result.
The following query is equivalent to the query above:
SELECT p.vendor
FROM Employee e JOIN e.contactInfo c JOIN c.phones p
WHERE e.contactInfo.address.zipcode = '95054'
4.4.4.1. Path Expression Syntax
The syntax for single-valued path expressions and collection-valued path expressions is as follows.
An identification variable used in a
single_valued_object_path_expression
or in a
collection_valued_path_expression
may be an unqualified identification
variable or an identification variable to which the KEY or VALUE
function has been applied.
general_identification_variable ::= identification_variable | map_field_identification_variable
The type of an entity-valued path expression or an entity-valued subpath of a path expression used in a WHERE clause may be specified as a subtype of the corresponding declared type by means of the TREAT operator. See Section 4.4.9.
general_subpath ::= simple_subpath | treated_subpath{.single_valued_object_field}* simple_subpath ::= general_identification_variable | general_identification_variable{.single_valued_object_field}* treated_subpath ::= TREAT(general_subpath AS subtype) single_valued_path_expression ::= qualified_identification_variable | TREAT(qualified_identification_variable AS subtype) | state_field_path_expression | single_valued_object_path_expression state_field_path_expression ::= general_subpath.state_field state_valued_path_expression ::= state_field_path_expression | general_identification_variable single_valued_object_path_expression ::= general_subpath.single_valued_object_field collection_valued_path_expression ::= general_subpath.collection_valued_field
A single_valued_object_field
is designated by the name of an association
field in a one-to-one or many-to-one relationship or a field of
embeddable class type. The type of a single_valued_object_field
is the abstract schema type of the related
entity or embeddable class.
A single_valued_embeddable_object_field
is designated by the name
of a field of embeddable class type.
A _state field
is designated by the name of
an entity or embeddable class state field that corresponds to a basic
type.
A collection_valued_field
is designated by the name of an association
field in a one-to-many or a many-to-many relationship or by the name of
an element collection field. The type of a collection_valued_field
is
a collection of values of the abstract schema type of the related entity
or element type.
It is syntactically illegal to compose a path
expression from a path expression that evaluates to a collection. For
example, if o designates Order, the path expression o.lineItems.product
is illegal since navigation to lineItems
results in a collection. This
case should produce an error when the query string is verified. To
handle such a navigation, an identification variable must be declared in
the FROM clause to range over the elements of the lineItems
collection. Another path expression must be used to navigate over each
such element in the WHERE clause of the query, as in the following:
SELECT DISTINCT l.product
FROM Order AS o JOIN o.lineItems l
A collection_valued_path_expression
may only occur in:
-
the FROM clause of a query,
-
an
empty_collection_comparison_expression
, -
a
collection_member_expression
, or -
as an argument to the SIZE operator.
See Section 4.6.12, Section 4.6.13, and Section 4.7.3.2.
4.4.5. Joins
JPQL defines the following varieties of join:
-
inner joins, and.
-
left outer joins.[67]
The semantics of each variety of join is identical to SQL, and the syntax is borrowed from ANSI SQL.
Every join has a target, either:
-
an entity-valued path expression, or
-
an entity type (that is, range variable declaration, as already specified in Section 4.4.3).
An inner join may be implicitly specified by the use of a cartesian product in the FROM clause and a join condition in the WHERE clause. In the absence of a join condition, this reduces to the cartesian product.
The main use case for this generalized style of join is when a join condition does not involve a foreign key relationship mapped to an association between entities.
Example:
SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
This style of inner join (sometimes called a "theta" join) is less typical than explicitly defined joins over relationships.
The syntax for explicit join operations is given by:
join ::= range_join | path_join range_join ::= join_spec range_variable_declaration [join_condition] path_join ::= join_spec join_association_path_expression [AS] identification_variable [join_condition] fetch_join ::= join_spec FETCH join_association_path_expression join_spec ::= [INNER | LEFT [OUTER]] JOIN join_association_path_expression ::= join_collection_valued_path_expression | join_single_valued_path_expression | TREAT(join_collection_valued_path_expression `AS` subtype) | TREAT(join_single_valued_path_expression AS subtype) join_collection_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}*collection_valued_field join_single_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}*single_valued_object_field join_condition ::= ON conditional_expression
The inner and outer join operation types described in Section 4.4.5.1, Section 4.4.5.2, and Section 4.4.5.3 are supported.
4.4.5.1. Inner Joins
The syntax for an inner join to an entity type is given by:
[INNER] JOIN range_variable_declaration [join_condition]
The keyword INNER is optional and does not affect the semantics of the query.
SELECT c
FROM Customer c
JOIN Order o ON o.customer.id = c.id
WHERE c.status = 1
Or, equivalently:
SELECT c
FROM Customer c
INNER JOIN Order o ON o.customer.id = c.id
WHERE c.status = 1
These queries are equivalent to the following query involving an implicit "theta" join:
SELECT c
FROM Customer c, Order o
WHERE o.customer.id = c.id AND c.status = 1
The syntax for an inner join over an association is given by:
[INNER] JOIN join_association_path_expression [AS] identification_variable [join_condition]
For example, the query below joins over the relationship between customers and orders. This type of join typically equates to a join over a foreign key relationship in the database.
SELECT c
FROM Customer c
JOIN c.orders o
WHERE c.status = 1
Equivalently:
SELECT c
FROM Customer c
INNER JOIN c.orders o
WHERE c.status = 1
This is equivalent to the following query using the earlier IN construct, defined in [4]. It selects those customers of status 1 for which at least one order exists:
SELECT OBJECT(c)
FROM Customer c, IN(c.orders) o
WHERE c.status = 1
The query below joins over Employee
, ContactInfo
and Phone
.
ContactInfo
is an embeddable class that consists of an address
and set of phones. Phone
is an entity.
SELECT p.vendor
FROM Employee e JOIN e.contactInfo c JOIN c.phones p
WHERE c.address.zipcode = '95054'
A join condition may be specified for an inner join. This is equivalent to specification of the same condition in the WHERE clause.
4.4.5.2. Outer Joins
The syntax for an outer join to an entity type is given by:
LEFT [OUTER] JOIN range_variable_declaration [join_condition]
The keyword OUTER is optional and does not affect the semantics of the query.
SELECT c
FROM Customer c
LEFT JOIN Order o ON o.customer.id = c.id
WHERE c.status = 1
Or, equivalently:
SELECT c
FROM Customer c
LEFT OUTER JOIN Order o ON o.customer.id = c.id
WHERE c.status = 1
Outer joins enable the retrieval of a set of entities where matching
values in the join condition may be absent. For example, the queries
above return Customer
instances with no matching Order
.
The syntax for an outer join over an association is given by:
LEFT [OUTER] JOIN join_association_path_expression [AS] identification_variable [join_condition]
An association outer join without no explicit join_condition
has an
implicit join condition inferred from the foreign key relationship
mapped by the join_association_path_expression
. Typically, a JPQL
join of this form is translated to a SQL outer join with an ON condition
specifying the foreign key relationship, as in the following examples.
Jakarta Persistence query language:
SELECT s.name, COUNT(p)
FROM Suppliers s LEFT JOIN s.products p
GROUP BY s.name
SQL:
SELECT s.name, COUNT(p.id)
FROM Suppliers s LEFT JOIN Products p
ON s.id = p.supplierId
GROUP By s.name
An explicit join_condition
(that is, an ON condition in the JOIN)
results in an additional restriction in the ON condition of the
generated SQL.
Jakarta Persistence query language:
SELECT s.name, COUNT(p)
FROM Suppliers s LEFT JOIN s.products p
ON p.status = 'inStock'
GROUP BY s.name
SQL:
SELECT s.name, COUNT(p.id)
FROM Suppliers s LEFT JOIN Products p
ON s.id = p.supplierId AND p.status = 'inStock'
GROUP BY s.name
Note that the result of this query will be different from that of the following query:
SELECT s.name, COUNT(p)
FROM Suppliers s LEFT JOIN s.products p
WHERE p.status = 'inStock'
GROUP BY s.name
The result of the latter query will exclude suppliers who have no products in stock whereas the former query will include them.
An important use case for LEFT JOIN is in enabling the prefetching of related data items as a side effect of a query. This is accomplished by specifying the LEFT JOIN as a FETCH JOIN, as described below.
4.4.5.3. Fetch Joins
A FETCH JOIN clause in a query results in eager fetching of an association or element collection as a side effect of execution of the query.
The syntax for a fetch join is given by:
fetch_join ::= [LEFT [OUTER] | INNER] JOIN FETCH join_association_path_expression
A FETCH JOIN must be an INNER or LEFT (OUTER) join. A FETCH JOIN does not have an explicit join condition or identification variable.
The association referenced by the right side of the FETCH JOIN clause must be an association or element collection that is referenced from an entity or embeddable that is returned as a result of the query. It is not permitted to specify an identification variable for the objects referenced by the right side of the FETCH JOIN clause, and hence references to the implicitly fetched entities or elements cannot appear elsewhere in the query.
The following query returns a set of
departments. As a side effect, the associated employees for those
departments are also retrieved, even though they are not part of the
explicit query result. The initialization of the persistent state or
relationship fields or properties of the objects that are retrieved as a
result of a fetch join is determined by the metadata for that class—in
this example, the Employee
entity class.
SELECT d
FROM Department d LEFT JOIN FETCH d.employees
WHERE d.deptno = 1
A fetch join has the same join semantics as the corresponding inner or outer join, except that the related objects specified on the right-hand side of the join operation are not returned in the query result or otherwise referenced in the query. Hence, for example, if department 1 has five employees, the above query returns five references to the department 1 entity.
The FETCH JOIN construct must not be used in the FROM clause of a subquery.
4.4.6. Collection Member Declarations
An identification variable declared by a
collection_member_declaration
ranges over values of a collection
obtained by navigation using a path expression.
An identification variable of a collection member declaration is declared using a special operator, the reserved identifier IN. The argument to the IN operator is a collection-valued path expression. The path expression evaluates to a collection type specified as a result of navigation to a collection-valued association field of an entity or embeddable class abstract schema type.
The syntax for declaring a collection member identification variable is as follows:
collection_member_declaration ::= IN (collection_valued_path_expression) [AS] identification_variable
For example, the query
SELECT DISTINCT o
FROM Order o JOIN o.lineItems l
WHERE l.product.productType = 'office_supplies'
can equivalently be expressed as follows, using the IN operator:
SELECT DISTINCT o
FROM Order o, IN(o.lineItems) l
WHERE l.product.productType = 'office_supplies'
In this example, lineItems
is the name of an
association field whose value is a collection of instances of the
abstract schema type LineItem
. The identification variable l
designates a member of this collection, a single LineItem abstract
schema type instance. In this example, o
is an identification variable
of the abstract schema type Order.
4.4.7. FROM Clause and SQL
The Jakarta Persistence query language treats the FROM clause similarly to SQL in that the declared identification variables affect the results of the query even if they are not used in the WHERE clause. Application developers should use caution in defining identification variables because the domain of the query can depend on whether there are any values of the declared type.
For example, the FROM clause below defines a
query over all orders that have line items and existing products. If
there are no Product
instances in the database, the domain of the
query is empty and no order is selected.
SELECT o
FROM Order AS o JOIN o.lineItems l JOIN l.product p
4.4.8. Polymorphism
Jakarta Persistence queries are automatically polymorphic. The FROM clause of a query designates not only instances of the specific entity class(es) to which it explicitly refers but instances of subclasses of those classes as well. The instances returned by a query thus include instances of the subclasses that satisfy the query criteria.
Non-polymorphic queries or queries whose polymorphism is restricted can be specified using entity type expressions in the WHERE clause to restrict the domain of the query. See Section 4.7.7.
4.4.9. Downcasting
The use of the TREAT operator is supported for downcasting within path expressions in the FROM and WHERE clauses. Use of the TREAT operator allows access to subclass-specific state.
If during query execution the first argument to the TREAT operator is not a subtype (proper or improper) of the target type, the path is considered to have no value, and does not participate in the determination of the result. That is, in the case of a join, the referenced object does not participate in the result, and in the case of a restriction, the associated predicate is false. Use of the TREAT operator therefore also has the effect of filtering on the specified type (and its subtypes) as well as performing the downcast. If the target type is not a subtype (proper or improper) of the static type of the first argument, the query is invalid.
Examples:
SELECT b.name, b.ISBN
FROM Order o JOIN TREAT(o.product AS Book) b
SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp
WHERE lp.budget > 1000
SELECT e FROM Employee e JOIN e.projects p
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE "cost overrun"
SELECT e FROM Employee e
WHERE TREAT(e AS Exempt).vacationDays > 10
OR TREAT(e AS Contractor).hours > 100
4.5. WHERE Clause
The WHERE clause of a query consists of a conditional expression used to select objects or values that satisfy the expression. The WHERE clause restricts the result of a select statement or the scope of an update or delete operation.
A WHERE clause is defined as follows:
where_clause ::= WHERE conditional_expression
The GROUP BY construct enables the aggregation of values according to the properties of an entity class. The HAVING construct enables conditions to be specified that further restrict the query result as restrictions upon the groups.
The syntax of the HAVING clause is as follows:
having_clause ::= HAVING conditional_expression
The GROUP BY and HAVING constructs are further discussed in Section 4.8.
4.6. Conditional Expressions
The following sections describe language constructs that can be used in a conditional expression of the WHERE clause, the HAVING clause, or in an ON condition.
State fields that are mapped in serialized form or as lobs cannot be portably used in conditional [68].
4.6.1. Literals
A string literal is enclosed in single
quotes—for example: 'literal'. A string literal that includes a single
quote is represented by two single quotes—for example: 'literal''s'.
String literals in queries, like Java String
literals, use unicode
character encoding. The use of Java escape notation is not supported in
query string literals.
A numeric literal may be either:
-
a decimal Java integer (int or long) literal
-
a Java floating point (float or double) literal, or
-
a literal
BigInteger
orBigDecimal
.
A suffix L
, D
, or F
may be used to indicate the specific numeric
type, in accordance with the Java Language Specification. The suffix is
not case-sensitive. The literal numeric value preceding the suffix must
conform to the rules for Java numeric literals established by the Java
Language Specification.
A suffix BI
or BD
may be used to indicate a literal BigInteger
or
BigDecimal
, respectively. The literal numeric value preceding the suffix
must be an exact or approximate SQL numeric literal. For a BigInteger
literal, the numeric value must be an exact integer literal.
Just as in Java, when a numeric literal has no suffix:
-
an integer literal is interpreted as a Java int, and
-
a floating point literal is interpreted as a Java double.
Support for hexadecimal and octal numeric literals is not required by this specification.
Enum literals support the use of Java enum literal syntax. The fully qualified enum class name must be specified.
The JDBC escape syntax may be used for the specification of date, time, and timestamp literals. For example:
SELECT o
FROM Customer c JOIN c.orders o
WHERE c.name = 'Smith'
AND o.submissionDate < {d '2008-12-31'}
The portability of this syntax for date, time, and timestamp literals is dependent upon the JDBC driver in use. Persistence providers are not required to translate from this syntax into the native syntax of the database or driver.
The boolean literals are TRUE
and FALSE
.
Entity type literals are specified by entity names—for example: Customer
.
Although reserved literals appear in upper case, they are case-insensitive.
4.6.2. Identification Variables
All identification variables used in the WHERE or HAVING clause of a SELECT or DELETE statement must be declared in the FROM clause, as described in Section 4.4.2. The identification variables used in the WHERE clause of an UPDATE statement must be declared in the UPDATE clause.
Identification variables are existentially quantified in the WHERE and HAVING clause. This means that an identification variable represents a member of a collection or an instance of an entity’s abstract schema type. An identification variable never designates a collection in its entirety.
4.6.3. Path Expressions
It is illegal to use a
collection_valued_path_expression
within a WHERE or HAVING clause as
part of a conditional expression except in an
empty_collection_comparison_expression
, in a
collection_member_expression
, or as an argument to the SIZE operator.
4.6.4. Input Parameters
An input parameter allows a value in the Java program to be safely interpolated into the text of the parameterized query.
In a given query, either positional or named parameters may be used. Positional and named parameters must not be mixed in a single query.
The persistence provider is required to support input parameters which
occur in the WHERE
clause or HAVING
clause of a query, or as the
new value for an update item in the SET
clause of an update statement.
Note that if an input parameter value is null, comparison operations or arithmetic operations involving the input parameter will result in an unknown value. See Section 4.12. |
An input parameter might be single-valued or collection-valued.
An input parameter which occurs directly to the right of the IN
keyword
in an IN
predicate, as defined in Section 4.6.9, is collection-valued. Every
other input parameter is single-valued
The API for the binding concrete arguments to query parameters is described in Section 3.11.
4.6.4.1. Positional Parameters
The following rules apply to positional input parameters.
-
A positional parameter is designated by an integer, and prefixed with a ? symbol (question mark) in the text of the query string. For example: ?1.
-
Input parameters are numbered starting from 1.
-
A given positional parameter may occur more than once in the query string.
-
The ordering of the use of parameters within the text of the query string need not match the numbering of the positional parameters.
4.6.4.2. Named Parameters
A named parameter is denoted by an identifier, and prefixed by the : symbol (colon) in the text of the query string. The identifier name must follow the usual rules for identifiers specified in Section 4.4.1. Named parameters are case-sensitive.
Example:
SELECT c
FROM Customer c
WHERE c.status = :stat
A given named parameter may occur more than once in the query string.
4.6.5. Conditional Expression Composition
Conditional expressions are composed of other conditional expressions, comparison operations, logical operations, path expressions that evaluate to boolean values, boolean literals, and boolean input parameters.
The scalar expressions described in Section 4.7 can be used in conditional expressions.
Aggregate functions can only be used in conditional expressions in a HAVING clause. See Section 4.8.
Standard bracketing ()
for ordering expression evaluation is supported.
Conditional expressions are defined as follows:
conditional_expression ::= conditional_term | conditional_expression OR conditional_term conditional_term ::= conditional_factor | conditional_term AND conditional_factor conditional_factor ::= [NOT] conditional_primary conditional_primary ::= simple_cond_expression | (conditional_expression) simple_cond_expression ::= comparison_expression | between_expression | in_expression | like_expression | null_comparison_expression | empty_collection_comparison_expression | collection_member_expression | exists_expression
4.6.6. Operators and Operator Precedence
The operators are listed below in order of decreasing precedence.
-
Navigation operator (
.
) -
Arithmetic operators:
-
+, - unary
-
*, / multiplication and division
-
+, - addition and subtraction
-
-
String concatenation (||)
-
Comparison operators: =, >, >=, < , <=, <> (not equal), [NOT] BETWEEN, [NOT] LIKE, [NOT] IN, IS [NOT] NULL, IS [NOT] EMPTY, [NOT] MEMBER [OF], [NOT] EXISTS
-
Logical operators:
-
NOT
-
AND
-
OR
-
The following sections describe operators used in specific expressions.
4.6.7. Comparison Expressions
The syntax for the use of comparison expressions in a conditional expression is as follows[69]:
comparison_expression ::= string_expression comparison_operator {string_expression | all_or_any_expression} | boolean_expression {= | <>} {boolean_expression | all_or_any_expression} | enum_expression {= | <>} {enum_expression | all_or_any_expression} | datetime_expression comparison_operator {datetime_expression | all_or_any_expression} | entity_expression {= | <>} {entity_expression | all_or_any_expression} | arithmetic_expression comparison_operator {arithmetic_expression | all_or_any_expression} | entity_type_expression {= | <>} entity_type_expression} comparison_operator ::= = | > | >= | < | <= | <>
Examples:
item.cost * 1.08 <= 100.00 CONCAT(person.lastName, ', ', person.firstName)) = 'Jones, Sam' TYPE(e) = ExemptEmployee
4.6.8. Between Expressions
The syntax for the use of the comparison operator [NOT] BETWEEN in a conditional expression is as follows:
between_expression ::= arithmetic_expression [NOT] BETWEEN arithmetic_expression AND arithmetic_expression | string_expression [NOT] BETWEEN string_expression AND string_expression | datetime_expression [NOT] BETWEEN datetime_expression AND datetime_expression
The BETWEEN expression
x BETWEEN y AND z
is semantically equivalent to:
y <= x AND x <= z
The rules for unknown and NULL values in comparison operations apply. See Section 4.12.
Examples:
-
p.age BETWEEN 15 and 19
is equivalent top.age >= 15 AND p.age <= 19
-
p.age NOT BETWEEN 15 and 19
is equivalent top.age < 15 OR p.age > 19
In the following example,
transactionHistory
is a list of credit card transactions defined using
an order column.
SELECT t
FROM CreditCard c JOIN c.transactionHistory t
WHERE c.holder.name = 'John Doe' AND INDEX(t) BETWEEN 0 AND 9
4.6.9. In Expressions
The syntax for the use of the comparison operator [NOT] IN in a conditional expression is as follows:
in_expression ::= {state_valued_path_expression | type_discriminator} [NOT] IN {(in_item {, in_item}*) | (subquery) | collection_valued_input_parameter} in_item ::= literal | single_valued_input_parameter
The state_valued_path_expression
must have
a string, numeric, date, time, timestamp, or enum value.
The literal and/or input parameter values
must be like the abstract schema type of the
state_valued_path_expression
in type. (See Section 4.13.)
The results of the subquery must be like
the abstract schema type of the state_valued_path_expression
in
type. Subqueries are discussed in Section 4.6.16.
Example 1:
o.country IN ('UK', 'US', 'France')
is true for UK
and false for Peru
, and is equivalent to the expression
(o.country = 'UK') OR (o.country = 'US') OR (o.country = 'France')
Example 2:
o.country NOT IN ('UK', 'US', 'France')
is false for UK
and true for Peru
, and is equivalent to the expression
NOT ((o.country = 'UK') OR (o.country = 'US') OR (o.country = 'France'))
If an IN or NOT IN expression has a list of in_item
expressions,
there must be at least one item in the list.
The value of such expressions is determined according to the
following rules:
-
If the
state_valued_path_expression
in an IN or NOT IN expression evaluates toNULL
or unknown, then the whole IN or NOT IN expression evaluates toNULL
or unknown. -
Otherwise, if the
state_valued_path_expression
and at least onein_item
evaluate to the same value, the whole IN or NOT IN expression evaluates to true. -
Otherwise, if the value of a
state_valued_path_expression
evaluates to a value distinct from the value of everyin_item
expression, the whole IN or NOT IN expression evaluates to:-
false, if every
in_item
expression evaluates to a non-null value, or -
NULL
or unknown if at least onein_item
expression evaluates to null.
-
The list of values may be parameterized by a collection-valued input parameter. [70] (See Section 4.6.4.)
o.country NOT IN :countries
4.6.10. Like Expressions
The syntax for the use of the comparison operator [NOT] LIKE in a conditional expression is as follows:
like_expression ::= string_expression [NOT] LIKE pattern_value [ESCAPE escape_character]
The string_expression
must have a string
value. The pattern_value
is a string literal or a string-valued input
parameter in which an underscore () stands for any single
character, a percent (%) character stands for any sequence of
characters (including the empty sequence), and all other characters
stand for themselves. The optional
escape_character
_ is a
single-character string literal or a character-valued input parameter
(i.e., char
or Character
) and is used to escape the special meaning
of the underscore and percent characters in pattern_value
_.[71]
Examples:
-
address.phone LIKE '12%3' is true for '123', '12993' and false for '1234'
-
asentence.word LIKE 'l_se' is true for 'lose' and false for 'loose'
-
aword.underscored LIKE '\%' ESCAPE '\'_ is true for '_foo' and false for 'bar'
-
address.phone NOT LIKE '12%3' is false for '123' and '12993' and true for '1234'
If the value of the string_expression
or
pattern_value
is NULL
or unknown, the value of the LIKE expression
is unknown. If the escape_character
is specified and is NULL
, the
value of the LIKE expression is unknown.
4.6.11. Null Comparison Expressions
The syntax for the use of the comparison operator IS NULL in a conditional expression is as follows:
null_comparison_expression ::= {single_valued_path_expression | input_parameter} IS [NOT] NULL
A null comparison expression tests whether or
not the single-valued path expression or input parameter is a NULL
value.
Null comparisons over instances of embeddable class types are not supported. Support for comparisons over embeddables may be added in a future release of this specification.
4.6.12. Empty Collection Comparison Expressions
The syntax for the use of the comparison
operator IS EMPTY in an empty_collection_comparison_expression
is as
follows:
empty_collection_comparison_expression ::= collection_valued_path_expression IS [NOT] EMPTY
This expression tests whether or not the collection designated by the collection-valued path expression is empty (i.e, has no elements).
Example:
SELECT o
FROM Order o
WHERE o.lineItems IS EMPTY
If the value of the collection-valued path expression in an empty collection comparison expression is unknown, the value of the empty comparison expression is unknown.
4.6.13. Collection Member Expressions
The syntax for the use of the comparison
operator MEMBER OF[72] in an
collection_member_expression
is as follows:
collection_member_expression ::= entity_or_value_expression [NOT] MEMBER [OF] collection_valued_path_expression entity_or_value_expression ::= single_valued_object_path_expression | state_valued_path_expression | simple_entity_or_value_expression simple_entity_or_value_expression ::= identification_variable | input_parameter | literal
This expression tests whether the designated value is a member of the collection specified by the collection-valued path expression.
Expressions that evaluate to embeddable types are not supported in collection member expressions. Support for use of embeddables in collection member expressions may be added in a future release of this specification.
If the collection valued path expression
designates an empty collection, the value of the MEMBER OF expression is
FALSE and the value of the NOT MEMBER OF expression is TRUE. Otherwise,
if the value of the collection_valued_path_expression
or entity_or_value_expression
in the
collection member expression is NULL
or unknown, the value of the
collection member expression is unknown.
Example:
SELECT p
FROM Person p
WHERE 'Joe' MEMBER OF p.nicknames
4.6.14. Exists Expressions
An EXISTS expression is a predicate that is true only if the result of the subquery consists of one or more values and that is false otherwise.
The syntax of an exists expression is
exists_expression ::= [NOT] EXISTS (subquery)
Example:
SELECT DISTINCT emp
FROM Employee emp
WHERE EXISTS (
SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
The result of this query consists of all employees whose spouses are also employees.
4.6.15. All or Any Expressions
An ALL conditional expression is a predicate over a subquery that is true if the comparison operation is true for all values in the result of the subquery or the result of the subquery is empty. An ALL conditional expression is false if the result of the comparison is false for at least one value of the result of the subquery, and is unknown if neither true nor false.
An ANY conditional expression is a predicate over a subquery that is true if the comparison operation is true for some value in the result of the subquery. An ANY conditional expression is false if the result of the subquery is empty or if the comparison operation is false for every value in the result of the subquery, and is unknown if neither true nor false. The keyword SOME is synonymous with ANY.
The comparison operators used with ALL or ANY conditional expressions are =, <, <=, >, >=, <>. The result of the subquery must be like that of the other argument to the comparison operator in type. See Section 4.13.
The syntax of an ALL or ANY expression is specified as follows:
all_or_any_expression ::= {ALL | ANY | SOME} (subquery)
Example:
SELECT emp
FROM Employee emp
WHERE emp.salary > ALL (
SELECT m.salary
FROM Manager m
WHERE m.department = emp.department)
The result of this query consists of all employees whose salaries exceed the salaries of all managers in their department.
4.6.16. Subqueries
Subqueries may be used in the WHERE or HAVING clause.[73]
The syntax for subqueries is as follows:
subquery ::= simple_select_clause subquery_from_clause [where_clause] [groupby_clause] [having_clause] simple_select_clause ::= SELECT [DISTINCT] simple_select_expression subquery_from_clause ::= FROM subselect_identification_variable_declaration {, subselect_identification_variable_declaration | collection_member_declaration}* subselect_identification_variable_declaration ::= identification_variable_declaration | derived_path_expression [AS] identification_variable {join}* | derived_collection_member_declaration simple_select_expression ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable derived_path_expression ::= general_derived_path.single_valued_object_field | general_derived_path.collection_valued_field general_derived_path ::= simple_derived_path | treated_derived_path{.single_valued_object_field}* simple_derived_path ::= superquery_identification_variable{.single_valued_object_field}* treated_derived_path ::= TREAT(general_derived_path AS subtype) derived_collection_member_declaration ::= IN superquery_identification_variable.{single_valued_object_field.}*collection_valued_field
Examples:
SELECT DISTINCT emp
FROM Employee emp
WHERE EXISTS (
SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
Note that some contexts in which a subquery can be used require that the subquery be a scalar subquery (i.e., produce a single result). This is illustrated in the following examples using numeric comparisons.
SELECT c
FROM Customer c
WHERE (SELECT AVG(o.price) FROM c.orders o) > 100
SELECT goodCustomer
FROM Customer goodCustomer
WHERE goodCustomer.balanceOwed < (
SELECT AVG(c.balanceOwed)/2.0 FROM Customer c)
4.7. Scalar Expressions
Numeric, string, datetime, case, and entity type expressions result in scalar values.
Scalar expressions may be used in the SELECT clause of a query as well as in the WHERE[74] and HAVING clauses.
scalar_expression::= arithmetic_expression | string_expression | enum_expression | datetime_expression | boolean_expression | case_expression | entity_type_expression
4.7.1. Arithmetic Expressions
The arithmetic operators are:
-
+, - unary
-
*, / multiplication and division
-
+, - addition and subtraction
Arithmetic operations use numeric promotion.
Arithmetic functions are described in Section 4.7.3.2.
4.7.2. String concatenation operator
The binary concatenation operator is ||. Its operands must be string expressions.
4.7.3. Built-in String, Arithmetic, and Datetime Functional Expressions
The Jakarta Persistence query language includes the built-in functions described in Section 4.7.3.1, Section 4.7.3.2, Section 4.7.3.3, which may be used in the SELECT, WHERE or HAVING clause of a query. The invocation of predefined database functions and user-defined database functions is described in Section 4.7.5.
If the value of any argument to a functional expression is null or unknown, the value of the functional expression is unknown.
4.7.3.1. String Functions
functions_returning_strings ::= CONCAT(string_expression, string_expression {, string_expression}*) | SUBSTRING(string_expression, arithmetic_expression [, arithmetic_expression]) | TRIM([[trim_specification] [trim_character] FROM] string_expression) | LOWER(string_expression) | UPPER(string_expression) | REPLACE(string_expression, string_expression, string_expression) | LEFT(string_expression, arithmetic_expression) | RIGHT(string_expression, arithmetic_expression) trim_specification ::= LEADING | TRAILING | BOTH functions_returning_numerics ::= LENGTH(string_expression) | LOCATE(string_expression, string_expression[, arithmetic_expression])
The CONCAT function returns a string that is a concatenation of its arguments.
The second and third arguments of the SUBSTRING function denote the starting position and length of the substring to be returned. These arguments are integers. The third argument is optional. If it is not specified, the substring from the start position to the end of the string is returned. The first position of a string is denoted by 1. The SUBSTRING function returns a string.
The TRIM function trims the specified
character from a string. If the character to be trimmed is not
specified, it will be assumed to be space (or blank). The optional
trim_character
__ is a single-character string literal or a
character-valued input parameter (i.e., char
or Character
)[75]. If a trim specification is not provided, it
defaults to BOTH. The TRIM function returns the trimmed string.
The LOWER and UPPER functions convert a string to lower and upper case, respectively, with regard to the locale of the database. They return a string.
The LEFT and RIGHT functions return the leftmost or rightmost substring, respectively, of the first argument whose length is given by the second argument.
The REPLACE function replaces all occurrences within the first argument string of the second argument string with the third argument string.
The LOCATE function returns the position at which one string occurs within a second string, optionally ignoring any occurrences that begin before a specified character position in the second string. It returns the first character position within the second string (after the specified character position, if any) at which the first string occurs, as an integer, where the first character of the second string is denoted by 1. That is, the first argument is the string to be searched for; the second argument is the string to be searched in; the optional third argument is an integer representing the character position at which the search starts (by default, 1, the first character of the second string). If the first string does not occur within the second string, 0 is returned.[76]
The LENGTH function returns the length of the string in characters as an integer.
4.7.3.2. Arithmetic Functions
functions_returning_numerics ::= ABS(arithmetic_expression) | CEILING(arithmetic_expression) | EXP(arithmetic_expression) | FLOOR(arithmetic_expression) | LN(arithmetic_expression) | MOD(arithmetic_expression, arithmetic_expression) | POWER(arithmetic_expression, arithmetic_expression) | ROUND(arithmetic_expression, arithmetic_expression) | SIGN(arithmetic_expression) | SQRT(arithmetic_expression) | SIZE(collection_valued_path_expression) | INDEX(identification_variable) | extract_datetime_field
The ABS, CEILING, and FLOOR functions accept a numeric argument and return a number (integer, float, or double) of the same type as the argument.
The SIGN function accepts a numeric argument and returns an integer.
The SQRT, EXP, and LN functions accept a numeric argument and return a double.
The MOD function accepts two integer arguments and returns an integer.
The ROUND function accepts a numeric argument and an integer argument and returns a number of the same type as the first argument.
The POWER function accepts two numeric arguments and returns a double.
Numeric arguments to these functions may correspond to the numeric Java object types as well as the primitive numeric types.
The SIZE function returns an integer value, the number of elements of the collection. If the collection is empty, the SIZE function evaluates to zero.
The INDEX function returns an integer value corresponding to the position of its argument in an ordered list. The INDEX function can only be applied to identification variables denoting types for which an order column has been specified.
In the following example, studentWaitlist is a list of students for which an order column has been specified:
SELECT w.name
FROM Course c JOIN c.studentWaitlist w
WHERE c.name = 'Calculus'
AND INDEX(w) = 0
4.7.3.3. Datetime Functions
functions_returning_datetime := CURRENT_DATE | CURRENT_TIME | CURRENT_TIMESTAMP | LOCAL DATE | LOCAL TIME | LOCAL DATETIME | extract_datetime_part
The functions LOCAL DATE, LOCAL TIME, and LOCAL DATETIME return the value
of the current date, time, or timestamp on the database server, respectively.
Their types are java.time.LocalDate
, java.time.LocalTime
, and
java.time.LocalDateTime
respectively.
The functions CURRENT_DATE, CURRENT_TIME, and CURRENT_TIMESTAMP
return the value of the current date, time, or timestamp on the database
server, respectively. Their types are java.sql.Date
, java.sql.Time
,
and java.sql.Timestamp
respectively.
The EXTRACT function takes a datetime argument and one of the following field type identifiers: YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, DATE, TIME.
EXTRACT returns the value of the corresponding field or part of the datetime.
extract_datetime_field := EXTRACT(datetime_field FROM datetime_expression) datetime_field := identification_variable
For the following field type identifiers, EXTRACT returns an integer value:
-
YEAR means the calendar year.
-
QUARTER means the calendar quarter, numbered from 1 to 4.
-
MONTH means the calendar month of the year, numbered from 1.
-
WEEK means the ISO-8601 week number.
-
DAY means the calendar day of the month, numbered from 1.
-
HOUR means the hour of the day in 24-hour time, numbered from 0 to 23.
-
MINUTE means the minute of the hour, numbered from 0 to 59.
For the SECOND field type identifier, EXTRACT returns a floating point value:
-
SECOND means the second of the minute, numbered from 0 to 59, including a fractional part representing fractions of a second.
It is illegal to pass a datetime argument which does not have the given field type to EXTRACT.
extract_datetime_part := EXTRACT(datetime_part FROM datetime_expression) datetime_part := identification_variable
For the following field type identifiers, EXTRACT returns a part of the datetime value:
-
DATE means the date part of a datetime.
-
TIME means the time part of a datetime.
It is illegal to pass a datetime argument which does not have the given part to EXTRACT.
FROM Course c WHERE c.year = EXTRACT(YEAR FROM LOCAL DATE)
4.7.4. Typecasts
The CAST function converts an expression of one type to an expression of a different type.
string_cast_function::= CAST(scalar_expression AS STRING) arithmetic_cast_function::= CAST(string_expression AS {INTEGER | LONG | FLOAT | DOUBLE})
The persistence provider is required to accept typecasts of the following forms:
-
any scalar expression to STRING
-
any string expression to INTEGER, LONG, FLOAT, or DOUBLE
Typecast expressions are evaluated by the database, with semantics that vary somewhat between different databases.
When a typecast occurs as a select expression, the result type of the select expression is:
-
java.lang.String
for a cast to STRING -
java.lang.Integer
,java.lang.Long
,java.lang.Float
, orjava.lang.Double
for a cast to INTEGER, LONG, FLOAT, or DOUBLE, respectively
4.7.5. Invocation of Predefined and User-defined Database Functions
The invocation of functions other than the
built-in functions of the Jakarta Persistence query language is supported
by means of the function_invocation
syntax. This includes the
invocation of predefined database functions and user-defined database
functions.
function_invocation ::= FUNCTION(function_name {, function_arg}*) function_arg ::= literal | state_valued_path_expression | input_parameter | scalar_expression
The function_name
argument is a string that
denotes the database function that is to be invoked. The arguments must
be suitable for the database function that is to be invoked. The result
of the function must be suitable for the invocation context.
The function may be a database-defined function or a user-defined function. The function may be a scalar function or an aggregate function.
Applications that use the
function_invocation
syntax will not be portable across databases.
Example:
SELECT c
FROM Customer c
WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit)
4.7.6. Case Expressions
The following forms of case expressions are supported: general case expressions, simple case expressions, coalesce expressions, and nullif expressions.[77]
case_expression ::= general_case_expression | simple_case_expression | coalesce_expression | nullif_expression general_case_expression ::= CASE when_clause {when_clause}* ELSE scalar_expression END when_clause ::= WHEN conditional_expression THEN scalar_expression simple_case_expression ::= CASE case_operand simple_when_clause {simple_when_clause}* ELSE scalar_expression END case_operand ::= state_valued_path_expression | type_discriminator simple_when_clause ::= WHEN scalar_expression THEN scalar_expression coalesce_expression ::= COALESCE(scalar_expression {, scalar_expression}+) nullif_expression ::= NULLIF(scalar_expression, scalar_expression)
Examples:
UPDATE Employee e
SET e.salary =
CASE WHEN e.rating = 1 THEN e.salary * 1.1
WHEN e.rating = 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
UPDATE Employee e
SET e.salary =
CASE e.rating WHEN 1 THEN e.salary * 1.1
WHEN 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
SELECT e.name,
CASE TYPE(e) WHEN Exempt THEN 'Exempt'
WHEN Contractor THEN 'Contractor'
WHEN Intern THEN 'Intern'
ELSE 'NonExempt'
END
FROM Employee e
WHERE e.dept.name = 'Engineering'
SELECT e.name,
f.name,
CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum '
WHEN f.annualMiles > 25000 THEN 'Gold '
ELSE ''
END,
'Frequent Flyer')
FROM Employee e JOIN e.frequentFlierPlan f
4.7.7. Entity Type Expressions
An entity type expression can be used to restrict query polymorphism. The TYPE operator returns the exact type of the argument.
The syntax of an entity type expression is as follows:
entity_type_expression ::= type_discriminator | entity_type_literal | input_parameter type_discriminator ::= TYPE(general_identification_variable | single_valued_object_path_expression | input_parameter)
An entity_type_literal
is designated by the entity name.
The Java class of the entity is used as an input parameter to specify the entity type.
Examples:
SELECT e
FROM Employee e
WHERE TYPE(e) IN (Exempt, Contractor)
SELECT e
FROM Employee e
WHERE TYPE(e) IN (:empType1, :empType2)
SELECT e
FROM Employee e
WHERE TYPE(e) IN :empTypes
SELECT TYPE(e)
FROM Employee e
WHERE TYPE(e) <> Exempt
4.7.8. Numeric Expressions and Type Promotion
Every numeric expression in a query is assigned a Java numeric type according to the following rules:
-
An expression that corresponds to a persistent state field is of the same type as that persistent state field.
-
An expression that corresponds to one of arithmetic functions described in Section 4.7.3.2 is of the type defined by Section 4.7.3.2.
-
An expression that corresponds to one of an aggregate functions described in Section 4.9.5 is of the type defined by Section 4.9.5.
For a CASE
expression, COALESCE
expression, NULLIF
expression, or
arithmetic operator expression (+
, -
, *
, /
), the numeric type is
determined by its operand types, and by the following rules[78].
-
If there is an operand of type
Double
ordouble
, the expression is of typeDouble
; -
otherwise, if there is an operand of type
Float
orfloat
, the expression is of typeFloat
; -
otherwise, if there is an operand of type
BigDecimal
, the expression is of typeBigDecimal
; -
otherwise, if there is an operand of type
BigInteger
, the expression is of typeBigInteger
, unless the operator is/
(division), in which case the expression type is not defined here; -
otherwise, if there is an operand of type
Long
orlong
, the expression is of typeLong
, unless the operator is/
(division), in which case the expression type is not defined here; -
otherwise, if there is an operand of integral type, the expression is of type
Integer
, unless the operator is/
(division), in which case the expression type is not defined here.
Users should note that the semantics of the SQL division operation are not standard across databases. In particular, when both operands are of integral types, the result of the division operation will be an integral type in some databases, and an non-integral type in others. Portable applications should not assume a particular result type. |
For numeric expressions occurring in the SELECT clause, these rules determine the Java object type returned in the query result list.
4.8. GROUP BY, HAVING
The GROUP BY construct enables the aggregation of result values according to a set of properties. The HAVING construct enables conditions to be specified that further restrict the query result. Such conditions are restrictions upon the groups.
The syntax of the GROUP BY and HAVING clauses is as follows:
groupby_clause ::= GROUP BY groupby_item {, groupby_item}* groupby_item ::= single_valued_path_expression | identification_variable having_clause ::= HAVING conditional_expression
If a query contains both a WHERE clause and a GROUP BY clause, the effect is that of first applying the where clause, and then forming the groups and filtering them according to the HAVING clause. The HAVING clause causes those groups to be retained that satisfy the condition of the HAVING clause.
The requirements for the SELECT clause when GROUP BY is used follow those of SQL: namely, any item that appears in the SELECT clause (other than as an aggregate function or as an argument to an aggregate function) must also appear in the GROUP BY clause. In forming the groups, null values are treated as the same for grouping purposes.
Grouping by an entity is permitted. In this case, the entity must contain no serialized state fields or lob-valued state fields that are eagerly fetched. Grouping by an entity that contains serialized state fields or lob-valued state fields is not portable, since the implementation is permitted to eagerly fetch fields or properties that have been specified as LAZY.
Grouping by embeddables is not supported.
The HAVING clause is used to filter over the groups, and can contain aggregate functions over attributes included in the groups and/or functions or other query language operators over the attributes that are used for grouping. It is not required that an aggregate function used in the HAVING clause also be used in the SELECT clause.
If there is no GROUP BY clause and the HAVING clause is used, the result is treated as a single group, and the select list can only consist of aggregate functions. The use of HAVING in the absence of GROUP BY is not required to be supported by an implementation of this specification. Portable applications should not rely on HAVING without the use of GROUP BY.
Examples:
SELECT c.status, AVG(c.filledOrderCount), COUNT(c)
FROM Customer c
GROUP BY c.status
HAVING c.status IN (1, 2)
SELECT c.country, COUNT(c)
FROM Customer c
GROUP BY c.country
HAVING COUNT(c) > 30
SELECT c, COUNT(o)
FROM Customer c JOIN c.orders o
GROUP BY c
HAVING COUNT(o) >= 5
4.9. SELECT Clause
The SELECT clause denotes the query result. More than one value may be returned from the SELECT clause of a query.
The SELECT clause can contain one or more of the following elements: an identification variable that ranges over an abstract schema type, a single-valued path expression, a scalar expression, an aggregate expression, a constructor expression.
The SELECT clause has the following syntax:
select_clause ::= SELECT [DISTINCT] select_item {, select_item}* select_item ::= select_expression [[AS] result_variable] select_expression ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable | OBJECT(identification_variable) | constructor_expression constructor_expression ::= NEW constructor_name (constructor_item {, constructor_item}*) constructor_item ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable aggregate_expression ::= {AVG | MAX | MIN | SUM} ([DISTINCT] state_valued_path_expression) | COUNT ([DISTINCT] identification_variable | state_valued_path_expression | single_valued_object_path_expression) | function_invocation
For example:
SELECT c.id, c.status
FROM Customer c JOIN c.orders o
WHERE o.count > 100
In the following example, videoInventory
is
a Map from the entity Movie
to the number of copies in stock:
SELECT v.location.street, KEY(i).title, VALUE(i)
FROM VideoStore v JOIN v.videoInventory i
WHERE v.location.zipcode = '94301' AND VALUE(i) > 0
Note that the SELECT clause must be specified to return only single-valued expressions. The query below is therefore not valid:
SELECT o.lineItems FROM Order AS o
The DISTINCT keyword is used to specify that duplicate values must be eliminated from the query result.
If DISTINCT is not specified, duplicate values are not eliminated.
The result of DISTINCT over embeddable
objects or map entry
results is undefined.
Standalone identification variables in the SELECT clause may optionally be qualified by the OBJECT operator.[79] The SELECT clause must not use the OBJECT operator to qualify path expressions.
A result_variable
may be used to
name a select_item
in the query result.[80]
Example:
SELECT c, COUNT(l) AS itemCount
FROM Customer c JOIN c.Orders o JOIN o.lineItems l
WHERE c.address.state = 'CA'
GROUP BY c
ORDER BY itemCount
4.9.1. Result Type of the SELECT Clause
The type of the query result specified by the SELECT clause of a query is an entity abstract schema type, a state field type, the result of a scalar expression, the result of an aggregate function, the result of a construction operation, or some sequence of these.
The result type of the SELECT clause is defined by the the result types of the select expressions contained in it. When multiple select expressions are used in the SELECT clause, the elements in this result correspond in order to the order of their specification in the SELECT clause and in type to the result types of each of the select expressions.
The type of the result of a select_expression is as follows:
-
The result type of an identification_variable is the type of the entity object or embeddable object to which the identification variable corresponds. The type of an identification_variable that refers to an entity abstract schema type is the type of the entity to which that identification variable corresponds or a subtype as determined by the object/relational mapping.
-
The result type of a
single_valued_path_expression
that is astate_field_path_expression
is the same type as the corresponding state field of the entity or embeddable class. If the state field of the entity is a primitive type, the result type is the corresponding object type. -
The result type of a
single_valued_path_expression
that is asingle_valued_object_path_expression
is the type of the entity object or embeddable object to which the path expression corresponds. Asingle_valued_object_path_expression
that results in an entity object will result in an entity of the type of the relationship field or the subtype of the relationship field of the entity object as determined by the object/relational mapping. -
The result type of a
single_valued_path_expression
that is anidentification_variable
to which the KEY or VALUE function has been applied is determined by the type of the map key or value respectively, as defined by the above rules. -
The result type of a
single_valued_path_expression
that is anidentification_variable
to which the ENTRY function has been applied isjava.util.Map.Entry
, where the key and value types of the map entry are determined by the above rules as applied to the map key and map value respectively. -
The result type of a
scalar_expression
is the type of the scalar value to which the expression evaluates. The result type of a numericscalar_expression
is defined in Section 4.7.8. -
The result type of an
entity_type_expression
scalar expression is the Java class to which the resulting abstract schema type corresponds. -
The result type of aggregate_expression is defined in Section 4.9.5.
-
The result type of a constructor_expression is the type of the class for which the constructor is defined. The types of the arguments to the constructor are defined by the above rules.
4.9.2. Constructor Expressions in the SELECT Clause
A constructor may be used in the SELECT list to return an instance of a Java class. The specified class is not required to be an entity or to be mapped to the database. The constructor name must be fully qualified.
If an entity class name is specified as the constructor name in the SELECT NEW clause, the resulting entity instances will be in either the new or the detached state, depending on whether a primary key is retrieved for the constructed object.
If a single_valued_path_expression
or
identification_variable
that is an argument to the constructor
references an entity, the resulting entity instance referenced by that
single_valued_path_expression
or identification_variable
will be in
the managed state.
For example,
SELECT NEW com.acme.example.CustomerDetails(c.id, c.status, o.count)
FROM Customer c JOIN c.orders o
WHERE o.count > 100
4.9.3. Null Values in the Query Result
If the result of a query corresponds to an association field or state field whose value is null, that null value is returned in the result of the query method. The IS NOT NULL construct can be used to eliminate such null values from the result set of the query.
Note, however, that state field types defined in terms of Java numeric primitive types cannot produce NULL values in the query result. A query that returns such a state field type as a result type must not return a null value.
4.9.4. Embeddables in the Query Result
If the result of a query corresponds to an identification variable or state field whose value is an embeddable, the embeddable instance returned by the query will not be in the managed state (i.e., it will not be part of the state of any managed entity).
In the following example, the Address
instances returned by the query will reference Phone
instances. While
the Phone
instances will be managed, the Address
instances
referenced by the addr
result variable will not be. Modifications to
these embeddable instances will have no effect on persistent state.
@Entity
public class Employee {
@Id
int id;
Address address;
// ...
}
@Embeddable
public class Address {
String street;
// ...
@OneToOne
Phone phone; // fetch=EAGER
}
@Entity
public class Phone {
@Id
int id;
// ...
@OneToOne(mappedBy="address.phone")
Employee emp; // fetch=EAGER
}
SELECT e.address AS addr
FROM Employee e
4.9.5. Aggregate Functions in the SELECT Clause
The result of a query may be the result of an aggregate function applied to a path expression.
The following aggregate functions can be used in the SELECT clause of a query: AVG, COUNT, MAX, MIN, SUM, aggregate functions defined in the database.
For all aggregate functions except COUNT, the path expression that is the argument to the aggregate function must terminate in a state field. The path expression argument to COUNT may terminate in either a state field or a association field, or the argument to COUNT may be an identification variable.
Arguments to the functions SUM and AVG must be numeric. Arguments to the functions MAX and MIN must correspond to orderable state field types (i.e., numeric types, string types, character types, or date types).
The Java type that is contained in the result of a query using an aggregate function is as follows:
-
COUNT returns Long.
-
MAX, MIN return the type of the state field to which they are applied.
-
AVG returns Double.
-
SUM returns Long when applied to state fields of integral types (other than BigInteger); Double when applied to state fields of floating point types; BigInteger when applied to state fields of type BigInteger; and BigDecimal when applied to state fields of type BigDecimal.
Null values are eliminated before the aggregate function is applied, regardless of whether the keyword DISTINCT is specified.
If SUM, AVG, MAX, or MIN is used, and there are no values to which the aggregate function can be applied, the result of the aggregate function is NULL.
If COUNT is used, and there are no values to which COUNT can be applied, the result of the aggregate function is 0.
The argument to an aggregate function may be preceded by the keyword DISTINCT to specify that duplicate values are to be eliminated before the aggregate function is applied.[81]
The use of DISTINCT with COUNT is not supported for arguments of embeddable types or map entry types.
The invocation of aggregate database functions, including user defined functions, is supported by means of the FUNCTION operator. See Section 4.7.5.
The following query returns the average order quantity:
SELECT AVG(o.quantity) FROM Order o
The following query returns the total cost of the items that John Smith has ordered.
SELECT SUM(l.price)
FROM Order o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
The following query returns the total number of orders.
SELECT COUNT(o) FROM Order o
The following query counts the number of items in John Smith’s order for which prices have been specified.
SELECT COUNT(l.price)
FROM Order o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
Note that this is equivalent to:
SELECT COUNT(l)
FROM Order o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Smith' AND c.firstname = 'John' AND l.price IS NOT NULL
4.10. ORDER BY Clause
The ORDER BY clause allows the objects or values that are returned by the query to be ordered.
The syntax of the ORDER BY clause is
orderby_clause ::= ORDER BY orderby_item {, orderby_item}* orderby_item ::= {state_field_path_expression | general_identification_variable | result_variable} [ASC | DESC] [NULLS {FIRST | LAST}]
An orderby_item must be one of the following:
-
A
state_field_path_expression
that evaluates to an orderable state field of an entity or embeddable class abstract schema type designated in the SELECT clause by one of the following:-
a
general_identification_variable
-
a
single_valued_object_path_expression
-
-
A
state_field_path_expression
that evaluates to the same state field of the same entity or embeddable abstract schema type as astate_field_path_expression
in the SELECT clause -
A
general_identification_variable
that evaluates to the same map field of the same entity or embeddable abstract schema type as ageneral_identification_variable
in the SELECT clause -
A
result_variable
that refers to an orderable item in the SELECT clause for which the sameresult_variable
has been specified. This may be the result of anaggregate_expression
, ascalar_expression
, or astate_field_path_expression
in the SELECT clause.
For example, the four queries below are legal.
SELECT o
FROM Customer c JOIN c.orders o JOIN c.address a
WHERE a.state = 'CA'
ORDER BY o.quantity DESC, o.totalcost
SELECT o.quantity, a.zipcode
FROM Customer c JOIN c.orders o JOIN c.address a
WHERE a.state = 'CA'
ORDER BY o.quantity, a.zipcode
SELECT o.quantity, o.cost*1.08 AS taxedCost, a.zipcode
FROM Customer c JOIN c.orders o JOIN c.address a
WHERE a.state = 'CA' AND a.county = 'Santa Clara'
ORDER BY o.quantity, taxedCost, a.zipcode
SELECT AVG(o.quantity) as q, a.zipcode
FROM Customer c JOIN c.orders o JOIN c.address a
WHERE a.state = 'CA'
GROUP BY a.zipcode
ORDER BY q DESC
The following two queries are not legal
because the orderby_item
is not reflected in the SELECT clause of the
query.
SELECT p.product_name
FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
ORDER BY p.price
SELECT p.product_name
FROM Order o, IN(o.lineItems) l JOIN o.customer c
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
ORDER BY o.quantity
If more than one orderby_item
is specified,
the left-to-right sequence of the orderby_item
elements determines the
precedence, whereby the leftmost orderby_item
has highest precedence.
The keyword ASC specifies that ascending
ordering be used for the associated orderby_item
; the keyword DESC
specifies that descending ordering be used. Ascending ordering is the
default.
The keyword NULLS specifies the ordering of null values, either FIRST or LAST.
If NULLS is not specified, SQL rules for the ordering of null values apply: that is, all null values must appear before all non-null values in the ordering or all null values must appear after all non-null values in the ordering, but it is not specified which.
The ordering of the query result is preserved in the result of the query execution method if the ORDER BY clause is used.
4.11. Bulk Update and Delete Operations
Bulk update and delete operations apply to entities of a single entity class (together with its subclasses, if any). Only one entity abstract schema type may be specified in the FROM or UPDATE clause.
The syntax of these operations is as follows:
update_statement ::= update_clause [where_clause] update_clause ::= UPDATE entity_name [[AS] identification_variable] SET update_item {, update_item}* update_item ::= [identification_variable.]{single_valued_embeddable_object_field.}* {state_field | single_valued_object_field} = new_value new_value ::= scalar_expression | simple_entity_expression | NULL delete_statement ::= delete_clause [where_clause] delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]
The syntax of the WHERE clause is described in Section 4.5.
A delete operation only applies to entities of the specified class and its subclasses. It does not cascade to related entities.
The new_value specified for an update operation must be compatible in type with the field to which it is assigned.
Bulk update maps directly to a database update operation, bypassing optimistic locking checks. Portable applications must manually update the value of the version column, if desired, and/or manually validate the value of the version column.
The persistence context is not synchronized with the result of the bulk update or delete.
Caution should be used when executing bulk update or delete operations because they may result in inconsistencies between the database and the entities in the active persistence context. In general, bulk update and delete operations should only be performed within a transaction in a new persistence context or before fetching or accessing entities whose state might be affected by such operations._ |
Examples:
DELETE
FROM Customer c
WHERE c.status = 'inactive'
DELETE
FROM Customer c
WHERE c.status = 'inactive'
AND c.orders IS EMPTY
UPDATE Customer c
SET c.status = 'outstanding'
WHERE c.balance < 10000
UPDATE Employee e
SET e.address.building = 22
WHERE e.address.building = 14
AND e.address.city = 'Santa Clara'
AND e.project = 'Jakarta EE'
4.12. Null Values
When the target of a reference does not exist
in the database, its value is regarded as NULL
. SQL NULL
semantics
[2] defines the evaluation of
conditional expressions containing NULL
values.
The following is a brief description of these semantics:
-
Comparison or arithmetic operations with a NULL value always yield an unknown value.
-
Two NULL values are not considered to be equal, the comparison yields an unknown value.
-
Comparison or arithmetic operations with an unknown value always yield an unknown value.
-
The IS NULL and IS NOT NULL operators convert a
NULL
state field or single-valued object field value into the respective TRUE or FALSE value. -
Boolean operators use three valued logic, defined by Table 1, Table 2, and Table 3.
AND | T | F | U |
---|---|---|---|
T |
T |
F |
U |
F |
F |
F |
F |
U |
U |
F |
U |
OR | T | F | U |
---|---|---|---|
T |
T |
T |
T |
F |
T |
F |
U |
U |
T |
U |
U |
NOT | |
---|---|
T |
F |
F |
T |
U |
U |
The Jakarta Persistence query language defines the empty string, '', as a string with 0 length, which is not equal to a NULL value. However, NULL values and empty strings may not always be distinguished when queries are mapped to some databases. Application developers should therefore not rely on the semantics of query comparisons involving the empty string and NULL value. |
4.13. Equality and Comparison Semantics
Only the values of like types are permitted
to be compared. A type is like another type if they correspond to the
same Java language type, or if one is a primitive Java language type and
the other is the wrapped Java class type equivalent (e.g., int
and
Integer
are like types in this sense). There is one exception to this
rule: it is valid to compare numeric values for which the rules of
numeric promotion apply. Conditional expressions attempting to compare
non-like type values are disallowed except for this numeric case.
Note that the arithmetic operators, the string concatenation operator, and comparison operators are permitted to be applied to state fields and input parameters of the wrapped Java class equivalents to the primitive numeric Java types. |
Two entities of the same abstract schema type are equal if and only if they have the same primary key value.
Only equality/inequality comparisons over enums are required to be supported.
Comparisons over instances of embeddable class or map entry types are not supported.
The following examples illustrate the syntax and semantics of the Jakarta Persistence query language. These examples are based on the example presented in Section 4.3.2.
Find all orders:
SELECT o
FROM Order o
Find all orders that need to be shipped to California:
SELECT o
FROM Order o
WHERE o.shippingAddress.state = 'CA'
Find all states for which there are orders:
SELECT DISTINCT o.shippingAddress.state
FROM Order o
Find all orders that have line items:
SELECT DISTINCT o
FROM Order o JOIN o.lineItems l
Note that the result of this query does not include orders with no associated line items. This query can also be written as:
SELECT o
FROM Order o
WHERE o.lineItems IS NOT EMPTY
Find all orders that have no line items:
SELECT o
FROM Order o
WHERE o.lineItems IS EMPTY
Find all pending orders:
SELECT DISTINCT o
FROM Order o JOIN o.lineItems l
WHERE l.shipped = FALSE
Find all orders in which the shipping address
differs from the billing address. This example assumes that the
application developer uses two distinct entity
types to designate
shipping and billing addresses.
SELECT o
FROM Order o
WHERE
NOT (o.shippingAddress.state = o.billingAddress.state AND
o.shippingAddress.city = o.billingAddress.city AND
o.shippingAddress.street = o.billingAddress.street)
If the application developer uses a single
entity
type in two different relationships for both the shipping
address and the billing address, the above expression can be simplified
based on the equality rules defined in Section 4.13. The
query can then be written as:
SELECT o
FROM Order o
WHERE o.shippingAddress <> o.billingAddress
The query checks whether the same entity abstract schema type instance (identified by its primary key) is related to an order through two distinct relationships.
4.13.1. Queries Using Input Parameters
The following query finds the orders for a product whose name is designated by an input parameter:
SELECT DISTINCT o
FROM Order o JOIN o.lineItems l
WHERE l.product.name = ?1
For this query, the input parameter must be of the type of the state field name, i.e., a string.
4.14. BNF
BNF notation summary:
-
{ … }
grouping -
[ … ]
optional constructs -
*
zero or more -
+
one or more -
|
alternates
The following is the BNF for the Jakarta Persistence query language.
QL_statement ::= select_statement | update_statement | delete_statement select_statement ::= union union ::= intersection | union {UNION [ALL] | EXCEPT [ALL]} intersection intersection ::= query_expression | intersection INTERSECT [ALL] query_expression query_expression ::= select_query | (union) select_query ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause] update_statement ::= update_clause [where_clause] delete_statement ::= delete_clause [where_clause] from_clause ::= FROM identification_variable_declaration {, {identification_variable_declaration | collection_member_declaration}}* identification_variable_declaration ::= range_variable_declaration {join | fetch_join}* range_variable_declaration ::= entity_name [AS] identification_variable join ::= range_join | path_join range_join ::= join_spec range_variable_declaration [join_condition] path_join ::= join_spec join_association_path_expression [AS] identification_variable [join_condition] fetch_join ::= join_spec FETCH join_association_path_expression join_spec ::= [INNER | LEFT [OUTER]] JOIN join_condition ::= ON conditional_expression join_association_path_expression ::= join_collection_valued_path_expression | join_single_valued_path_expression | TREAT(join_collection_valued_path_expression AS subtype) | TREAT(join_single_valued_path_expression AS subtype) join_collection_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}* collection_valued_field join_single_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}* single_valued_object_field collection_member_declaration ::= IN (collection_valued_path_expression) [AS] identification_variable qualified_identification_variable ::= map_field_identification_variable | ENTRY(identification_variable) map_field_identification_variable ::= KEY(identification_variable) | VALUE(identification_variable) single_valued_path_expression ::= qualified_identification_variable | TREAT(qualified_identification_variable AS subtype) | state_field_path_expression | single_valued_object_path_expression general_identification_variable ::= identification_variable | map_field_identification_variable general_subpath ::= simple_subpath | treated_subpath{.single_valued_object_field}* simple_subpath ::= general_identification_variable | general_identification_variable{.single_valued_object_field}* treated_subpath ::= TREAT(general_subpath AS subtype) state_field_path_expression ::= general_subpath.state_field state_valued_path_expression ::= state_field_path_expression | general_identification_variable single_valued_object_path_expression ::= general_subpath.single_valued_object_field collection_valued_path_expression ::= general_subpath.{collection_valued_field} update_clause ::= UPDATE entity_name [[AS] identification_variable] SET update_item {, update_item}* update_item ::= [identification_variable.]{single_valued_embeddable_object_field.}* {state_field | single_valued_object_field} = new_value new_value ::= scalar_expression | simple_entity_expression | NULL delete_clause ::= DELETE FROM entity_name [[AS] identification_variable] select_clause ::= SELECT [DISTINCT] select_item {, select_item}* select_item ::= select_expression [[AS] result_variable] select_expression ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable | OBJECT(identification_variable) | constructor_expression constructor_expression ::= NEW constructor_name (constructor_item {, constructor_item}*) constructor_item ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable aggregate_expression ::= {AVG | MAX | MIN | SUM} ([DISTINCT] state_valued_path_expression) | COUNT ([DISTINCT] identification_variable | state_valued_path_expression | single_valued_object_path_expression) | function_invocation where_clause ::= WHERE conditional_expression groupby_clause ::= GROUP BY groupby_item {, groupby_item}* groupby_item ::= single_valued_path_expression | identification_variable having_clause ::= HAVING conditional_expression orderby_clause ::= ORDER BY orderby_item {, orderby_item}* orderby_item ::= state_field_path_expression | general_identification_variable | result_variable [ASC | DESC] [NULLS {FIRST | LAST}] subquery ::= simple_select_clause subquery_from_clause [where_clause] [groupby_clause] [having_clause] subquery_from_clause ::= FROM subselect_identification_variable_declaration {, subselect_identification_variable_declaration | collection_member_declaration}* subselect_identification_variable_declaration ::= identification_variable_declaration | derived_path_expression [AS] identification_variable {join}* | derived_collection_member_declaration derived_path_expression ::= general_derived_path.single_valued_object_field | general_derived_path.collection_valued_field general_derived_path ::= simple_derived_path | treated_derived_path{.single_valued_object_field}* simple_derived_path ::= superquery_identification_variable{.single_valued_object_field}* treated_derived_path ::= TREAT(general_derived_path AS subtype) derived_collection_member_declaration ::= IN superquery_identification_variable.{single_valued_object_field.}*collection_valued_field simple_select_clause ::= SELECT [DISTINCT] simple_select_expression simple_select_expression::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable scalar_expression ::= arithmetic_expression | string_expression | enum_expression | datetime_expression | boolean_expression | case_expression | entity_type_expression conditional_expression ::= conditional_term | conditional_expression OR conditional_term conditional_term ::= conditional_factor | conditional_term AND conditional_factor conditional_factor ::= [NOT] conditional_primary conditional_primary ::= simple_cond_expression | (conditional_expression) simple_cond_expression ::= comparison_expression | between_expression | in_expression | like_expression | null_comparison_expression | empty_collection_comparison_expression | collection_member_expression | exists_expression between_expression ::= arithmetic_expression [NOT] BETWEEN arithmetic_expression AND arithmetic_expression | string_expression [NOT] BETWEEN string_expression AND string_expression | datetime_expression [NOT] BETWEEN datetime_expression AND datetime_expression in_expression ::= {state_valued_path_expression | type_discriminator} [NOT] IN {(in_item{, in_item}*) | (subquery) | collection_valued_input_parameter} in_item ::= literal | single_valued_input_parameter like_expression ::= string_expression [NOT] LIKE pattern_value [ESCAPE escape_character] null_comparison_expression ::= {single_valued_path_expression | input_parameter} IS [NOT] NULL empty_collection_comparison_expression ::= collection_valued_path_expression IS [NOT] EMPTY collection_member_expression ::= entity_or_value_expression [NOT] MEMBER [OF] collection_valued_path_expression entity_or_value_expression ::= single_valued_object_path_expression | state_field_path_expression | simple_entity_or_value_expression simple_entity_or_value_expression ::= identification_variable | input_parameter | literal exists_expression ::= [NOT] EXISTS (subquery) all_or_any_expression ::= {ALL | ANY | SOME} (subquery) comparison_expression ::= string_expression comparison_operator {string_expression | all_or_any_expression} | boolean_expression {= | <>} {boolean_expression | all_or_any_expression} | enum_expression {= | <>} {enum_expression | all_or_any_expression} | datetime_expression comparison_operator {datetime_expression | all_or_any_expression} | entity_expression {= | <>} {entity_expression | all_or_any_expression} | arithmetic_expression comparison_operator {arithmetic_expression | all_or_any_expression} | entity_type_expression {= | <>} entity_type_expression} comparison_operator ::= = | > | >= | < | <= | <> arithmetic_expression ::= arithmetic_term | arithmetic_expression {+ | -} arithmetic_term arithmetic_term ::= arithmetic_factor | arithmetic_term {* | /} arithmetic_factor arithmetic_factor ::= [{+ | -}] arithmetic_primary arithmetic_primary ::= state_valued_path_expression | numeric_literal | (arithmetic_expression) | input_parameter | functions_returning_numerics | aggregate_expression | case_expression | function_invocation | arithmetic_cast_function | (subquery) string_expression ::= state_valued_path_expression | string_literal | input_parameter | functions_returning_strings | aggregate_expression | case_expression | function_invocation | string_cast_function | string_expression || string_expression | (subquery) datetime_expression ::= state_valued_path_expression | input_parameter | functions_returning_datetime | aggregate_expression | case_expression | function_invocation | date_time_timestamp_literal | (subquery) boolean_expression ::= state_valued_path_expression | boolean_literal | input_parameter | case_expression | function_invocation | (subquery) enum_expression ::= state_valued_path_expression | enum_literal | input_parameter | case_expression | (subquery) entity_expression ::= single_valued_object_path_expression | simple_entity_expression simple_entity_expression ::= identification_variable | input_parameter entity_type_expression ::= type_discriminator | entity_type_literal | input_parameter type_discriminator ::= TYPE(general_identification_variable | single_valued_object_path_expression | input_parameter) arithmetic_cast_function::= CAST(string_expression AS {INTEGER | LONG | FLOAT | DOUBLE}) functions_returning_numerics ::= LENGTH(string_expression) | LOCATE(string_expression, string_expression[, arithmetic_expression]) | ABS(arithmetic_expression) | CEILING(arithmetic_expression) | EXP(arithmetic_expression) | FLOOR(arithmetic_expression) | LN(arithmetic_expression) | SIGN(arithmetic_expression) | SQRT(arithmetic_expression) | MOD(arithmetic_expression, arithmetic_expression) | POWER(arithmetic_expression, arithmetic_expression) | ROUND(arithmetic_expression, arithmetic_expression) | SIZE(collection_valued_path_expression) | INDEX(identification_variable) | extract_datetime_field functions_returning_datetime ::= CURRENT_DATE | CURRENT_TIME | CURRENT_TIMESTAMP | LOCAL DATE | LOCAL TIME | LOCAL DATETIME | extract_datetime_part string_cast_function::= CAST(scalar_expression AS STRING) functions_returning_strings ::= CONCAT(string_expression, string_expression{, string_expression}*) | SUBSTRING(string_expression, arithmetic_expression[, arithmetic_expression]) | TRIM([[trim_specification] [trim_character] FROM] string_expression) | LOWER(string_expression) | UPPER(string_expression) trim_specification ::= LEADING | TRAILING | BOTH function_invocation ::= FUNCTION(function_name{, function_arg}*) extract_datetime_field := EXTRACT(datetime_field FROM datetime_expression) datetime_field := identification_variable extract_datetime_part := EXTRACT(datetime_part FROM datetime_expression) datetime_part := identification_variable function_arg ::= literal | state_valued_path_expression | input_parameter | scalar_expression case_expression ::= general_case_expression | simple_case_expression | coalesce_expression | nullif_expression general_case_expression::= CASE when_clause {when_clause}* ELSE scalar_expression END when_clause ::= WHEN conditional_expression THEN scalar_expression simple_case_expression ::= CASE case_operand simple_when_clause {simple_when_clause}* ELSE scalar_expression END case_operand ::= state_valued_path_expression | type_discriminator simple_when_clause ::= WHEN scalar_expression THEN scalar_expression coalesce_expression ::= COALESCE(scalar_expression{, scalar_expression}+) nullif_expression::= NULLIF(scalar_expression, scalar_expression)
5. Metamodel API
This specification provides a set of interfaces for dynamically accessing the metamodel corresponding to the managed classes of a persistence unit.
5.1. Metamodel API Interfaces
The jakarta.persistence.metamodel
interfaces
provide for dynamically accessing the metamodel of the persistent
state and relationships of the managed classes of a persistence unit.
The metamodel can be accessed through the
EntityManagerFactory
or EntityManager.getMetamodel
methods.
The metamodel API may be extended to cover object/relational mapping information in a future release of this specification.
5.1.1. Metamodel Interface
package jakarta.persistence.metamodel;
import java.util.Set;
/**
* Provides access to the metamodel of persistent
* entities in the persistence unit.
*
* @since 2.0
*/
public interface Metamodel {
/**
* Return the metamodel entity type representing the entity.
* @param entityName the name of the represented entity
* @return the metamodel entity type
* @throws IllegalArgumentException if not an entity
* @see jakarta.persistence.Entity#name
* @since 3.2
*/
EntityType<?> entity(String entityName);
/**
* Return the metamodel entity type representing the entity.
* @param cls the type of the represented entity
* @return the metamodel entity type
* @throws IllegalArgumentException if not an entity
*/
<X> EntityType<X> entity(Class<X> cls);
/**
* Return the metamodel managed type representing the
* entity, mapped superclass, or embeddable class.
* @param cls the type of the represented managed class
* @return the metamodel managed type
* @throws IllegalArgumentException if not a managed class
*/
<X> ManagedType<X> managedType(Class<X> cls);
/**
* Return the metamodel embeddable type representing the
* embeddable class.
* @param cls the type of the represented embeddable class
* @return the metamodel embeddable type
* @throws IllegalArgumentException if not an embeddable class
*/
<X> EmbeddableType<X> embeddable(Class<X> cls);
/**
* Return the metamodel managed types.
* @return the metamodel managed types
*/
Set<ManagedType<?>> getManagedTypes();
/**
* Return the metamodel entity types.
* @return the metamodel entity types
*/
Set<EntityType<?>> getEntities();
/**
* Return the metamodel embeddable types. Returns empty set
* if there are no embeddable types.
* @return the metamodel embeddable types
*/
Set<EmbeddableType<?>> getEmbeddables();
}
5.1.2. Type Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>Type</code> represent persistent object
* or attribute types.
*
* @param <X> The type of the represented object or attribute
*
* @since 2.0
*/
public interface Type<X> {
public static enum PersistenceType {
/** Entity */
ENTITY,
/** Embeddable class */
EMBEDDABLE,
/** Mapped superclass */
MAPPED_SUPERCLASS,
/** Basic type */
BASIC
}
/**
* Return the persistence type.
* @return persistence type
*/
PersistenceType getPersistenceType();
/**
* Return the represented Java type.
* @return Java type
*/
Class<X> getJavaType();
}
5.1.3. ManagedType Interface
package jakarta.persistence.metamodel;
import java.util.Set;
/**
* Instances of the type <code>ManagedType</code> represent entity, mapped
* superclass, and embeddable types.
*
* @param <X> The represented type.
*
* @since 2.0
*
*/
public interface ManagedType<X> extends Type<X> {
/**
* Return the attributes of the managed type.
* @return attributes of the managed type
*/
Set<Attribute<? super X, ?>> getAttributes();
/**
* Return the attributes declared by the managed type.
* Returns empty set if the managed type has no declared
* attributes.
* @return declared attributes of the managed type
*/
Set<Attribute<X, ?>> getDeclaredAttributes();
/**
* Return the single-valued attribute of the managed
* type that corresponds to the specified name and Java type.
* @param name the name of the represented attribute
* @param type the type of the represented attribute
* @return single-valued attribute with given name and type
* @throws IllegalArgumentException if attribute of the given
* name and type is not present in the managed type
*/
<Y> SingularAttribute<? super X, Y> getSingularAttribute(String name, Class<Y> type);
/**
* Return the single-valued attribute declared by the
* managed type that corresponds to the specified name and
* Java type.
* @param name the name of the represented attribute
* @param type the type of the represented attribute
* @return declared single-valued attribute of the given
* name and type
* @throws IllegalArgumentException if attribute of the given
* name and type is not declared in the managed type
*/
<Y> SingularAttribute<X, Y> getDeclaredSingularAttribute(String name, Class<Y> type);
/**
* Return the single-valued attributes of the managed type.
* Returns empty set if the managed type has no single-valued
* attributes.
* @return single-valued attributes
*/
Set<SingularAttribute<? super X, ?>> getSingularAttributes();
/**
* Return the single-valued attributes declared by the managed
* type.
* Returns empty set if the managed type has no declared
* single-valued attributes.
* @return declared single-valued attributes
*/
Set<SingularAttribute<X, ?>> getDeclaredSingularAttributes();
/**
* Return the Collection-valued attribute of the managed type
* that corresponds to the specified name and Java element type.
* @param name the name of the represented attribute
* @param elementType the element type of the represented
* attribute
* @return CollectionAttribute of the given name and element
* type
* @throws IllegalArgumentException if attribute of the given
* name and type is not present in the managed type
*/
<E> CollectionAttribute<? super X, E> getCollection(String name, Class<E> elementType);
/**
* Return the Collection-valued attribute declared by the
* managed type that corresponds to the specified name and Java
* element type.
* @param name the name of the represented attribute
* @param elementType the element type of the represented
* attribute
* @return declared <code>CollectionAttribute</code> of the given name and
* element type
* @throws IllegalArgumentException if attribute of the given
* name and type is not declared in the managed type
*/
<E> CollectionAttribute<X, E> getDeclaredCollection(String name, Class<E> elementType);
/**
* Return the Set-valued attribute of the managed type that
* corresponds to the specified name and Java element type.
* @param name the name of the represented attribute
* @param elementType the element type of the represented
* attribute
* @return SetAttribute of the given name and element type
* @throws IllegalArgumentException if attribute of the given
* name and type is not present in the managed type
*/
<E> SetAttribute<? super X, E> getSet(String name, Class<E> elementType);
/**
* Return the Set-valued attribute declared by the managed type
* that corresponds to the specified name and Java element type.
* @param name the name of the represented attribute
* @param elementType the element type of the represented
* attribute
* @return declared SetAttribute of the given name and
* element type
* @throws IllegalArgumentException if attribute of the given
* name and type is not declared in the managed type
*/
<E> SetAttribute<X, E> getDeclaredSet(String name, Class<E> elementType);
/**
* Return the List-valued attribute of the managed type that
* corresponds to the specified name and Java element type.
* @param name the name of the represented attribute
* @param elementType the element type of the represented
* attribute
* @return ListAttribute of the given name and element type
* @throws IllegalArgumentException if attribute of the given
* name and type is not present in the managed type
*/
<E> ListAttribute<? super X, E> getList(String name, Class<E> elementType);
/**
* Return the List-valued attribute declared by the managed
* type that corresponds to the specified name and Java
* element type.
* @param name the name of the represented attribute
* @param elementType the element type of the represented
* attribute
* @return declared ListAttribute of the given name and
* element type
* @throws IllegalArgumentException if attribute of the given
* name and type is not declared in the managed type
*/
<E> ListAttribute<X, E> getDeclaredList(String name, Class<E> elementType);
/**
* Return the Map-valued attribute of the managed type that
* corresponds to the specified name and Java key and value
* types.
* @param name the name of the represented attribute
* @param keyType the key type of the represented attribute
* @param valueType the value type of the represented attribute
* @return MapAttribute of the given name and key and value
* types
* @throws IllegalArgumentException if attribute of the given
* name and type is not present in the managed type
*/
<K, V> MapAttribute<? super X, K, V> getMap(String name,
Class<K> keyType,
Class<V> valueType);
/**
* Return the Map-valued attribute declared by the managed
* type that corresponds to the specified name and Java key
* and value types.
* @param name the name of the represented attribute
* @param keyType the key type of the represented attribute
* @param valueType the value type of the represented attribute
* @return declared MapAttribute of the given name and key
* and value types
* @throws IllegalArgumentException if attribute of the given
* name and type is not declared in the managed type
*/
<K, V> MapAttribute<X, K, V> getDeclaredMap(String name,
Class<K> keyType,
Class<V> valueType);
/**
* Return all multi-valued attributes (Collection-, Set-,
* List-, and Map-valued attributes) of the managed type.
* Returns empty set if the managed type has no multi-valued
* attributes.
* @return Collection-, Set-, List-, and Map-valued attributes
*/
Set<PluralAttribute<? super X, ?, ?>> getPluralAttributes();
/**
* Return all multi-valued attributes (Collection-, Set-,
* List-, and Map-valued attributes) declared by the
* managed type.
* Returns empty set if the managed type has no declared
* multi-valued attributes.
* @return declared Collection-, Set-, List-, and Map-valued
* attributes
*/
Set<PluralAttribute<X, ?, ?>> getDeclaredPluralAttributes();
//String-based:
/**
* Return the attribute of the managed
* type that corresponds to the specified name.
* @param name the name of the represented attribute
* @return attribute with given name
* @throws IllegalArgumentException if attribute of the given
* name is not present in the managed type
*/
Attribute<? super X, ?> getAttribute(String name);
/**
* Return the attribute declared by the managed
* type that corresponds to the specified name.
* @param name the name of the represented attribute
* @return attribute with given name
* @throws IllegalArgumentException if attribute of the given
* name is not declared in the managed type
*/
Attribute<X, ?> getDeclaredAttribute(String name);
/**
* Return the single-valued attribute of the managed type that
* corresponds to the specified name.
* @param name the name of the represented attribute
* @return single-valued attribute with the given name
* @throws IllegalArgumentException if attribute of the given
* name is not present in the managed type
*/
SingularAttribute<? super X, ?> getSingularAttribute(String name);
/**
* Return the single-valued attribute declared by the managed
* type that corresponds to the specified name.
* @param name the name of the represented attribute
* @return declared single-valued attribute of the given
* name
* @throws IllegalArgumentException if attribute of the given
* name is not declared in the managed type
*/
SingularAttribute<X, ?> getDeclaredSingularAttribute(String name);
/**
* Return the Collection-valued attribute of the managed type
* that corresponds to the specified name.
* @param name the name of the represented attribute
* @return CollectionAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not present in the managed type
*/
CollectionAttribute<? super X, ?> getCollection(String name);
/**
* Return the Collection-valued attribute declared by the
* managed type that corresponds to the specified name.
* @param name the name of the represented attribute
* @return declared CollectionAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not declared in the managed type
*/
CollectionAttribute<X, ?> getDeclaredCollection(String name);
/**
* Return the Set-valued attribute of the managed type that
* corresponds to the specified name.
* @param name the name of the represented attribute
* @return SetAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not present in the managed type
*/
SetAttribute<? super X, ?> getSet(String name);
/**
* Return the Set-valued attribute declared by the managed type
* that corresponds to the specified name.
* @param name the name of the represented attribute
* @return declared SetAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not declared in the managed type
*/
SetAttribute<X, ?> getDeclaredSet(String name);
/**
* Return the List-valued attribute of the managed type that
* corresponds to the specified name.
* @param name the name of the represented attribute
* @return ListAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not present in the managed type
*/
ListAttribute<? super X, ?> getList(String name);
/**
* Return the List-valued attribute declared by the managed
* type that corresponds to the specified name.
* @param name the name of the represented attribute
* @return declared ListAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not declared in the managed type
*/
ListAttribute<X, ?> getDeclaredList(String name);
/**
* Return the Map-valued attribute of the managed type that
* corresponds to the specified name.
* @param name the name of the represented attribute
* @return MapAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not present in the managed type
*/
MapAttribute<? super X, ?, ?> getMap(String name);
/**
* Return the Map-valued attribute declared by the managed
* type that corresponds to the specified name.
* @param name the name of the represented attribute
* @return declared MapAttribute of the given name
* @throws IllegalArgumentException if attribute of the given
* name is not declared in the managed type
*/
MapAttribute<X, ?, ?> getDeclaredMap(String name);
}
5.1.4. IdentifiableType Interface
package jakarta.persistence.metamodel;
import java.util.Set;
/**
* Instances of the type <code>IdentifiableType</code> represent entity or
* mapped superclass types.
*
* @param <X> The represented entity or mapped superclass type.
*
* @since 2.0
*
*/
public interface IdentifiableType<X> extends ManagedType<X> {
/**
* Return the attribute that corresponds to the id attribute of
* the entity or mapped superclass.
* @param type the type of the represented id attribute
* @return id attribute
* @throws IllegalArgumentException if id attribute of the given
* type is not present in the identifiable type or if
* the identifiable type has an id class
*/
<Y> SingularAttribute<? super X, Y> getId(Class<Y> type);
/**
* Return the attribute that corresponds to the id attribute
* declared by the entity or mapped superclass.
* @param type the type of the represented declared
* id attribute
* @return declared id attribute
* @throws IllegalArgumentException if id attribute of the given
* type is not declared in the identifiable type or if
* the identifiable type has an id class
*/
<Y> SingularAttribute<X, Y> getDeclaredId(Class<Y> type);
/**
* Return the attribute that corresponds to the version
* attribute of the entity or mapped superclass.
* @param type the type of the represented version attribute
* @return version attribute
* @throws IllegalArgumentException if version attribute of the
* given type is not present in the identifiable type
*/
<Y> SingularAttribute<? super X, Y> getVersion(Class<Y> type);
/**
* Return the attribute that corresponds to the version
* attribute declared by the entity or mapped superclass.
* @param type the type of the represented declared version
* attribute
* @return declared version attribute
* @throws IllegalArgumentException if version attribute of the
* type is not declared in the identifiable type
*/
<Y> SingularAttribute<X, Y> getDeclaredVersion(Class<Y> type);
/**
* Return the identifiable type that corresponds to the most
* specific mapped superclass or entity extended by the entity
* or mapped superclass.
* @return supertype of identifiable type or null if no
* such supertype
*/
IdentifiableType<? super X> getSupertype();
/**
* Whether the identifiable type has a single id attribute.
* Returns true for a simple id or embedded id; returns false
* for an idclass.
* @return boolean indicating whether the identifiable
* type has a single id attribute
*/
boolean hasSingleIdAttribute();
/**
* Whether the identifiable type has a version attribute.
* @return boolean indicating whether the identifiable
* type has a version attribute
*/
boolean hasVersionAttribute();
/**
* Return the attributes corresponding to the id class of the
* identifiable type.
* @return id attributes
* @throws IllegalArgumentException if the identifiable type
* does not have an id class
*/
Set<SingularAttribute<? super X, ?>> getIdClassAttributes();
/**
* Return the type that represents the type of the id.
* @return type of id
*/
Type<?> getIdType();
}
5.1.5. EntityType Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>EntityType</code> represent entity types.
*
* @param <X> The represented entity type.
*
* @since 2.0
*
*/
public interface EntityType<X>
extends IdentifiableType<X>, Bindable<X>{
/**
* Return the entity name.
* @return entity name
*/
String getName();
}
5.1.6. EmbeddableType Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>EmbeddableType</code> represent embeddable types.
*
* @param <X> The represented type.
*
* @since 2.0
*
*/
public interface EmbeddableType<X> extends ManagedType<X> {}
5.1.7. MappedSuperclassType Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>MappedSuperclassType</code> represent mapped
* superclass types.
*
* @param <X> The represented entity type
* @since 2.0
*/
public interface MappedSuperclassType<X> extends IdentifiableType<X> {}
5.1.8. BasicType Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>BasicType</code> represent basic types (including
* temporal and enumerated types).
*
* @param <X> The type of the represented basic type
*
* @since 2.0
*/
public interface BasicType<X> extends Type<X> {}
5.1.9. Bindable Interface
package jakarta.persistence.metamodel;
import jakarta.persistence.criteria.Path;
/**
* Instances of the type <code>Bindable</code> represent object or attribute types
* that can be bound into a {@link Path Path}.
*
* @param <T> The type of the represented object or attribute
*
* @since 2.0
*
*/
public interface Bindable<T> {
public static enum BindableType {
/**
* Single-valued attribute type.
*
* @see SingularAttribute
*/
SINGULAR_ATTRIBUTE,
/**
* Multivalued attribute type, that is, a collection.
*
* @see PluralAttribute
*/
PLURAL_ATTRIBUTE,
/**
* Entity type.
*
* @see EntityType
*/
ENTITY_TYPE
}
/**
* Return the bindable type of the represented object.
* @return bindable type
*/
BindableType getBindableType();
/**
* Return the Java type of the represented object.
* If the bindable type of the object is <code>PLURAL_ATTRIBUTE</code>,
* the Java element type is returned. If the bindable type is
* <code>SINGULAR_ATTRIBUTE</code> or <code>ENTITY_TYPE</code>,
* the Java type of the
* represented entity or attribute is returned.
* @return Java type
*/
Class<T> getBindableJavaType();
}
5.1.10. Attribute Interface
package jakarta.persistence.metamodel;
/**
* Represents an attribute of a Java type.
*
* @param <X> The represented type that contains the attribute
* @param <Y> The type of the represented attribute
*
* @since 2.0
*/
public interface Attribute<X, Y> {
public static enum PersistentAttributeType {
/** Many-to-one association */
MANY_TO_ONE,
/** One-to-one association */
ONE_TO_ONE,
/** Basic attribute */
BASIC,
/** Embeddable class attribute */
EMBEDDED,
/** Many-to-many association */
MANY_TO_MANY,
/** One-to-many association */
ONE_TO_MANY,
/** Element collection */
ELEMENT_COLLECTION
}
/**
* Return the name of the attribute.
* @return name
*/
String getName();
/**
* Return the persistent attribute type for the attribute.
* @return persistent attribute type
*/
PersistentAttributeType getPersistentAttributeType();
/**
* Return the managed type representing the type in which
* the attribute was declared.
* @return declaring type
*/
ManagedType<X> getDeclaringType();
/**
* Return the Java type of the represented attribute.
* @return Java type
*/
Class<Y> getJavaType();
/**
* Return the <code>java.lang.reflect.Member</code> for the represented
* attribute.
* @return corresponding <code>java.lang.reflect.Member</code>
*/
java.lang.reflect.Member getJavaMember();
/**
* Is the attribute an association.
* @return boolean indicating whether the attribute
* corresponds to an association
*/
boolean isAssociation();
/**
* Is the attribute collection-valued (represents a Collection,
* Set, List, or Map).
* @return boolean indicating whether the attribute is
* collection-valued
*/
boolean isCollection();
}
5.1.11. SingularAttribute Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>SingularAttribute</code> represents persistent
* single-valued properties or fields.
*
* @param <X> The type containing the represented attribute
* @param <T> The type of the represented attribute
*
* @since 2.0
*/
public interface SingularAttribute<X, T>
extends Attribute<X, T>, Bindable<T> {
/**
* Is the attribute an id attribute. This method will return
* true if the attribute is an attribute that corresponds to
* a simple id, an embedded id, or an attribute of an id class.
* @return boolean indicating whether the attribute is an id
*/
boolean isId();
/**
* Is the attribute a version attribute.
* @return boolean indicating whether the attribute is
* a version attribute
*/
boolean isVersion();
/**
* Can the attribute be null.
* @return boolean indicating whether the attribute can
* be null
*/
boolean isOptional();
/**
* Return the type that represents the type of the attribute.
* @return type of attribute
*/
Type<T> getType();
}
5.1.12. PluralAttribute Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>PluralAttribute</code> represent
* persistent collection-valued attributes.
*
* @param <X> The type the represented collection belongs to
* @param <C> The type of the represented collection
* @param <E> The element type of the represented collection
*
* @since 2.0
*/
public interface PluralAttribute<X, C, E>
extends Attribute<X, C>, Bindable<E> {
public static enum CollectionType {
/** Collection-valued attribute */
COLLECTION,
/** Set-valued attribute */
SET,
/** List-valued attribute */
LIST,
/** Map-valued attribute */
MAP
}
/**
* Return the collection type.
* @return collection type
*/
CollectionType getCollectionType();
/**
* Return the type representing the element type of the
* collection.
* @return element type
*/
Type<E> getElementType();
}
5.1.13. CollectionAttribute Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>CollectionAttribute</code> represent persistent
* <code>java.util.Collection</code>-valued attributes.
*
* @param <X> The type the represented Collection belongs to
* @param <E> The element type of the represented Collection
*
* @since 2.0
*
*/
public interface CollectionAttribute<X, E>
extends PluralAttribute<X, java.util.Collection<E>, E> {}
5.1.14. SetAttribute Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>SetAttribute</code> represent
* persistent <code>java.util.Set</code>-valued attributes.
*
* @param <X> The type the represented Set belongs to
* @param <E> The element type of the represented Set
*
* @since 2.0
*/
public interface SetAttribute<X, E>
extends PluralAttribute<X, java.util.Set<E>, E> {}
5.1.15. ListAttribute Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>ListAttribute</code> represent persistent
* <code>java.util.List</code>-valued attributes.
*
* @param <X> The type the represented List belongs to
* @param <E> The element type of the represented List
*
* @since 2.0
*
*/
public interface ListAttribute<X, E>
extends PluralAttribute<X, java.util.List<E>, E> {}
5.1.16. MapAttribute Interface
package jakarta.persistence.metamodel;
/**
* Instances of the type <code>MapAttribute</code> represent
* persistent <code>java.util.Map</code>-valued attributes.
*
* @param <X> The type the represented Map belongs to
* @param <K> The type of the key of the represented Map
* @param <V> The type of the value of the represented Map
*
* @since 2.0
*
*/
public interface MapAttribute<X, K, V>
extends PluralAttribute<X, java.util.Map<K, V>, V> {
/**
* Return the Java type of the map key.
* @return Java key type
*/
Class<K> getKeyJavaType();
/**
* Return the type representing the key type of the map.
* @return type representing key type
*/
Type<K> getKeyType();
}
5.1.17. StaticMetamodel Annotation
package jakarta.persistence.metamodel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* The <code>StaticMetamodel</code> annotation specifies that the class
* is a metamodel class that represents the entity, mapped
* superclass, or embeddable class designated by the value
* element.
*
* @since 2.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StaticMetamodel {
/**
* Class being modelled by the annotated class.
*/
Class<?> value();
}
6. Criteria API
The Jakarta Persistence Criteria API is used to define queries through the construction of object-based query definition objects, rather than use of the string-based approach of the Jakarta Persistence query language described in Chapter 4.
This chapter provides the full definition of the Criteria API.
6.1. Overview
The Jakarta Persistence Criteria API, like the Jakarta Persistence query language is based on the abstract persistence schema of entities, their embedded objects, and their relationships as its data model. This abstract persistence schema is materialized in the form of metamodel objects over which the Criteria API operates. The semantics of criteria queries are designed to reflect those of Jakarta Persistence query language queries.
The syntax of the Criteria API is designed to allow the construction of an object-based query “graph”, whose nodes correspond to the semantic query elements.
Java language variables can be used to reference individual nodes in a criteria query object as it is constructed and/or modified. Such variables, when used to refer to the entities and embeddable types that constitute the query domain, play a role analogous to that of the identification variables of the Jakarta Persistence query language.
These concepts are further described in the
sections that follow. The metamodel on which criteria queries are based
is presented in Chapter 5.
The static metamodel classes that can be used in constructing
strongly-typed criteria queries are described in Section 6.2. The
jakarta.persistence.criteria
interfaces are presented in Section 6.3. Sections
Section 6.4 through Section 6.8 describe the
construction and modification of criteria query objects. Additional
requirements on the persistence provider are described in Section 6.9.
6.2. Metamodel
Jakarta Persistence criteria queries are based
on a metamodel of the managed classes of the persistence unit. Static
metamodel classes corresponding to the managed classes of the
persistence unit can be generated by means of an annotation processor or
can be created by the application developer, or the metamodel can be
accessed dynamically by use of the
jakarta.persistence.metamodel.Metamodel
interface. The getMetamodel
method of the EntityManagerFactory
or EntityManager
interface can be
used to obtain a Metamodel
instance.
6.2.1. Static Metamodel Classes
In the typical case, an annotation processor is expected to be used to produce static metamodel classes corresponding to the entities, mapped superclasses, and embeddable classes in the persistence unit. A static metamodel class models the persistent state and relationships of the corresponding managed class. For portability, an annotation processor should generate a canonical metamodel as defined below.
6.2.1.1. Canonical Metamodel
This specification defines as follows a canonical metamodel and the structure of canonical metamodel classes.
For every managed class in the persistence unit, a corresponding metamodel class is produced as follows:
-
For each managed class
X
in packagep
, a metamodel classX_
in packagep
is created.[82] -
The name of the metamodel class is derived from the name of the managed class by appending “_” to the name of the managed class.
-
The metamodel class
X_
must be annotated with thejakarta.persistence.StaticMetamodel
annotation[83]. -
If the managed class
X
extends another classS
, whereS
is the most derived managed class (i.e., entity or mapped superclass) extended byX
, then the metamodel classX_
must extend the metamodel classS_
created forS
. -
The metamodel class must contain a field declaration as follows:
public static volatile jakarta.persistence.metamodel.T<X> class_;
where
T
isEntityType
,EmbeddableType
, orMappedSuperclassType
depending on whetherX
is an entity, embeddable, or mapped superclass. -
For every persistent attribute
y
declared by classX
, the metamodel class must contain a field declaration as follows:public static final String Y = "y";
where the field name
Y
is obtained by transforming each lowercase character in the attribute namey
to uppercase, and inserting an underscore if the character following the transformed character is uppercase. -
For every persistent non-collection-valued attribute
y
declared by classX
, where the type ofy
isY
, the metamodel class must contain a declaration as follows:public static volatile SingularAttribute<X, Y> y;
-
For every persistent collection-valued attribute
z
declared by classX
, where the element type ofz
isZ
, the metamodel class must contain a declaration as follows:-
if the collection type of
z
isjava.util.Collection
, thenpublic static volatile CollectionAttribute<X, Z> z;
-
if the collection type of
z
isjava.util.Set
, thenpublic static volatile SetAttribute<X, Z> z;
-
if the collection type of
z
isjava.util.List
, thenpublic static volatile ListAttribute<X, Z> z;
-
if the collection type of
z
isjava.util.Map
, thenpublic static volatile MapAttribute<X, K, Z> z;
where
K
is the type of the key of the map in classX
-
-
For every named query, named entity graph, or SQL result set mapping with name
"n"
declared by annotations of the classX
, the metamodel class must contain a declaration as follows:public static final String T_N = "n";
where The prefix
T
is the stringQUERY
,GRAPH
, orMAPPING
, as appropriate, depending on the annotation type, and the suffixN
is obtained by transforming each lowercase character in the namen
to uppercase, inserting an underscore if the character following the transformed character is uppercase, and then replacing each character which is not a legal Java identifier character with an underscore. -
For every named query with name
"n"
and query result classR
declared by annotations of the classX
, the metamodel class must contain a declaration as follows:public static volatile TypedQueryReference<R> _n_;
-
For every named entity graph with name
"n"
declared by annotations of the classX
, the metamodel class must contain a declaration as follows:public static volatile EntityGraph<X> _n;
Import statements must be included for the needed
jakarta.persistence.metamodel
types as appropriate (e.g.,jakarta.persistence.metamodel.SingularAttribute
,jakarta.persistence.metamodel.CollectionAttribute
,jakarta.persistence.metamodel.SetAttribute
,jakarta.persistence.metamodel.ListAttribute
,jakarta.persistence.metamodel.MapAttribute
) and all classesX
,Y
,Z
,R
, andK
.
Implementations of this specification are not required to support the use of non-canonical metamodel classes. Applications that use non-canonical metamodel classes will not be portable. |
6.2.1.2. Example
Assume the Order
entity below.
package com.example;
import java.util.Set;
import java.math.BigDecimal;
@Entity
public class Order {
@Id
Integer orderId;
@ManyToOne
Customer customer;
@OneToMany
Set<Item> lineItems;
Address shippingAddress;
BigDecimal totalCost;
// ...
}
The corresponding canonical metamodel class,
Order
, is as follows:
package com.example;
import java.math.BigDecimal;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.SetAttribute;
import jakarta.persistence.metamodel.StaticMetamodel;
@StaticMetamodel(Order.class)
public class Order {
public static volatile SingularAttribute<Order, Integer> orderId;
public static volatile SingularAttribute<Order, Customer> customer;
public static volatile SetAttribute<Order, Item> lineItems;
public static volatile SingularAttribute<Order, Address> shippingAddress;
public static volatile SingularAttribute<Order, BigDecimal> totalCost;
}
6.2.2. Bootstrapping
When the entity manager factory for a persistence unit is created, it is the responsibility of the persistence provider to initialize the state of the metamodel classes of the persistence unit. Any generated metamodel classes must be accessible on the classpath.
Persistence providers must support the use of canonical metamodel classes. Persistence providers may, but are not required to, support the use of non-canonical metamodel classes.
6.3. Criteria API Interfaces
6.3.1. CriteriaBuilder Interface
package jakarta.persistence.criteria;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import jakarta.persistence.Tuple;
/**
* Used to construct criteria queries, compound selections,
* expressions, predicates, orderings.
*
* <p> Note that <code>Predicate</code> is used instead of <code>Expression<Boolean></code>
* in this API in order to work around the fact that Java
* generics are not compatible with varags.
*
* @since 2.0
*/
public interface CriteriaBuilder {
/**
* Create a <code>CriteriaQuery</code> object.
* @return criteria query object
*/
CriteriaQuery<Object> createQuery();
/**
* Create a <code>CriteriaQuery</code> object with the specified result
* type.
* @param resultClass type of the query result
* @return criteria query object
*/
<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
/**
* Create a <code>CriteriaQuery</code> object that returns a tuple of
* objects as its result.
* @return criteria query object
*/
CriteriaQuery<Tuple> createTupleQuery();
// methods to construct queries for bulk updates and deletes:
/**
* Create a <code>CriteriaUpdate</code> query object to perform a bulk update operation.
* @param targetEntity target type for update operation
* @return the query object
* @since 2.1
*/
<T> CriteriaUpdate<T> createCriteriaUpdate(Class<T> targetEntity);
/**
* Create a <code>CriteriaDelete</code> query object to perform a bulk delete operation.
* @param targetEntity target type for delete operation
* @return the query object
* @since 2.1
*/
<T> CriteriaDelete<T> createCriteriaDelete(Class<T> targetEntity);
// selection construction methods:
/**
* Create a selection item corresponding to a constructor.
* This method is used to specify a constructor that will be
* applied to the results of the query execution. If the
* constructor is for an entity class, the resulting entities
* will be in the new state after the query is executed.
* @param resultClass class whose instance is to be constructed
* @param selections arguments to the constructor
* @return compound selection item
* @throws IllegalArgumentException if an argument is a
* tuple- or array-valued selection item
*/
<Y> CompoundSelection<Y> construct(Class<Y> resultClass, Selection<?>... selections);
/**
* Create a tuple-valued selection item.
* @param selections selection items
* @return tuple-valued compound selection
* @throws IllegalArgumentException if an argument is a
* tuple- or array-valued selection item
*/
CompoundSelection<Tuple> tuple(Selection<?>... selections);
/**
* Create a tuple-valued selection item.
* @param selections list of selection items
* @return tuple-valued compound selection
* @throws IllegalArgumentException if an argument is a
* tuple- or array-valued selection item
*/
CompoundSelection<Tuple> tuple(List<Selection<?>> selections);
/**
* Create an array-valued selection item.
* @param selections selection items
* @return array-valued compound selection
* @throws IllegalArgumentException if an argument is a
* tuple- or array-valued selection item
*/
CompoundSelection<Object[]> array(Selection<?>... selections);
/**
* Create an array-valued selection item.
* @param selections list of selection items
* @return array-valued compound selection
* @throws IllegalArgumentException if an argument is a
* tuple- or array-valued selection item
*/
CompoundSelection<Object[]> array(List<Selection<?>> selections);
//ordering:
/**
* Create an ordering by the ascending value of the expression.
* @param x expression used to define the ordering
* @return ascending ordering corresponding to the expression
*/
Order asc(Expression<?> x);
/**
* Create an ordering by the descending value of the expression.
* @param x expression used to define the ordering
* @return descending ordering corresponding to the expression
*/
Order desc(Expression<?> x);
//aggregate functions:
/**
* Create an aggregate expression applying the avg operation.
* @param x expression representing input value to avg operation
* @return avg expression
*/
<N extends Number> Expression<Double> avg(Expression<N> x);
/**
* Create an aggregate expression applying the sum operation.
* @param x expression representing input value to sum operation
* @return sum expression
*/
<N extends Number> Expression<N> sum(Expression<N> x);
/**
* Create an aggregate expression applying the sum operation to an
* Integer-valued expression, returning a Long result.
* @param x expression representing input value to sum operation
* @return sum expression
*/
Expression<Long> sumAsLong(Expression<Integer> x);
/**
* Create an aggregate expression applying the sum operation to a
* Float-valued expression, returning a Double result.
* @param x expression representing input value to sum operation
* @return sum expression
*/
Expression<Double> sumAsDouble(Expression<Float> x);
/**
* Create an aggregate expression applying the numerical max
* operation.
* @param x expression representing input value to max operation
* @return max expression
*/
<N extends Number> Expression<N> max(Expression<N> x);
/**
* Create an aggregate expression applying the numerical min
* operation.
* @param x expression representing input value to min operation
* @return min expression
*/
<N extends Number> Expression<N> min(Expression<N> x);
/**
* Create an aggregate expression for finding the greatest of
* the values (strings, dates, etc).
* @param x expression representing input value to greatest
* operation
* @return greatest expression
*/
<X extends Comparable<? super X>> Expression<X> greatest(Expression<X> x);
/**
* Create an aggregate expression for finding the least of
* the values (strings, dates, etc).
* @param x expression representing input value to least
* operation
* @return least expression
*/
<X extends Comparable<? super X>> Expression<X> least(Expression<X> x);
/**
* Create an aggregate expression applying the count operation.
* @param x expression representing input value to count
* operation
* @return count expression
*/
Expression<Long> count(Expression<?> x);
/**
* Create an aggregate expression applying the count distinct
* operation.
* @param x expression representing input value to
* count distinct operation
* @return count distinct expression
*/
Expression<Long> countDistinct(Expression<?> x);
//subqueries:
/**
* Create a predicate testing the existence of a subquery result.
* @param subquery subquery whose result is to be tested
* @return exists predicate
*/
Predicate exists(Subquery<?> subquery);
/**
* Create an all expression over the subquery results.
* @param subquery subquery
* @return all expression
*/
<Y> Expression<Y> all(Subquery<Y> subquery);
/**
* Create a some expression over the subquery results.
* This expression is equivalent to an <code>any</code> expression.
* @param subquery subquery
* @return some expression
*/
<Y> Expression<Y> some(Subquery<Y> subquery);
/**
* Create an any expression over the subquery results.
* This expression is equivalent to a <code>some</code> expression.
* @param subquery subquery
* @return any expression
*/
<Y> Expression<Y> any(Subquery<Y> subquery);
//boolean functions:
/**
* Create a conjunction of the given boolean expressions.
* @param x boolean expression
* @param y boolean expression
* @return and predicate
*/
Predicate and(Expression<Boolean> x, Expression<Boolean> y);
/**
* Create a conjunction of the given restriction predicates.
* A conjunction of zero predicates is true.
* @param restrictions zero or more restriction predicates
* @return and predicate
*/
Predicate and(Predicate... restrictions);
/**
* Create a disjunction of the given boolean expressions.
* @param x boolean expression
* @param y boolean expression
* @return or predicate
*/
Predicate or(Expression<Boolean> x, Expression<Boolean> y);
/**
* Create a disjunction of the given restriction predicates.
* A disjunction of zero predicates is false.
* @param restrictions zero or more restriction predicates
* @return or predicate
*/
Predicate or(Predicate... restrictions);
/**
* Create a negation of the given restriction.
* @param restriction restriction expression
* @return not predicate
*/
Predicate not(Expression<Boolean> restriction);
/**
* Create a conjunction (with zero conjuncts).
* A conjunction with zero conjuncts is true.
* @return and predicate
*/
Predicate conjunction();
/**
* Create a disjunction (with zero disjuncts).
* A disjunction with zero disjuncts is false.
* @return or predicate
*/
Predicate disjunction();
//turn Expression<Boolean> into a Predicate
//useful for use with varargs methods
/**
* Create a predicate testing for a true value.
* @param x expression to be tested
* @return predicate
*/
Predicate isTrue(Expression<Boolean> x);
/**
* Create a predicate testing for a false value.
* @param x expression to be tested
* @return predicate
*/
Predicate isFalse(Expression<Boolean> x);
//null tests:
/**
* Create a predicate to test whether the expression is null.
* @param x expression
* @return is-null predicate
*/
Predicate isNull(Expression<?> x);
/**
* Create a predicate to test whether the expression is not null.
* @param x expression
* @return is-not-null predicate
*/
Predicate isNotNull(Expression<?> x);
//equality:
/**
* Create a predicate for testing the arguments for equality.
* @param x expression
* @param y expression
* @return equality predicate
*/
Predicate equal(Expression<?> x, Expression<?> y);
/**
* Create a predicate for testing the arguments for equality.
* @param x expression
* @param y object
* @return equality predicate
*/
Predicate equal(Expression<?> x, Object y);
/**
* Create a predicate for testing the arguments for inequality.
* @param x expression
* @param y expression
* @return inequality predicate
*/
Predicate notEqual(Expression<?> x, Expression<?> y);
/**
* Create a predicate for testing the arguments for inequality.
* @param x expression
* @param y object
* @return inequality predicate
*/
Predicate notEqual(Expression<?> x, Object y);
//comparisons for generic (non-numeric) operands:
/**
* Create a predicate for testing whether the first argument is
* greater than the second.
* @param x expression
* @param y expression
* @return greater-than predicate
*/
<Y extends Comparable<? super Y>> Predicate greaterThan(Expression<? extends Y> x, Expression<? extends Y> y);
/**
* Create a predicate for testing whether the first argument is
* greater than the second.
* @param x expression
* @param y value
* @return greater-than predicate
*/
<Y extends Comparable<? super Y>> Predicate greaterThan(Expression<? extends Y> x, Y y);
/**
* Create a predicate for testing whether the first argument is
* greater than or equal to the second.
* @param x expression
* @param y expression
* @return greater-than-or-equal predicate
*/
<Y extends Comparable<? super Y>> Predicate greaterThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y);
/**
* Create a predicate for testing whether the first argument is
* greater than or equal to the second.
* @param x expression
* @param y value
* @return greater-than-or-equal predicate
*/
<Y extends Comparable<? super Y>> Predicate greaterThanOrEqualTo(Expression<? extends Y> x, Y y);
/**
* Create a predicate for testing whether the first argument is
* less than the second.
* @param x expression
* @param y expression
* @return less-than predicate
*/
<Y extends Comparable<? super Y>> Predicate lessThan(Expression<? extends Y> x, Expression<? extends Y> y);
/**
* Create a predicate for testing whether the first argument is
* less than the second.
* @param x expression
* @param y value
* @return less-than predicate
*/
<Y extends Comparable<? super Y>> Predicate lessThan(Expression<? extends Y> x, Y y);
/**
* Create a predicate for testing whether the first argument is
* less than or equal to the second.
* @param x expression
* @param y expression
* @return less-than-or-equal predicate
*/
<Y extends Comparable<? super Y>> Predicate lessThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y);
/**
* Create a predicate for testing whether the first argument is
* less than or equal to the second.
* @param x expression
* @param y value
* @return less-than-or-equal predicate
*/
<Y extends Comparable<? super Y>> Predicate lessThanOrEqualTo(Expression<? extends Y> x, Y y);
/**
* Create a predicate for testing whether the first argument is
* between the second and third arguments in value.
* @param v expression
* @param x expression
* @param y expression
* @return between predicate
*/
<Y extends Comparable<? super Y>> Predicate between(Expression<? extends Y> v, Expression<? extends Y> x, Expression<? extends Y> y);
/**
* Create a predicate for testing whether the first argument is
* between the second and third arguments in value.
* @param v expression
* @param x value
* @param y value
* @return between predicate
*/
<Y extends Comparable<? super Y>> Predicate between(Expression<? extends Y> v, Y x, Y y);
//comparisons for numeric operands:
/**
* Create a predicate for testing whether the first argument is
* greater than the second.
* @param x expression
* @param y expression
* @return greater-than predicate
*/
Predicate gt(Expression<? extends Number> x, Expression<? extends Number> y);
/**
* Create a predicate for testing whether the first argument is
* greater than the second.
* @param x expression
* @param y value
* @return greater-than predicate
*/
Predicate gt(Expression<? extends Number> x, Number y);
/**
* Create a predicate for testing whether the first argument is
* greater than or equal to the second.
* @param x expression
* @param y expression
* @return greater-than-or-equal predicate
*/
Predicate ge(Expression<? extends Number> x, Expression<? extends Number> y);
/**
* Create a predicate for testing whether the first argument is
* greater than or equal to the second.
* @param x expression
* @param y value
* @return greater-than-or-equal predicate
*/
Predicate ge(Expression<? extends Number> x, Number y);
/**
* Create a predicate for testing whether the first argument is
* less than the second.
* @param x expression
* @param y expression
* @return less-than predicate
*/
Predicate lt(Expression<? extends Number> x, Expression<? extends Number> y);
/**
* Create a predicate for testing whether the first argument is
* less than the second.
* @param x expression
* @param y value
* @return less-than predicate
*/
Predicate lt(Expression<? extends Number> x, Number y);
/**
* Create a predicate for testing whether the first argument is
* less than or equal to the second.
* @param x expression
* @param y expression
* @return less-than-or-equal predicate
*/
Predicate le(Expression<? extends Number> x, Expression<? extends Number> y);
/**
* Create a predicate for testing whether the first argument is
* less than or equal to the second.
* @param x expression
* @param y value
* @return less-than-or-equal predicate
*/
Predicate le(Expression<? extends Number> x, Number y);
//numerical operations:
/**
* Create an expression that returns the arithmetic negation
* of its argument.
* @param x expression
* @return arithmetic negation
*/
<N extends Number> Expression<N> neg(Expression<N> x);
/**
* Create an expression that returns the absolute value
* of its argument.
* @param x expression
* @return absolute value
*/
<N extends Number> Expression<N> abs(Expression<N> x);
/**
* Create an expression that returns the sum
* of its arguments.
* @param x expression
* @param y expression
* @return sum
*/
<N extends Number> Expression<N> sum(Expression<? extends N> x, Expression<? extends N> y);
/**
* Create an expression that returns the sum
* of its arguments.
* @param x expression
* @param y value
* @return sum
*/
<N extends Number> Expression<N> sum(Expression<? extends N> x, N y);
/**
* Create an expression that returns the sum
* of its arguments.
* @param x value
* @param y expression
* @return sum
*/
<N extends Number> Expression<N> sum(N x, Expression<? extends N> y);
/**
* Create an expression that returns the product
* of its arguments.
* @param x expression
* @param y expression
* @return product
*/
<N extends Number> Expression<N> prod(Expression<? extends N> x, Expression<? extends N> y);
/**
* Create an expression that returns the product
* of its arguments.
* @param x expression
* @param y value
* @return product
*/
<N extends Number> Expression<N> prod(Expression<? extends N> x, N y);
/**
* Create an expression that returns the product
* of its arguments.
* @param x value
* @param y expression
* @return product
*/
<N extends Number> Expression<N> prod(N x, Expression<? extends N> y);
/**
* Create an expression that returns the difference
* between its arguments.
* @param x expression
* @param y expression
* @return difference
*/
<N extends Number> Expression<N> diff(Expression<? extends N> x, Expression<? extends N> y);
/**
* Create an expression that returns the difference
* between its arguments.
* @param x expression
* @param y value
* @return difference
*/
<N extends Number> Expression<N> diff(Expression<? extends N> x, N y);
/**
* Create an expression that returns the difference
* between its arguments.
* @param x value
* @param y expression
* @return difference
*/
<N extends Number> Expression<N> diff(N x, Expression<? extends N> y);
/**
* Create an expression that returns the quotient
* of its arguments.
* @param x expression
* @param y expression
* @return quotient
*/
Expression<Number> quot(Expression<? extends Number> x, Expression<? extends Number> y);
/**
* Create an expression that returns the quotient
* of its arguments.
* @param x expression
* @param y value
* @return quotient
*/
Expression<Number> quot(Expression<? extends Number> x, Number y);
/**
* Create an expression that returns the quotient
* of its arguments.
* @param x value
* @param y expression
* @return quotient
*/
Expression<Number> quot(Number x, Expression<? extends Number> y);
/**
* Create an expression that returns the modulus
* of its arguments.
* @param x expression
* @param y expression
* @return modulus
*/
Expression<Integer> mod(Expression<Integer> x, Expression<Integer> y);
/**
* Create an expression that returns the modulus
* of its arguments.
* @param x expression
* @param y value
* @return modulus
*/
Expression<Integer> mod(Expression<Integer> x, Integer y);
/**
* Create an expression that returns the modulus
* of its arguments.
* @param x value
* @param y expression
* @return modulus
*/
Expression<Integer> mod(Integer x, Expression<Integer> y);
/**
* Create an expression that returns the square root
* of its argument.
* @param x expression
* @return square root
*/
Expression<Double> sqrt(Expression<? extends Number> x);
//typecasts:
/**
* Typecast. Returns same expression object.
* @param number numeric expression
* @return Expression<Long>
*/
Expression<Long> toLong(Expression<? extends Number> number);
/**
* Typecast. Returns same expression object.
* @param number numeric expression
* @return Expression<Integer>
*/
Expression<Integer> toInteger(Expression<? extends Number> number);
/**
* Typecast. Returns same expression object.
* @param number numeric expression
* @return Expression<Float>
*/
Expression<Float> toFloat(Expression<? extends Number> number);
/**
* Typecast. Returns same expression object.
* @param number numeric expression
* @return Expression<Double>
*/
Expression<Double> toDouble(Expression<? extends Number> number);
/**
* Typecast. Returns same expression object.
* @param number numeric expression
* @return Expression<BigDecimal>
*/
Expression<BigDecimal> toBigDecimal(Expression<? extends Number> number);
/**
* Typecast. Returns same expression object.
* @param number numeric expression
* @return Expression<BigInteger>
*/
Expression<BigInteger> toBigInteger(Expression<? extends Number> number);
/**
* Typecast. Returns same expression object.
* @param character expression
* @return Expression<String>
*/
Expression<String> toString(Expression<Character> character);
//literals:
/**
* Create an expression for a literal.
* @param value value represented by the expression
* @return expression literal
* @throws IllegalArgumentException if value is null
*/
<T> Expression<T> literal(T value);
/**
* Create an expression for a null literal with the given type.
* @param resultClass type of the null literal
* @return null expression literal
*/
<T> Expression<T> nullLiteral(Class<T> resultClass);
//parameters:
/**
* Create a parameter expression.
* @param paramClass parameter class
* @return parameter expression
*/
<T> ParameterExpression<T> parameter(Class<T> paramClass);
/**
* Create a parameter expression with the given name.
* @param paramClass parameter class
* @param name name that can be used to refer to
* the parameter
* @return parameter expression
*/
<T> ParameterExpression<T> parameter(Class<T> paramClass, String name);
//collection operations:
/**
* Create a predicate that tests whether a collection is empty.
* @param collection expression
* @return is-empty predicate
*/
<C extends Collection<?>> Predicate isEmpty(Expression<C> collection);
/**
* Create a predicate that tests whether a collection is
* not empty.
* @param collection expression
* @return is-not-empty predicate
*/
<C extends Collection<?>> Predicate isNotEmpty(Expression<C> collection);
/**
* Create an expression that tests the size of a collection.
* @param collection expression
* @return size expression
*/
<C extends java.util.Collection<?>> Expression<Integer> size(Expression<C> collection);
/**
* Create an expression that tests the size of a collection.
* @param collection collection
* @return size expression
*/
<C extends Collection<?>> Expression<Integer> size(C collection);
/**
* Create a predicate that tests whether an element is
* a member of a collection.
* If the collection is empty, the predicate will be false.
* @param elem element expression
* @param collection expression
* @return is-member predicate
*/
<E, C extends Collection<E>> Predicate isMember(Expression<E> elem, Expression<C> collection);
/**
* Create a predicate that tests whether an element is
* a member of a collection.
* If the collection is empty, the predicate will be false.
* @param elem element
* @param collection expression
* @return is-member predicate
*/
<E, C extends Collection<E>> Predicate isMember(E elem, Expression<C> collection);
/**
* Create a predicate that tests whether an element is
* not a member of a collection.
* If the collection is empty, the predicate will be true.
* @param elem element expression
* @param collection expression
* @return is-not-member predicate
*/
<E, C extends Collection<E>> Predicate isNotMember(Expression<E> elem, Expression<C> collection);
/**
* Create a predicate that tests whether an element is
* not a member of a collection.
* If the collection is empty, the predicate will be true.
* @param elem element
* @param collection expression
* @return is-not-member predicate
*/
<E, C extends Collection<E>> Predicate isNotMember(E elem, Expression<C> collection);
//get the values and keys collections of the Map, which may then
//be passed to size(), isMember(), isEmpty(), etc
/**
* Create an expression that returns the values of a map.
* @param map map
* @return collection expression
*/
<V, M extends Map<?, V>> Expression<Collection<V>> values(M map);
/**
* Create an expression that returns the keys of a map.
* @param map map
* @return set expression
*/
<K, M extends Map<K, ?>> Expression<Set<K>> keys(M map);
//string functions:
/**
* Create a predicate for testing whether the expression
* satisfies the given pattern.
* @param x string expression
* @param pattern string expression
* @return like predicate
*/
Predicate like(Expression<String> x, Expression<String> pattern);
/**
* Create a predicate for testing whether the expression
* satisfies the given pattern.
* @param x string expression
* @param pattern string
* @return like predicate
*/
Predicate like(Expression<String> x, String pattern);
/**
* Create a predicate for testing whether the expression
* satisfies the given pattern.
* @param x string expression
* @param pattern string expression
* @param escapeChar escape character expression
* @return like predicate
*/
Predicate like(Expression<String> x, Expression<String> pattern, Expression<Character> escapeChar);
/**
* Create a predicate for testing whether the expression
* satisfies the given pattern.
* @param x string expression
* @param pattern string expression
* @param escapeChar escape character
* @return like predicate
*/
Predicate like(Expression<String> x, Expression<String> pattern, char escapeChar);
/**
* Create a predicate for testing whether the expression
* satisfies the given pattern.
* @param x string expression
* @param pattern string
* @param escapeChar escape character expression
* @return like predicate
*/
Predicate like(Expression<String> x, String pattern, Expression<Character> escapeChar);
/**
* Create a predicate for testing whether the expression
* satisfies the given pattern.
* @param x string expression
* @param pattern string
* @param escapeChar escape character
* @return like predicate
*/
Predicate like(Expression<String> x, String pattern, char escapeChar);
/**
* Create a predicate for testing whether the expression
* does not satisfy the given pattern.
* @param x string expression
* @param pattern string expression
* @return not-like predicate
*/
Predicate notLike(Expression<String> x, Expression<String> pattern);
/**
* Create a predicate for testing whether the expression
* does not satisfy the given pattern.
* @param x string expression
* @param pattern string
* @return not-like predicate
*/
Predicate notLike(Expression<String> x, String pattern);
/**
* Create a predicate for testing whether the expression
* does not satisfy the given pattern.
* @param x string expression
* @param pattern string expression
* @param escapeChar escape character expression
* @return not-like predicate
*/
Predicate notLike(Expression<String> x, Expression<String> pattern, Expression<Character> escapeChar);
/**
* Create a predicate for testing whether the expression
* does not satisfy the given pattern.
* @param x string expression
* @param pattern string expression
* @param escapeChar escape character
* @return not-like predicate
*/
Predicate notLike(Expression<String> x, Expression<String> pattern, char escapeChar);
/**
* Create a predicate for testing whether the expression
* does not satisfy the given pattern.
* @param x string expression
* @param pattern string
* @param escapeChar escape character expression
* @return not-like predicate
*/
Predicate notLike(Expression<String> x, String pattern, Expression<Character> escapeChar);
/**
* Create a predicate for testing whether the expression
* does not satisfy the given pattern.
* @param x string expression
* @param pattern string
* @param escapeChar escape character
* @return not-like predicate
*/
Predicate notLike(Expression<String> x, String pattern, char escapeChar);
/**
* Create an expression for string concatenation.
* If the given list of expressions is empty, returns
* an expression equivalent to {@code literal("")}.
* @param expressions string expressions
* @return expression corresponding to concatenation
*/
Expression<String> concat(List<Expression<String>> expressions);
/**
* Create an expression for string concatenation.
* @param x string expression
* @param y string expression
* @return expression corresponding to concatenation
*/
Expression<String> concat(Expression<String> x, Expression<String> y);
/**
* Create an expression for string concatenation.
* @param x string expression
* @param y string
* @return expression corresponding to concatenation
*/
Expression<String> concat(Expression<String> x, String y);
/**
* Create an expression for string concatenation.
* @param x string
* @param y string expression
* @return expression corresponding to concatenation
*/
Expression<String> concat(String x, Expression<String> y);
/**
* Create an expression for substring extraction.
* Extracts a substring starting at the specified position
* through to end of the string.
* First position is 1.
* @param x string expression
* @param from start position expression
* @return expression corresponding to substring extraction
*/
Expression<String> substring(Expression<String> x, Expression<Integer> from);
/**
* Create an expression for substring extraction.
* Extracts a substring starting at the specified position
* through to end of the string.
* First position is 1.
* @param x string expression
* @param from start position
* @return expression corresponding to substring extraction
*/
Expression<String> substring(Expression<String> x, int from);
/**
* Create an expression for substring extraction.
* Extracts a substring of given length starting at the
* specified position.
* First position is 1.
* @param x string expression
* @param from start position expression
* @param len length expression
* @return expression corresponding to substring extraction
*/
Expression<String> substring(Expression<String> x, Expression<Integer> from, Expression<Integer> len);
/**
* Create an expression for substring extraction.
* Extracts a substring of given length starting at the
* specified position.
* First position is 1.
* @param x string expression
* @param from start position
* @param len length
* @return expression corresponding to substring extraction
*/
Expression<String> substring(Expression<String> x, int from, int len);
/**
* Used to specify how strings are trimmed.
*/
public static enum Trimspec {
/**
* Trim from leading end.
*/
LEADING,
/**
* Trim from trailing end.
*/
TRAILING,
/**
* Trim from both ends.
*/
BOTH
}
/**
* Create expression to trim blanks from both ends of
* a string.
* @param x expression for string to trim
* @return trim expression
*/
Expression<String> trim(Expression<String> x);
/**
* Create expression to trim blanks from a string.
* @param ts trim specification
* @param x expression for string to trim
* @return trim expression
*/
Expression<String> trim(Trimspec ts, Expression<String> x);
/**
* Create expression to trim character from both ends of
* a string.
* @param t expression for character to be trimmed
* @param x expression for string to trim
* @return trim expression
*/
Expression<String> trim(Expression<Character> t, Expression<String> x);
/**
* Create expression to trim character from a string.
* @param ts trim specification
* @param t expression for character to be trimmed
* @param x expression for string to trim
* @return trim expression
*/
Expression<String> trim(Trimspec ts, Expression<Character> t, Expression<String> x);
/**
* Create expression to trim character from both ends of
* a string.
* @param t character to be trimmed
* @param x expression for string to trim
* @return trim expression
*/
Expression<String> trim(char t, Expression<String> x);
/**
* Create expression to trim character from a string.
* @param ts trim specification
* @param t character to be trimmed
* @param x expression for string to trim
* @return trim expression
*/
Expression<String> trim(Trimspec ts, char t, Expression<String> x);
/**
* Create expression for converting a string to lowercase.
* @param x string expression
* @return expression to convert to lowercase
*/
Expression<String> lower(Expression<String> x);
/**
* Create expression for converting a string to uppercase.
* @param x string expression
* @return expression to convert to uppercase
*/
Expression<String> upper(Expression<String> x);
/**
* Create expression to return length of a string.
* @param x string expression
* @return length expression
*/
Expression<Integer> length(Expression<String> x);
/**
* Create an expression for the leftmost substring of a string,
* @param x string expression
* @param len length of the substring to return
* @return expression for the leftmost substring
*/
Expression<String> left(Expression<String> x, int len);
/**
* Create an expression for the rightmost substring of a string,
* @param x string expression
* @param len length of the substring to return
* @return expression for the rightmost substring
*/
Expression<String> right(Expression<String> x, int len);
/**
* Create an expression for the leftmost substring of a string,
* @param x string expression
* @param len length of the substring to return
* @return expression for the leftmost substring
*/
Expression<String> left(Expression<String> x, Expression<Integer> len);
/**
* Create an expression for the rightmost substring of a string,
* @param x string expression
* @param len length of the substring to return
* @return expression for the rightmost substring
*/
Expression<String> right(Expression<String> x, Expression<Integer> len);
/**
* Create an expression replacing every occurrence of a substring
* within a string.
* @param x string expression
* @param substring the literal substring to replace
* @param replacement the replacement string
* @return expression for the resulting string
*/
Expression<String> replace(Expression<String> x, Expression<String> substring, Expression<String> replacement);
/**
* Create an expression replacing every occurrence of a substring
* within a string.
* @param x string expression
* @param substring the literal substring to replace
* @param replacement the replacement string
* @return expression for the resulting string
*/
Expression<String> replace(Expression<String> x, String substring, Expression<String> replacement);
/**
* Create an expression replacing every occurrence of a substring
* within a string.
* @param x string expression
* @param substring the literal substring to replace
* @param replacement the replacement string
* @return expression for the resulting string
*/
Expression<String> replace(Expression<String> x, Expression<String> substring, String replacement);
/**
* Create an expression replacing every occurrence of a substring
* within a string.
* @param x string expression
* @param substring the literal substring to replace
* @param replacement the replacement string
* @return expression for the resulting string
*/
Expression<String> replace(Expression<String> x, String substring, String replacement);
/**
* Create expression to locate the position of one string
* within another, returning position of first character
* if found.
* The first position in a string is denoted by 1. If the
* string to be located is not found, 0 is returned.
* <p><strong>Warning:</strong> the order of the parameters
* of this method is reversed compared to the corresponding
* function in JPQL.
* @param x expression for string to be searched
* @param pattern expression for string to be located
* @return expression corresponding to position
*/
Expression<Integer> locate(Expression<String> x, Expression<String> pattern);
/**
* Create expression to locate the position of one string
* within another, returning position of first character
* if found.
* The first position in a string is denoted by 1. If the
* string to be located is not found, 0 is returned.
* <p><strong>Warning:</strong> the order of the parameters
* of this method is reversed compared to the corresponding
* function in JPQL.
* @param x expression for string to be searched
* @param pattern string to be located
* @return expression corresponding to position
*/
Expression<Integer> locate(Expression<String> x, String pattern);
/**
* Create expression to locate the position of one string
* within another, returning position of first character
* if found.
* The first position in a string is denoted by 1. If the
* string to be located is not found, 0 is returned.
* <p><strong>Warning:</strong> the order of the first two
* parameters of this method is reversed compared to the
* corresponding function in JPQL.
* @param x expression for string to be searched
* @param pattern expression for string to be located
* @param from expression for position at which to start search
* @return expression corresponding to position
*/
Expression<Integer> locate(Expression<String> x, Expression<String> pattern, Expression<Integer> from);
/**
* Create expression to locate the position of one string
* within another, returning position of first character
* if found.
* The first position in a string is denoted by 1. If the
* string to be located is not found, 0 is returned.
* <p><strong>Warning:</strong> the order of the first two
* parameters of this method is reversed compared to the
* corresponding function in JPQL.
* @param x expression for string to be searched
* @param pattern string to be located
* @param from position at which to start search
* @return expression corresponding to position
*/
Expression<Integer> locate(Expression<String> x, String pattern, int from);
// Date/time/timestamp functions:
/**
* Create expression to return current date.
* @return expression for current date
*/
Expression<java.sql.Date> currentDate();
/**
* Create expression to return current timestamp.
* @return expression for current timestamp
*/
Expression<java.sql.Timestamp> currentTimestamp();
/**
* Create expression to return current time.
* @return expression for current time
*/
Expression<java.sql.Time> currentTime();
//in builders:
/**
* Interface used to build in predicates.
*/
public static interface In<T> extends Predicate {
/**
* Return the expression to be tested against the
* list of values.
* @return expression
*/
Expression<T> getExpression();
/**
* Add to list of values to be tested against.
* @param value value
* @return in predicate
*/
In<T> value(T value);
/**
* Add to list of values to be tested against.
* @param value expression
* @return in predicate
*/
In<T> value(Expression<? extends T> value);
}
/**
* Create predicate to test whether given expression
* is contained in a list of values.
* @param expression to be tested against list of values
* @return in predicate
*/
<T> In<T> in(Expression<? extends T> expression);
// coalesce, nullif:
/**
* Create an expression that returns null if all its arguments
* evaluate to null, and the value of the first non-null argument
* otherwise.
* @param x expression
* @param y expression
* @return coalesce expression
*/
<Y> Expression<Y> coalesce(Expression<? extends Y> x, Expression<? extends Y> y);
/**
* Create an expression that returns null if all its arguments
* evaluate to null, and the value of the first non-null argument
* otherwise.
* @param x expression
* @param y value
* @return coalesce expression
*/
<Y> Expression<Y> coalesce(Expression<? extends Y> x, Y y);
/**
* Create an expression that tests whether its argument are
* equal, returning null if they are and the value of the
* first expression if they are not.
* @param x expression
* @param y expression
* @return nullif expression
*/
<Y> Expression<Y> nullif(Expression<Y> x, Expression<?> y);
/**
* Create an expression that tests whether its argument are
* equal, returning null if they are and the value of the
* first expression if they are not.
* @param x expression
* @param y value
* @return nullif expression
*/
<Y> Expression<Y> nullif(Expression<Y> x, Y y);
// coalesce builder:
/**
* Interface used to build coalesce expressions.
*
* A coalesce expression is equivalent to a case expression
* that returns null if all its arguments evaluate to null,
* and the value of its first non-null argument otherwise.
*/
public static interface Coalesce<T> extends Expression<T> {
/**
* Add an argument to the coalesce expression.
* @param value value
* @return coalesce expression
*/
Coalesce<T> value(T value);
/**
* Add an argument to the coalesce expression.
* @param value expression
* @return coalesce expression
*/
Coalesce<T> value(Expression<? extends T> value);
}
/**
* Create a coalesce expression.
* @return coalesce expression
*/
<T> Coalesce<T> coalesce();
//case builders:
/**
* Interface used to build simple case expressions.
* Case conditions are evaluated in the order in which
* they are specified.
*/
public static interface SimpleCase<C,R> extends Expression<R> {
/**
* Return the expression to be tested against the
* conditions.
* @return expression
*/
Expression<C> getExpression();
/**
* Add a when/then clause to the case expression.
* @param condition "when" condition
* @param result "then" result value
* @return simple case expression
*/
SimpleCase<C, R> when(C condition, R result);
/**
* Add a when/then clause to the case expression.
* @param condition "when" condition
* @param result "then" result expression
* @return simple case expression
*/
SimpleCase<C, R> when(C condition, Expression<? extends R> result);
/**
* Add an "else" clause to the case expression.
* @param result "else" result
* @return expression
*/
Expression<R> otherwise(R result);
/**
* Add an "else" clause to the case expression.
* @param result "else" result expression
* @return expression
*/
Expression<R> otherwise(Expression<? extends R> result);
}
/**
* Create a simple case expression.
* @param expression to be tested against the case conditions
* @return simple case expression
*/
<C, R> SimpleCase<C,R> selectCase(Expression<? extends C> expression);
/**
* Interface used to build general case expressions.
* Case conditions are evaluated in the order in which
* they are specified.
*/
public static interface Case<R> extends Expression<R> {
/**
* Add a when/then clause to the case expression.
* @param condition "when" condition
* @param result "then" result value
* @return general case expression
*/
Case<R> when(Expression<Boolean> condition, R result);
/**
* Add a when/then clause to the case expression.
* @param condition "when" condition
* @param result "then" result expression
* @return general case expression
*/
Case<R> when(Expression<Boolean> condition, Expression<? extends R> result);
/**
* Add an "else" clause to the case expression.
* @param result "else" result
* @return expression
*/
Expression<R> otherwise(R result);
/**
* Add an "else" clause to the case expression.
* @param result "else" result expression
* @return expression
*/
Expression<R> otherwise(Expression<? extends R> result);
}
/**
* Create a general case expression.
* @return general case expression
*/
<R> Case<R> selectCase();
/**
* Create an expression for the execution of a database
* function.
* @param name function name
* @param type expected result type
* @param args function arguments
* @return expression
*/
<T> Expression<T> function(String name, Class<T> type,
Expression<?>... args);
// methods for downcasting:
/**
* Downcast Join object to the specified type.
* @param join Join object
* @param type type to be downcast to
* @return Join object of the specified type
* @since 2.1
*/
<X, T, V extends T> Join<X, V> treat(Join<X, T> join, Class<V> type);
/**
* Downcast CollectionJoin object to the specified type.
* @param join CollectionJoin object
* @param type type to be downcast to
* @return CollectionJoin object of the specified type
* @since 2.1
*/
<X, T, E extends T> CollectionJoin<X, E> treat(CollectionJoin<X, T> join, Class<E> type);
/**
* Downcast SetJoin object to the specified type.
* @param join SetJoin object
* @param type type to be downcast to
* @return SetJoin object of the specified type
* @since 2.1
*/
<X, T, E extends T> SetJoin<X, E> treat(SetJoin<X, T> join, Class<E> type);
/**
* Downcast ListJoin object to the specified type.
* @param join ListJoin object
* @param type type to be downcast to
* @return ListJoin object of the specified type
* @since 2.1
*/
<X, T, E extends T> ListJoin<X, E> treat(ListJoin<X, T> join, Class<E> type);
/**
* Downcast MapJoin object to the specified type.
* @param join MapJoin object
* @param type type to be downcast to
* @return MapJoin object of the specified type
* @since 2.1
*/
<X, K, T, V extends T> MapJoin<X, K, V> treat(MapJoin<X, K, T> join, Class<V> type);
/**
* Downcast Path object to the specified type.
* @param path path
* @param type type to be downcast to
* @return Path object of the specified type
* @since 2.1
*/
<X, T extends X> Path<T> treat(Path<X> path, Class<T> type);
/**
* Downcast Root object to the specified type.
* @param root root
* @param type type to be downcast to
* @return Root object of the specified type
* @since 2.1
*/
<X, T extends X> Root<T> treat(Root<X> root, Class<T> type);
/**
* Create a query which is the union of the given queries.
* @return a new criteria query which returns the union of
* the results of the given queries
* @since 3.2
*/
<T> CriteriaSelect<T> union(CriteriaSelect<? extends T> left, CriteriaSelect<? extends T> right);
/**
* Create a query which is the union of the given queries,
* without elimination of duplicate results.
* @return a new criteria query which returns the union of
* the results of the given queries
* @since 3.2
*/
<T> CriteriaSelect<T> unionAll(CriteriaSelect<? extends T> left, CriteriaSelect<? extends T> right);
/**
* Create a query which is the intersection of the given queries.
* @return a new criteria query which returns the intersection of
* the results of the given queries
* @since 3.2
*/
<T> CriteriaSelect<T> intersect(CriteriaSelect<? super T> left, CriteriaSelect<? super T> right);
/**
* Create a query which is the intersection of the given queries,
* without elimination of duplicate results.
* @return a new criteria query which returns the intersection of
* the results of the given queries
* @since 3.2
*/
<T> CriteriaSelect<T> intersectAll(CriteriaSelect<? super T> left, CriteriaSelect<? super T> right);
/**
* Create a query by (setwise) subtraction of the second query
* from the first query.
* @return a new criteria query which returns the result of
* subtracting the results of the second query from the
* results of the first query
* @since 3.2
*/
<T> CriteriaSelect<T> except(CriteriaSelect<T> left, CriteriaSelect<?> right);
/**
* Create a query by (setwise) subtraction of the second query
* from the first query, without elimination of duplicate results.
* @return a new criteria query which returns the result of
* subtracting the results of the second query from the
* results of the first query
* @since 3.2
*/
<T> CriteriaSelect<T> exceptAll(CriteriaSelect<T> left, CriteriaSelect<?> right);
}
6.3.2. CommonAbstractCriteria Interface
package jakarta.persistence.criteria;
/**
* The <code>CommonAbstractCriteria</code> interface defines functionality
* that is common to both top-level criteria queries and subqueries as
* well as to update and delete criteria operations.
* It is not intended to be used directly in query construction.
*
* <p> Note that criteria queries and criteria update and delete operations
* are typed differently.
* Criteria queries are typed according to the query result type.
* Update and delete operations are typed according to the target of the
* update or delete.
*
* @since 2.1
*/
public interface CommonAbstractCriteria {
/**
* Create a subquery of the query.
* @param type the subquery result type
* @return subquery
*/
<U> Subquery<U> subquery(Class<U> type);
/**
* Create a subquery of the query.
* @param type the subquery result type
* @return subquery
*/
<U> Subquery<U> subquery(EntityType<U> type);
/**
* Return the predicate that corresponds to the where clause
* restriction(s), or null if no restrictions have been
* specified.
* @return where clause predicate
*/
Predicate getRestriction();
/**
* Return the parameters of the query. Returns empty set if
* there are no parameters.
* Modifications to the set do not affect the query.
* @return the query parameters
*/
Set<ParameterExpression<?>> getParameters();
}
6.3.3. AbstractQuery Interface
package jakarta.persistence.criteria;
import java.util.List;
import java.util.Set;
import jakarta.persistence.metamodel.EntityType;
/**
* The <code>AbstractQuery</code> interface defines functionality that is common
* to both top-level queries and subqueries.
* It is not intended to be used directly in query construction.
*
* <p> All queries must have:
* a set of root entities (which may in turn own joins).
* <p> All queries may have:
* a conjunction of restrictions.
*
* @param <T> the type of the result
*
* @since 2.0
*/
public interface AbstractQuery<T> extends CommonAbstractCriteria {
/**
* Create and add a query root corresponding to the given entity,
* forming a cartesian product with any existing roots.
* @param entityClass the entity class
* @return query root corresponding to the given entity
*/
<X> Root<X> from(Class<X> entityClass);
/**
* Create and add a query root corresponding to the given entity,
* forming a cartesian product with any existing roots.
* @param entity metamodel entity representing the entity
* of type X
* @return query root corresponding to the given entity
*/
<X> Root<X> from(EntityType<X> entity);
/**
* Modify the query to restrict the query results according
* to the specified boolean expression.
* Replaces the previously added restriction(s), if any.
* @param restriction a simple or compound boolean expression
* @return the modified query
*/
AbstractQuery<T> where(Expression<Boolean> restriction);
/**
* Modify the query to restrict the query results according
* to the conjunction of the specified restriction predicates.
* Replaces the previously added restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
AbstractQuery<T> where(Predicate... restrictions);
/**
* Specify the expressions that are used to form groups over
* the query results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
* @param grouping zero or more grouping expressions
* @return the modified query
*/
AbstractQuery<T> groupBy(Expression<?>... grouping);
/**
* Specify the expressions that are used to form groups over
* the query results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
* @param grouping list of zero or more grouping expressions
* @return the modified query
*/
AbstractQuery<T> groupBy(List<Expression<?>> grouping);
/**
* Specify a restriction over the groups of the query.
* Replaces the previous having restriction(s), if any.
* @param restriction a simple or compound boolean expression
* @return the modified query
*/
AbstractQuery<T> having(Expression<Boolean> restriction);
/**
* Specify restrictions over the groups of the query
* according the conjunction of the specified restriction
* predicates.
* Replaces the previously having added restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
AbstractQuery<T> having(Predicate... restrictions);
/**
* Specify whether duplicate query results will be eliminated.
* A true value will cause duplicates to be eliminated.
* A false value will cause duplicates to be retained.
* If distinct has not been specified, duplicate results must
* be retained.
* @param distinct boolean value specifying whether duplicate
* results must be eliminated from the query result or
* whether they must be retained
* @return the modified query
*/
AbstractQuery<T> distinct(boolean distinct);
/**
* Return the query roots. These are the roots that have
* been defined for the <code>CriteriaQuery</code> or <code>Subquery</code> itself,
* including any subquery roots defined as a result of
* correlation. Returns empty set if no roots have been defined.
* Modifications to the set do not affect the query.
* @return the set of query roots
*/
Set<Root<?>> getRoots();
/**
* Return the selection of the query, or null if no selection
* has been set.
* @return selection item
*/
Selection<T> getSelection();
/**
* Return a list of the grouping expressions. Returns empty
* list if no grouping expressions have been specified.
* Modifications to the list do not affect the query.
* @return the list of grouping expressions
*/
List<Expression<?>> getGroupList();
/**
* Return the predicate that corresponds to the restriction(s)
* over the grouping items, or null if no restrictions have
* been specified.
* @return having clause predicate
*/
Predicate getGroupRestriction();
/**
* Return whether duplicate query results must be eliminated or
* retained.
* @return boolean indicating whether duplicate query results
* must be eliminated
*/
boolean isDistinct();
/**
* Return the result type of the query or subquery. If a result
* type was specified as an argument to the
* <code>createQuery</code> or <code>subquery</code> method, that
* type will be returned. If the query was created using the
* <code>createTupleQuery</code> method, the result type is
* <code>Tuple</code>. Otherwise, the result type is
* <code>Object</code>.
* @return result type
*/
Class<T> getResultType();
}
6.3.4. CriteriaQuery Interface
package jakarta.persistence.criteria;
import java.util.List;
import java.util.Set;
/**
* The <code>CriteriaQuery</code> interface defines functionality that is specific
* to top-level queries.
*
* @param <T> the type of the defined result
*
* @since 2.0
*/
public interface CriteriaQuery<T> extends AbstractQuery<T> {
/**
* Specify the item that is to be returned in the query result.
* Replaces the previously specified selection(s), if any.
*
* <p> Note: Applications using the string-based API may need to
* specify the type of the select item when it results from
* a get or join operation and the query result type is
* specified.
*
* <pre>
* For example:
*
* CriteriaQuery<String> q = cb.createQuery(String.class);
* Root<Order> order = q.from(Order.class);
* q.select(order.get("shippingAddress").<String>get("state"));
*
* CriteriaQuery<Product> q2 = cb.createQuery(Product.class);
* q2.select(q2.from(Order.class)
* .join("items")
* .<Item,Product>join("product"));
*
* </pre>
* @param selection selection specifying the item that
* is to be returned in the query result
* @return the modified query
* @throws IllegalArgumentException if the selection is
* a compound selection and more than one selection
* item has the same assigned alias
*/
CriteriaQuery<T> select(Selection<? extends T> selection);
/**
* Specify the selection items that are to be returned in the
* query result.
* Replaces the previously specified selection(s), if any.
*
* The type of the result of the query execution depends on
* the specification of the type of the criteria query object
* created as well as the arguments to the multiselect method.
* <p> An argument to the multiselect method must not be a tuple-
* or array-valued compound selection item.
*
* <p>The semantics of this method are as follows:
* <ul>
* <li>
* If the type of the criteria query is
* <code>CriteriaQuery<Tuple></code> (i.e., a criteria
* query object created by either the
* <code>createTupleQuery</code> method or by passing a
* <code>Tuple</code> class argument to the
* <code>createQuery</code> method), a <code>Tuple</code> object
* corresponding to the arguments of the <code>multiselect</code>
* method, in the specified order, will be instantiated and
* returned for each row that results from the query execution.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<X></code> for
* some user-defined class X (i.e., a criteria query object
* created by passing a X class argument to the <code>createQuery</code>
* method), the arguments to the <code>multiselect</code> method will be
* passed to the X constructor and an instance of type X will be
* returned for each row.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<X[]></code> for
* some class X, an instance of type X[] will be returned for
* each row. The elements of the array will correspond to the
* arguments of the <code>multiselect</code> method, in the
* specified order.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<Object></code>
* or if the criteria query was created without specifying a
* type, and only a single argument is passed to the <code>multiselect</code>
* method, an instance of type <code>Object</code> will be returned for
* each row.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<Object></code>
* or if the criteria query was created without specifying a
* type, and more than one argument is passed to the <code>multiselect</code>
* method, an instance of type <code>Object[]</code> will be instantiated
* and returned for each row. The elements of the array will
* correspond to the arguments to the <code> multiselect</code> method,
* in the specified order.
* </ul>
*
* @param selections selection items corresponding to the
* results to be returned by the query
* @return the modified query
* @throws IllegalArgumentException if a selection item is
* not valid or if more than one selection item has
* the same assigned alias
*/
CriteriaQuery<T> multiselect(Selection<?>... selections);
/**
* Specify the selection items that are to be returned in the
* query result.
* Replaces the previously specified selection(s), if any.
*
* <p> The type of the result of the query execution depends on
* the specification of the type of the criteria query object
* created as well as the argument to the <code>multiselect</code> method.
* An element of the list passed to the <code>multiselect</code> method
* must not be a tuple- or array-valued compound selection item.
*
* <p> The semantics of this method are as follows:
* <ul>
* <li> If the type of the criteria query is <code>CriteriaQuery<Tuple></code>
* (i.e., a criteria query object created by either the
* <code>createTupleQuery</code> method or by passing a <code>Tuple</code> class argument
* to the <code>createQuery</code> method), a <code>Tuple</code> object corresponding to
* the elements of the list passed to the <code>multiselect</code> method,
* in the specified order, will be instantiated and returned for each
* row that results from the query execution.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<X></code> for
* some user-defined class X (i.e., a criteria query object
* created by passing a X class argument to the <code>createQuery</code>
* method), the elements of the list passed to the <code>multiselect</code>
* method will be passed to the X constructor and an instance
* of type X will be returned for each row.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<X[]></code> for
* some class X, an instance of type X[] will be returned for
* each row. The elements of the array will correspond to the
* elements of the list passed to the <code>multiselect</code> method,
* in the specified order.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<Object></code>
* or if the criteria query was created without specifying a
* type, and the list passed to the <code>multiselect</code> method contains
* only a single element, an instance of type <code>Object</code> will be
* returned for each row.
*
* <li> If the type of the criteria query is <code>CriteriaQuery<Object></code>
* or if the criteria query was created without specifying a
* type, and the list passed to the <code>multiselect</code> method contains
* more than one element, an instance of type <code>Object[]</code> will be
* instantiated and returned for each row. The elements of the
* array will correspond to the elements of the list passed to
* the <code>multiselect</code> method, in the specified order.
* </ul>
*
* @param selectionList list of selection items corresponding
* to the results to be returned by the query
* @return the modified query
* @throws IllegalArgumentException if a selection item is
* not valid or if more than one selection item has
* the same assigned alias
*/
CriteriaQuery<T> multiselect(List<Selection<?>> selectionList);
/**
* Modify the query to restrict the query result according
* to the specified boolean expression.
* Replaces the previously added restriction(s), if any.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restriction a simple or compound boolean expression
* @return the modified query
*/
CriteriaQuery<T> where(Expression<Boolean> restriction);
/**
* Modify the query to restrict the query result according
* to the conjunction of the specified restriction predicates.
* Replaces the previously added restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
CriteriaQuery<T> where(Predicate... restrictions);
/**
* Specify the expressions that are used to form groups over
* the query results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param grouping zero or more grouping expressions
* @return the modified query
*/
CriteriaQuery<T> groupBy(Expression<?>... grouping);
/**
* Specify the expressions that are used to form groups over
* the query results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param grouping list of zero or more grouping expressions
* @return the modified query
*/
CriteriaQuery<T> groupBy(List<Expression<?>> grouping);
/**
* Specify a restriction over the groups of the query.
* Replaces the previous having restriction(s), if any.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restriction a simple or compound boolean expression
* @return the modified query
*/
CriteriaQuery<T> having(Expression<Boolean> restriction);
/**
* Specify restrictions over the groups of the query
* according the conjunction of the specified restriction
* predicates.
* Replaces the previously added having restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
CriteriaQuery<T> having(Predicate... restrictions);
/**
* Specify the ordering expressions that are used to
* order the query results.
* Replaces the previous ordering expressions, if any.
* If no ordering expressions are specified, the previous
* ordering, if any, is simply removed, and results will
* be returned in no particular order.
* The left-to-right sequence of the ordering expressions
* determines the precedence, whereby the leftmost has highest
* precedence.
* @param o zero or more ordering expressions
* @return the modified query
*/
CriteriaQuery<T> orderBy(Order... o);
/**
* Specify the ordering expressions that are used to
* order the query results.
* Replaces the previous ordering expressions, if any.
* If no ordering expressions are specified, the previous
* ordering, if any, is simply removed, and results will
* be returned in no particular order.
* The order of the ordering expressions in the list
* determines the precedence, whereby the first element in the
* list has highest precedence.
* @param o list of zero or more ordering expressions
* @return the modified query
*/
CriteriaQuery<T> orderBy(List<Order> o);
/**
* Specify whether duplicate query results will be eliminated.
* A true value will cause duplicates to be eliminated.
* A false value will cause duplicates to be retained.
* If distinct has not been specified, duplicate results must
* be retained.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param distinct boolean value specifying whether duplicate
* results must be eliminated from the query result or
* whether they must be retained
* @return the modified query.
*/
CriteriaQuery<T> distinct(boolean distinct);
/**
* Return the ordering expressions in order of precedence.
* Returns empty list if no ordering expressions have been
* specified.
* Modifications to the list do not affect the query.
* @return the list of ordering expressions
*/
List<Order> getOrderList();
}
6.3.5. CriteriaUpdate Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.EntityType;
/**
* The <code>CriteriaUpdate</code> interface defines functionality for performing
* bulk update operations using the Criteria API.
*
* <p>Criteria API bulk update operations map directly to database update
* operations, bypassing any optimistic locking checks. Portable
* applications using bulk update operations must manually update the
* value of the version column, if desired, and/or manually validate
* the value of the version column.
* The persistence context is not synchronized with the result of the
* bulk update.
*
* <p> A <code>CriteriaUpdate</code> object must have a single root.
*
* @param <T> the entity type that is the target of the update
*
* @since 2.1
*/
public interface CriteriaUpdate<T> extends CommonAbstractCriteria {
/**
* Create and add a query root corresponding to the entity
* that is the target of the update.
* A <code>CriteriaUpdate</code> object has a single root, the entity that
* is being updated.
* @param entityClass the entity class
* @return query root corresponding to the given entity
*/
Root<T> from(Class<T> entityClass);
/**
* Create and add a query root corresponding to the entity
* that is the target of the update.
* A <code>CriteriaUpdate</code> object has a single root, the entity that
* is being updated.
* @param entity metamodel entity representing the entity
* of type X
* @return query root corresponding to the given entity
*/
Root<T> from(EntityType<T> entity);
/**
* Return the query root.
* @return the query root
*/
Root<T> getRoot();
/**
* Update the value of the specified attribute.
* @param attribute attribute to be updated
* @param value new value
* @return the modified update query
*/
<Y, X extends Y> CriteriaUpdate<T> set(SingularAttribute<? super T, Y> attribute, X value);
/**
* Update the value of the specified attribute.
* @param attribute attribute to be updated
* @param value new value
* @return the modified update query
*/
<Y> CriteriaUpdate<T> set(SingularAttribute<? super T, Y> attribute, Expression<? extends Y> value);
/**
* Update the value of the specified attribute.
* @param attribute attribute to be updated
* @param value new value
* @return the modified update query
*/
<Y, X extends Y> CriteriaUpdate<T> set(Path<Y> attribute, X value);
/**
* Update the value of the specified attribute.
* @param attribute attribute to be updated
* @param value new value
* @return the modified update query
*/
<Y> CriteriaUpdate<T> set(Path<Y> attribute, Expression<? extends Y> value);
/**
* Update the value of the specified attribute.
* @param attributeName name of the attribute to be updated
* @param value new value
* @return the modified update query
*/
CriteriaUpdate<T> set(String attributeName, Object value);
/**
* Modify the update query to restrict the target of the update
* according to the specified boolean expression.
* Replaces the previously added restriction(s), if any.
* @param restriction a simple or compound boolean expression
* @return the modified update query
*/
CriteriaUpdate<T> where(Expression<Boolean> restriction);
/**
* Modify the update query to restrict the target of the update
* according to the conjunction of the specified restriction
* predicates.
* Replaces the previously added restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* @param restrictions zero or more restriction predicates
* @return the modified update query
*/
CriteriaUpdate<T> where(Predicate... restrictions);
}
6.3.6. CriteriaDelete Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.EntityType;
/**
* The <code>CriteriaDelete</code> interface defines functionality for performing
* bulk delete operations using the Criteria API
*
* <p>Criteria API bulk delete operations map directly to database
* delete operations. The persistence context is not synchronized
* with the result of the bulk delete.
*
* <p> A <code>CriteriaDelete</code> object must have a single root.
*
* @param <T> the entity type that is the target of the delete
*
* @since 2.1
*/
public interface CriteriaDelete<T> extends CommonAbstractCriteria {
/**
* Create and add a query root corresponding to the entity
* that is the target of the delete.
* A <code>CriteriaDelete</code> object has a single root, the entity that
* is being deleted.
* @param entityClass the entity class
* @return query root corresponding to the given entity
*/
Root<T> from(Class<T> entityClass);
/**
* Create and add a query root corresponding to the entity
* that is the target of the delete.
* A <code>CriteriaDelete</code> object has a single root, the entity that
* is being deleted.
* @param entity metamodel entity representing the entity
* of type X
* @return query root corresponding to the given entity
*/
Root<T> from(EntityType<T> entity);
/**
* Return the query root.
* @return the query root
*/
Root<T> getRoot();
/**
* Modify the delete query to restrict the target of the deletion
* according to the specified boolean expression.
* Replaces the previously added restriction(s), if any.
* @param restriction a simple or compound boolean expression
* @return the modified delete query
*/
CriteriaDelete<T> where(Expression<Boolean> restriction);
/**
* Modify the delete query to restrict the target of the deletion
* according to the conjunction of the specified restriction
* predicates.
* Replaces the previously added restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* @param restrictions zero or more restriction predicates
* @return the modified delete query
*/
CriteriaDelete<T> where(Predicate... restrictions);
}
6.3.7. Subquery Interface
package jakarta.persistence.criteria;
import java.util.List;
import java.util.Set;
/**
* The <code>Subquery</code> interface defines functionality that is
* specific to subqueries.
*
* A subquery has an expression as its selection item.
*
* @param <T> the type of the selection item.
*
* @since 2.0
*/
public interface Subquery<T> extends AbstractQuery<T>, Expression<T> {
/**
* Specify the item that is to be returned as the subquery
* result.
* Replaces the previously specified selection, if any.
* @param expression expression specifying the item that
* is to be returned as the subquery result
* @return the modified subquery
*/
Subquery<T> select(Expression<T> expression);
/**
* Modify the subquery to restrict the result according
* to the specified boolean expression.
* Replaces the previously added restriction(s), if any.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restriction a simple or compound boolean expression
* @return the modified subquery
*/
Subquery<T> where(Expression<Boolean> restriction);
/**
* Modify the subquery to restrict the result according
* to the conjunction of the specified restriction predicates.
* Replaces the previously added restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restrictions zero or more restriction predicates
* @return the modified subquery
*/
Subquery<T> where(Predicate... restrictions);
/**
* Specify the expressions that are used to form groups over
* the subquery results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param grouping zero or more grouping expressions
* @return the modified subquery
*/
Subquery<T> groupBy(Expression<?>... grouping);
/**
* Specify the expressions that are used to form groups over
* the subquery results.
* Replaces the previous specified grouping expressions, if any.
* If no grouping expressions are specified, any previously
* added grouping expressions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param grouping list of zero or more grouping expressions
* @return the modified subquery
*/
Subquery<T> groupBy(List<Expression<?>> grouping);
/**
* Specify a restriction over the groups of the subquery.
* Replaces the previous having restriction(s), if any.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restriction a simple or compound boolean expression
* @return the modified subquery
*/
Subquery<T> having(Expression<Boolean> restriction);
/**
* Specify restrictions over the groups of the subquery
* according the conjunction of the specified restriction
* predicates.
* Replaces the previously added having restriction(s), if any.
* If no restrictions are specified, any previously added
* restrictions are simply removed.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param restrictions zero or more restriction predicates
* @return the modified subquery
*/
Subquery<T> having(Predicate... restrictions);
/**
* Specify whether duplicate query results will be eliminated.
* A true value will cause duplicates to be eliminated.
* A false value will cause duplicates to be retained.
* If distinct has not been specified, duplicate results must
* be retained.
* This method only overrides the return type of the
* corresponding <code>AbstractQuery</code> method.
* @param distinct boolean value specifying whether duplicate
* results must be eliminated from the subquery result or
* whether they must be retained
* @return the modified subquery.
*/
Subquery<T> distinct(boolean distinct);
/**
* Create a subquery root correlated to a root of the
* enclosing query.
* @param parentRoot a root of the containing query
* @return subquery root
*/
<Y> Root<Y> correlate(Root<Y> parentRoot);
/**
* Create a subquery join object correlated to a join object
* of the enclosing query.
* @param parentJoin join object of the containing query
* @return subquery join
*/
<X, Y> Join<X, Y> correlate(Join<X, Y> parentJoin);
/**
* Create a subquery collection join object correlated to a
* collection join object of the enclosing query.
* @param parentCollection join object of the containing query
* @return subquery join
*/
<X, Y> CollectionJoin<X, Y> correlate(CollectionJoin<X, Y> parentCollection);
/**
* Create a subquery set join object correlated to a set join
* object of the enclosing query.
* @param parentSet join object of the containing query
* @return subquery join
*/
<X, Y> SetJoin<X, Y> correlate(SetJoin<X, Y> parentSet);
/**
* Create a subquery list join object correlated to a list join
* object of the enclosing query.
* @param parentList join object of the containing query
* @return subquery join
*/
<X, Y> ListJoin<X, Y> correlate(ListJoin<X, Y> parentList);
/**
* Create a subquery map join object correlated to a map join
* object of the enclosing query.
* @param parentMap join object of the containing query
* @return subquery join
*/
<X, K, V> MapJoin<X, K, V> correlate(MapJoin<X, K, V> parentMap);
/**
* Return the query of which this is a subquery.
* This must be a CriteriaQuery or a Subquery.
* @return the enclosing query or subquery
*/
AbstractQuery<?> getParent();
/**
* Return the query of which this is a subquery.
* This may be a CriteriaQuery, CriteriaUpdate, CriteriaDelete,
* or a Subquery.
* @return the enclosing query or subquery
* @since 2.1
*/
CommonAbstractCriteria getContainingQuery();
/**
* Return the selection expression.
* @return the item to be returned in the subquery result
*/
Expression<T> getSelection();
/**
* Return the correlated joins of the subquery.
* Returns empty set if the subquery has no correlated
* joins.
* Modifications to the set do not affect the query.
* @return the correlated joins of the subquery
*/
Set<Join<?, ?>> getCorrelatedJoins();
}
6.3.8. Selection Interface
package jakarta.persistence.criteria;
import jakarta.persistence.TupleElement;
import java.util.List;
/**
* The <code>Selection</code> interface defines an item that is to be
* returned in a query result.
*
* @param <X> the type of the selection item
*
* @since 2.0
*/
public interface Selection<X> extends TupleElement<X> {
/**
* Assigns an alias to the selection item.
* Once assigned, an alias cannot be changed or reassigned.
* Returns the same selection item.
* @param name alias
* @return selection item
*/
Selection<X> alias(String name);
/**
* Whether the selection item is a compound selection.
* @return boolean indicating whether the selection is a compound
* selection
*/
boolean isCompoundSelection();
/**
* Return the selection items composing a compound selection.
* Modifications to the list do not affect the query.
* @return list of selection items
* @throws IllegalStateException if selection is not a
* compound selection
*/
List<Selection<?>> getCompoundSelectionItems();
}
6.3.9. CompoundSelection Interface
package jakarta.persistence.criteria;
/**
* The <code>CompoundSelection</code> interface defines a compound selection item
* (tuple, array, or result of constructor).
*
* @param <X> the type of the selection item
*
* @since 2.0
*/
public interface CompoundSelection<X> extends Selection<X> {}
6.3.10. Expression Interface
package jakarta.persistence.criteria;
import java.util.Collection;
/**
* Type for query expressions.
*
* @param <T> the type of the expression
*
* @since 2.0
*/
public interface Expression<T> extends Selection<T> {
/**
* Create a predicate to test whether the expression is null.
* @return predicate testing whether the expression is null
*/
Predicate isNull();
/**
* Create a predicate to test whether the expression is
* not null.
* @return predicate testing whether the expression is not null
*/
Predicate isNotNull();
/**
* Create a predicate to test whether the expression is equal to
* the argument.
* @param value expression to be tested against
* @return predicate testing for equality
*/
Predicate equalTo(Expression<?> value);
/**
* Create a predicate to test whether the expression is equal to
* the argument.
* @param value value to be tested against
* @return predicate testing for equality
*/
Predicate equalTo(Object value);
/**
* Create a predicate to test whether the expression is unequal
* to the argument.
* @param value expression to be tested against
* @return predicate testing for inequality
*/
Predicate notEqualTo(Expression<?> value);
/**
* Create a predicate to test whether the expression is unequal
* to the argument.
* @param value value to be tested against
* @return predicate testing for inequality
*/
Predicate notEqualTo(Object value);
/**
* Create a predicate to test whether the expression is a member
* of the argument list.
* @param values values to be tested against
* @return predicate testing for membership
*/
Predicate in(Object... values);
/**
* Create a predicate to test whether the expression is a member
* of the argument list.
* @param values expressions to be tested against
* @return predicate testing for membership
*/
Predicate in(Expression<?>... values);
/**
* Create a predicate to test whether the expression is a member
* of the collection.
* @param values collection of values to be tested against
* @return predicate testing for membership
*/
Predicate in(Collection<?> values);
/**
* Create a predicate to test whether the expression is a member
* of the collection.
* @param values expression corresponding to collection to be
* tested against
* @return predicate testing for membership
*/
Predicate in(Expression<Collection<?>> values);
/**
* Perform a typecast upon the expression, returning a new
* expression object.
* This method does not cause type conversion:
* the runtime type is not changed.
* Warning: may result in a runtime failure.
* @param type intended type of the expression
* @return new expression of the given type
*/
<X> Expression<X> as(Class<X> type);
}
6.3.11. Predicate Interface
package jakarta.persistence.criteria;
import java.util.List;
/**
* The type of a simple or compound predicate: a conjunction or
* disjunction of restrictions.
* A simple predicate is considered to be a conjunction with a
* single conjunct.
*
* @since 2.0
*/
public interface Predicate extends Expression<Boolean> {
public static enum BooleanOperator {
AND, OR
}
/**
* Return the boolean operator for the predicate.
* If the predicate is simple, this is <code>AND</code>.
* @return boolean operator for the predicate
*/
BooleanOperator getOperator();
/**
* Whether the predicate has been created from another
* predicate by applying the <code>Predicate.not()</code> method
* or the <code>CriteriaBuilder.not()</code> method.
* @return boolean indicating if the predicate is
* a negated predicate
*/
boolean isNegated();
/**
* Return the top-level conjuncts or disjuncts of the predicate.
* Returns empty list if there are no top-level conjuncts or
* disjuncts of the predicate.
* Modifications to the list do not affect the query.
* @return list of boolean expressions forming the predicate
*/
List<Expression<Boolean>> getExpressions();
/**
* Create a negation of the predicate.
* @return negated predicate
*/
Predicate not();
}
6.3.12. Path Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.PluralAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Bindable;
import jakarta.persistence.metamodel.MapAttribute;
/**
* Represents a simple or compound attribute path from a
* bound type or collection, and is a "primitive" expression.
*
* @param <X> the type referenced by the path
*
* @since 2.0
*/
public interface Path<X> extends Expression<X> {
/**
* Return the bindable object that corresponds to the
* path expression.
* @return bindable object corresponding to the path
*/
Bindable<X> getModel();
/**
* Return the parent "node" in the path or null if no parent.
* @return parent
*/
Path<?> getParentPath();
/**
* Create a path corresponding to the referenced
* single-valued attribute.
* @param attribute single-valued attribute
* @return path corresponding to the referenced attribute
*/
<Y> Path<Y> get(SingularAttribute<? super X, Y> attribute);
/**
* Create a path corresponding to the referenced
* collection-valued attribute.
* @param collection collection-valued attribute
* @return expression corresponding to the referenced attribute
*/
<E, C extends java.util.Collection<E>> Expression<C> get(PluralAttribute<X, C, E> collection);
/**
* Create a path corresponding to the referenced
* map-valued attribute.
* @param map map-valued attribute
* @return expression corresponding to the referenced attribute
*/
<K, V, M extends java.util.Map<K, V>> Expression<M> get(MapAttribute<X, K, V> map);
/**
* Create an expression corresponding to the type of the path.
* @return expression corresponding to the type of the path
*/
Expression<Class<? extends X>> type();
//String-based:
/**
* Create a path corresponding to the referenced attribute.
*
* <p> Note: Applications using the string-based API may need to
* specify the type resulting from the <code>get</code> operation in order
* to avoid the use of <code>Path</code> variables.
*
* <pre>
* For example:
*
* CriteriaQuery<Person> q = cb.createQuery(Person.class);
* Root<Person> p = q.from(Person.class);
* q.select(p)
* .where(cb.isMember("joe",
* p.<Set<String>>get("nicknames")));
*
* rather than:
*
* CriteriaQuery<Person> q = cb.createQuery(Person.class);
* Root<Person> p = q.from(Person.class);
* Path<Set<String>> nicknames = p.get("nicknames");
* q.select(p)
* .where(cb.isMember("joe", nicknames));
* </pre>
*
* @param attributeName name of the attribute
* @return path corresponding to the referenced attribute
* @throws IllegalStateException if invoked on a path that
* corresponds to a basic type
* @throws IllegalArgumentException if attribute of the given
* name does not otherwise exist
*/
<Y> Path<Y> get(String attributeName);
}
6.3.13. FetchParent Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.PluralAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
/**
* Represents an element of the from clause which may
* function as the parent of Fetches.
*
* @param <Z> the source type
* @param <X> the target type
*
* @since 2.0
*/
public interface FetchParent<Z, X> {
/**
* Return the fetch joins that have been made from this type.
* Returns empty set if no fetch joins have been made from
* this type.
* Modifications to the set do not affect the query.
* @return fetch joins made from this type
*/
java.util.Set<Fetch<X, ?>> getFetches();
/**
* Create a fetch join to the specified single-valued attribute
* using an inner join.
* @param attribute target of the join
* @return the resulting fetch join
*/
<Y> Fetch<X, Y> fetch(SingularAttribute<? super X, Y> attribute);
/**
* Create a fetch join to the specified single-valued attribute
* using the given join type.
* @param attribute target of the join
* @param jt join type
* @return the resulting fetch join
*/
<Y> Fetch<X, Y> fetch(SingularAttribute<? super X, Y> attribute, JoinType jt);
/**
* Create a fetch join to the specified collection-valued
* attribute using an inner join.
* @param attribute target of the join
* @return the resulting join
*/
<Y> Fetch<X, Y> fetch(PluralAttribute<? super X, ?, Y> attribute);
/**
* Create a fetch join to the specified collection-valued
* attribute using the given join type.
* @param attribute target of the join
* @param jt join type
* @return the resulting join
*/
<Y> Fetch<X, Y> fetch(PluralAttribute<? super X, ?, Y> attribute, JoinType jt);
//String-based:
/**
* Create a fetch join to the specified attribute using an
* inner join.
* @param attributeName name of the attribute for the
* target of the join
* @return the resulting fetch join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
@SuppressWarnings("hiding")
<X, Y> Fetch<X, Y> fetch(String attributeName);
/**
* Create a fetch join to the specified attribute using
* the given join type.
* @param attributeName name of the attribute for the
* target of the join
* @param jt join type
* @return the resulting fetch join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
@SuppressWarnings("hiding")
<X, Y> Fetch<X, Y> fetch(String attributeName, JoinType jt);
}
6.3.14. Fetch Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.Attribute;
/**
* Represents a join-fetched association or attribute.
*
* @param <Z> the source type of the fetch
* @param <X> the target type of the fetch
*
* @since 2.0
*/
public interface Fetch<Z, X> extends FetchParent<Z, X> {
/**
* Return the metamodel attribute corresponding to the
* fetch join.
* @return metamodel attribute for the join
*/
Attribute<? super Z, ?> getAttribute();
/**
* Return the parent of the fetched item.
* @return fetch parent
*/
FetchParent<?, Z> getParent();
/**
* Return the join type used in the fetch join.
* @return join type
*/
JoinType getJoinType();
}
6.3.15. From Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.CollectionAttribute;
import jakarta.persistence.metamodel.ListAttribute;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.SetAttribute;
import java.util.Set;
/**
* Represents a bound type, usually an entity that appears in
* the from clause, but may also be an embeddable belonging to
* an entity in the from clause.
* <p> Serves as a factory for Joins of associations, embeddables, and
* collections belonging to the type, and for Paths of attributes
* belonging to the type.
*
* @param <Z> the source type
* @param <X> the target type
*
* @since 2.0
*/
@SuppressWarnings("hiding")
public interface From<Z, X> extends Path<X>, FetchParent<Z, X> {
/**
* Return the joins that have been made from this bound type.
* Returns empty set if no joins have been made from this
* bound type.
* Modifications to the set do not affect the query.
* @return joins made from this type
*/
Set<Join<X, ?>> getJoins();
/**
* Whether the <code>From</code> object has been obtained as a result of
* correlation (use of a <code>Subquery</code> <code>correlate</code>
* method).
* @return boolean indicating whether the object has been
* obtained through correlation
*/
boolean isCorrelated();
/**
* Returns the parent <code>From</code> object from which the correlated
* <code>From</code> object has been obtained through correlation (use
* of a <code>Subquery</code> <code>correlate</code> method).
* @return the parent of the correlated From object
* @throws IllegalStateException if the From object has
* not been obtained through correlation
*/
From<Z, X> getCorrelationParent();
/**
* Create an inner join to the specified single-valued
* attribute.
* @param attribute target of the join
* @return the resulting join
*/
<Y> Join<X, Y> join(SingularAttribute<? super X, Y> attribute);
/**
* Create a join to the specified single-valued attribute
* using the given join type.
* @param attribute target of the join
* @param jt join type
* @return the resulting join
*/
<Y> Join<X, Y> join(SingularAttribute<? super X, Y> attribute, JoinType jt);
/**
* Create an inner join to the specified Collection-valued
* attribute.
* @param collection target of the join
* @return the resulting join
*/
<Y> CollectionJoin<X, Y> join(CollectionAttribute<? super X, Y> collection);
/**
* Create an inner join to the specified Set-valued attribute.
* @param set target of the join
* @return the resulting join
*/
<Y> SetJoin<X, Y> join(SetAttribute<? super X, Y> set);
/**
* Create an inner join to the specified List-valued attribute.
* @param list target of the join
* @return the resulting join
*/
<Y> ListJoin<X, Y> join(ListAttribute<? super X, Y> list);
/**
* Create an inner join to the specified Map-valued attribute.
* @param map target of the join
* @return the resulting join
*/
<K, V> MapJoin<X, K, V> join(MapAttribute<? super X, K, V> map);
/**
* Create a join to the specified Collection-valued attribute
* using the given join type.
* @param collection target of the join
* @param jt join type
* @return the resulting join
*/
<Y> CollectionJoin<X, Y> join(CollectionAttribute<? super X, Y> collection, JoinType jt);
/**
* Create a join to the specified Set-valued attribute using
* the given join type.
* @param set target of the join
* @param jt join type
* @return the resulting join
*/
<Y> SetJoin<X, Y> join(SetAttribute<? super X, Y> set, JoinType jt);
/**
* Create a join to the specified List-valued attribute using
* the given join type.
* @param list target of the join
* @param jt join type
* @return the resulting join
*/
<Y> ListJoin<X, Y> join(ListAttribute<? super X, Y> list, JoinType jt);
/**
* Create a join to the specified Map-valued attribute using
* the given join type.
* @param map target of the join
* @param jt join type
* @return the resulting join
*/
<K, V> MapJoin<X, K, V> join(MapAttribute<? super X, K, V> map, JoinType jt);
//String-based:
/**
* Create an inner join to the specified attribute.
* @param attributeName name of the attribute for the
* target of the join
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> Join<X, Y> join(String attributeName);
/**
* Create an inner join to the specified Collection-valued
* attribute.
* @param attributeName name of the attribute for the
* target of the join
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> CollectionJoin<X, Y> joinCollection(String attributeName);
/**
* Create an inner join to the specified Set-valued attribute.
* @param attributeName name of the attribute for the
* target of the join
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> SetJoin<X, Y> joinSet(String attributeName);
/**
* Create an inner join to the specified List-valued attribute.
* @param attributeName name of the attribute for the
* target of the join
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> ListJoin<X, Y> joinList(String attributeName);
/**
* Create an inner join to the specified Map-valued attribute.
* @param attributeName name of the attribute for the
* target of the join
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, K, V> MapJoin<X, K, V> joinMap(String attributeName);
/**
* Create a join to the specified attribute using the given
* join type.
* @param attributeName name of the attribute for the
* target of the join
* @param jt join type
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> Join<X, Y> join(String attributeName, JoinType jt);
/**
* Create a join to the specified Collection-valued attribute
* using the given join type.
* @param attributeName name of the attribute for the
* target of the join
* @param jt join type
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> CollectionJoin<X, Y> joinCollection(String attributeName, JoinType jt);
/**
* Create a join to the specified Set-valued attribute using
* the given join type.
* @param attributeName name of the attribute for the
* target of the join
* @param jt join type
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> SetJoin<X, Y> joinSet(String attributeName, JoinType jt);
/**
* Create a join to the specified List-valued attribute using
* the given join type.
* @param attributeName name of the attribute for the
* target of the join
* @param jt join type
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, Y> ListJoin<X, Y> joinList(String attributeName, JoinType jt);
/**
* Create a join to the specified Map-valued attribute using
* the given join type.
* @param attributeName name of the attribute for the
* target of the join
* @param jt join type
* @return the resulting join
* @throws IllegalArgumentException if attribute of the given
* name does not exist
*/
<X, K, V> MapJoin<X, K, V> joinMap(String attributeName, JoinType jt);
}
6.3.16. Root Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.EntityType;
/**
* A root type in the from clause.
* Query roots always reference entities.
*
* @param <X> the entity type referenced by the root
*
* @since 2.0
*/
public interface Root<X> extends From<X, X> {
/**
* Return the metamodel entity corresponding to the root.
* @return metamodel entity corresponding to the root
*/
EntityType<X> getModel();
}
6.3.17. Join Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.Attribute;
/**
* A join to an entity, embeddable, or basic type.
*
* @param <Z> the source type of the join
* @param <X> the target type of the join
*
* @since 2.0
*/
public interface Join<Z, X> extends From<Z, X> {
/**
* Modify the join to restrict the result according to the
* specified ON condition and return the join object.
* Replaces the previous ON condition, if any.
* @param restriction a simple or compound boolean expression
* @return the modified join object
* @since 2.1
*/
Join<Z, X> on(Expression<Boolean> restriction);
/**
* Modify the join to restrict the result according to the
* specified ON condition and return the join object.
* Replaces the previous ON condition, if any.
* @param restrictions zero or more restriction predicates
* @return the modified join object
* @since 2.1
*/
Join<Z, X> on(Predicate... restrictions);
/**
* Return the predicate that corresponds to the ON
* restriction(s) on the join, or null if no ON condition
* has been specified.
* @return the ON restriction predicate
* @since 2.1
*/
Predicate getOn();
/**
* Return the metamodel attribute corresponding to the join.
* @return metamodel attribute corresponding to the join
*/
Attribute<? super Z, ?> getAttribute();
/**
* Return the parent of the join.
* @return join parent
*/
From<?, Z> getParent();
/**
* Return the join type.
* @return join type
*/
JoinType getJoinType();
}
6.3.18. JoinType
package jakarta.persistence.criteria;
/**
* Defines the three types of joins.
*
* Right outer joins and right outer fetch joins are not required
* to be supported. Applications that use <code>RIGHT</code> join
* types will not be portable.
*
* @since 2.0
*/
public enum JoinType {
/** Inner join. */
INNER,
/** Left outer join. */
LEFT,
/** Right outer join. */
RIGHT
}
6.3.19. PluralJoin Interface
package jakarta.persistence.criteria;
import jakarta.persistence.metamodel.PluralAttribute;
/**
* The <code>PluralJoin</code> interface defines functionality
* that is common to joins to all collection types. It is
* not intended to be used directly in query construction.
*
* @param <Z> the source type
* @param <C> the collection type
* @param <E> the element type of the collection
*
* @since 2.0
*/
public interface PluralJoin<Z, C, E> extends Join<Z, E> {
/**
* Return the metamodel representation for the collection-valued
* attribute corresponding to the join.
* @return metamodel collection-valued attribute corresponding
* to the target of the join
*/
PluralAttribute<? super Z, C, E> getModel();
}
6.3.20. CollectionJoin Interface
package jakarta.persistence.criteria;
import java.util.Collection;
import jakarta.persistence.metamodel.CollectionAttribute;
/**
* The <code>CollectionJoin</code> interface is the type of the result of
* joining to a collection over an association or element
* collection that has been specified as a <code>java.util.Collection</code>.
*
* @param <Z> the source type of the join
* @param <E> the element type of the target <code>Collection</code>
*
* @since 2.0
*/
public interface CollectionJoin<Z, E>
extends PluralJoin<Z, Collection<E>, E> {
/**
* Modify the join to restrict the result according to the
* specified ON condition and return the join object.
* Replaces the previous ON condition, if any.
* @param restriction a simple or compound boolean expression
* @return the modified join object
* @since 2.1
*/
CollectionJoin<Z, E> on(Expression<Boolean> restriction);
/**
* Modify the join to restrict the result according to the
* specified ON condition and return the join object.
* Replaces the previous ON condition, if any.
* @param restrictions zero or more restriction predicates
* @return the modified join object
* @since 2.1
*/
CollectionJoin<Z, E> on(Predicate... restrictions);
/**
* Return the metamodel representation for the collection
* attribute.
* @return metamodel type representing the <code>Collection</code> that is
* the target of the join
*/
CollectionAttribute<? super Z, E> getModel();
}
6.3.21. SetJoin Interface
package jakarta.persistence.criteria;
import java.util.Set;
import jakarta.persistence.metamodel.SetAttribute;
/**
* The <code>SetJoin</code> interface is the type of the result of
* joining to a collection over an association or element
* collection that has been specified as a <code>java.util.Set</code>.
*
* @param <Z> the source type of the join
* @param <E> the element type of the target <code>Set</code>
*
* @since 2.0
*/
public interface SetJoin<Z, E> extends PluralJoin<Z, Set<E>, E> {
/**
* Modify the join to restrict the result according to the
* specified ON condition and return the join object.
* Replaces the previous ON condition, if any.
* @param restriction a simple or compound boolean expression
* @return the modified join object
* @since 2.1
*/
SetJoin<Z, E> on(Expression<Boolean> restriction);
/**
* Modify the join to restrict the result according to the
* specified ON condition and return the join object.
* Replaces the previous ON condition, if any.
* @param restrictions zero or more restriction predicates
* @return the modified join object
* @since 2.1
*/
SetJ