The JPA specification defines JPQL (a pseudo-OO query language, with SQL-like syntax), for
selecting objects from the datastore.
To provide a simple example, this is what you would do
Query q = em.createQuery("SELECT p FROM Person p WHERE p.lastName = 'Jones'");
List results = (List)q.getResultsList();
This finds all "Person" objects with surname of "Jones". You specify all details in the query.
In JPQL queries you define the query in a single string, defining the result, the candidate class(es), the filter,
any grouping, and the ordering. This string has to follow the following pattern
SELECT [<result>]
[FROM <candidate-class(es)>]
[WHERE <filter>]
[GROUP BY <grouping>]
[HAVING <having>]
[ORDER BY <ordering>]
The "keywords" in the query are shown in UPPER CASE are case-insensitive.
In the example shown you note that we did not specify the full class name. We used
Person p
and thereafter could refer to
p
as the alias. The
Person
is
called the
entity name
and in JPA MetaData this can be defined against each class
in its definition. For example
<entity class="org.datanucleus.company.Person" name="Person">
...
</entity>
In strict JPA the entity name cannot be a
MappedSuperclass
entity name. That is, if
you have an abstract superclass that is persistable, you cannot query for instances of that
superclass and its subclasses. We consider this a significant shortcoming of the querying
capability, and allow the entity name to also be of a
MappedSuperclass
. You are unlikely
to find this supported in other JPA implementations, but then maybe that's why you chose
DataNucleus?
In JPQL queries it is convenient to pass in parameters so we dont have to define the same query
for different values. Let's take two examples
Named Parameters :
Query q = em.createQuery("SELECT p FROM Person p WHERE p.lastName = :surname AND o.firstName = :forename");
q.setParameter("surname", theSurname);
q.setParameter("forename", theForename");
Numbered Parameters :
Query q = em.createQuery("SELECT p FROM Person p WHERE p.lastName = ?1 AND p.firstName = ?2");
q.setParameter(1, theSurname);
q.setParameter(2, theForename);
So in the first case we have parameters that are prefixed by
:
(colon) to identify them as
a parameter and we use that name when calling
Query.setParameter()
.
In the second case we have parameters that are prefixed by
?
(question mark) and are
numbered starting at 1. We then use the numbered position when calling
Query.setParameter()
.
With JPQL you can select the range of results to be returned. For example if you have a web page and you are paginating
the results of some search, you may want to get the results from a query in blocks of 20 say, with results
0 to 19 on the first page, then 20 to 39, etc. You can facilitate this as follows
Query q = em.createQuery("SELECT p FROM Person p WHERE p.age > 20");
q.setFirstResult(0);
q.setMaxResults(20);
So with this query we get results 0 to 19 inclusive.
There are two ways to execute a JPQL query. When you know it will return 0 or 1 results you call
Object result = query.getSingleResult();
If however you know that the query will return multiple results, or you just don't know then you would call
List results = query.getResultList();
The JPA specification defines a mode of JPQL for deleting objects from the datastore.
The syntax for deleting records is very similar to selecting them
DELETE FROM [<candidate-class>]
[WHERE <filter>]
The "keywords" in the query are shown in UPPER CASE are case-insensitive.
The JPA specification defines a mode of JPQL for updating objects in the datastore.
The syntax for updating records is very similar to selecting them
UPDATE [<candidate-class>] SET item1=value1, item2=value2
[WHERE <filter>]
The "keywords" in the query are shown in UPPER CASE are case-insensitive.