11.10. Named Queries

11.10.1. Defining Named Queries
11.10.2. Executing Named Queries

Named queries provide a means to define complex or commonly used queries in metadata. These queries have all the capabilities of queries created in code, including support for parameters, aggregates, and projections.

11.10.1. Defining Named Queries

You typically define named queries in query metadata files. These files use a .jdoquery extension, but otherwise follow the same naming and placement rules we outlined for .jdo files in Section 5.7, “Metadata Placement”.

Query metadata also has the same basic structure as persistence metadata. There is a root jdoquery element that contains package elements, which in turn contain class elements. extensions are sprinkled throughout. The only novel element is query.

<!ELEMENT jdoquery (extension*, (package|query)+, extension*)>

<!ELEMENT package (extension*, class+, extension*)>
<!ATTLIST package name CDATA #REQUIRED>

<!ELEMENT class (query+)>
<!ATTLIST class name CDATA #REQUIRED>

<!ELEMENT query ((#PCDATA|extension)*)>
<!ATTLIST query name CDATA #REQUIRED>
<!ATTLIST query language CDATA #IMPLIED>

<!ELEMENT extension ANY>
<!ATTLIST extension vendor-name CDATA #REQUIRED>
<!ATTLIST extension key CDATA #IMPLIED>
<!ATTLIST extension value CDATA #IMPLIED>

The query element defines a named query. You can place query elements just below the document's root element or at the class level. Queries within the root element do not have an automatic candidate class. Queries in a class element default to that candidate class.

Named queries are expressed in single-string form, which we detailed in the previous section. The text of the query goes within the query element. This element also has the following attributes:

  • name: The name of the query. This attribute is required.

  • language: The language of the query text. Defaults to javax.jdo.query.JDOQL. In Chapter 17, SQL Queries we discuss how to write SQL queries, and vendors may offer support for additional query languages.

The following example defines both a root-level and a class-level named query.

Example 11.24. Query Metadata Document

The salesReport query generates sales information. The findByTitle query, on the other hand, finds a Magazine by title. Note that this query does not use a from clause to name its candidate class; its candidate class defaults to the surrounding class element.

<?xml version="1.0"?>
<jdoquery>
    <query name="salesReport">
        select title, price * copiesSold from org.mag.Magazine
    </query>
    <package name="org.mag">
        <class name="Magazine">
            <query name="findByTitle">select unique where title == :t</query>
        </class>
    </package>
</jdoquery>

The Magazine query metadata file above might be in any of the following locations:

  • org/mag/Magazine.jdoquery

  • org/mag/package.jdoquery

  • org/package.jdoquery

  • package.jdoquery

You do not have to use separate .jdoquery files to define named queries, however. You can integrate query definitions right into your persistence metadata (.jdo files) or mapping metadata (.orm files). Just add query elements below the root element, or after the last field and before any fetch-group elements in any class. Here is what it looks like to define the queries above in Magazine's persistence metadata, rather than in a .jdoquery file:

Example 11.25. Persistence Metadata Document

<?xml version="1.0"?>
<jdo>
    <query name="salesReport">
        select title, price * copiesSold from org.mag.Magazine
    </query>
    <package name="org.mag">
        <class name="Magazine" objectid-class="Magazine$ObjectId">
            <field name="isbn" primary-key="true"/>
            <field name="title" primary-key="true"/>
            <field name="articles">
                <collection element-type="Article" dependent-element="true"/>
            </field> 
            <query name="findByTitle">select unique where title == :t</query>
            <fetch-group name="detail">
                <field name="publisher" fetch-depth="0"/>
                <field name="articles" fetch-depth="0"/>
            </fetch-group>
        </class>
    </package>
</jdo>

11.10.2. Executing Named Queries

public Query newNamedQuery (Class cls, String name);

At runtime, you obtain named queries with the PersistenceManager.newNamedQuery method. The Class argument specifies the class that defines the query. Use null if the query is defined outside the scope of a class. The String argument is the name of the query.

Before returning a named query, the system populates it with the information provided in the metadata, then compiles it to make sure it is valid. You can still change the query before executing it, using the methods of the Query interface. These changes won't affect other query instances returned from subsequent calls to newNamedQuery.

The example below executes the two queries we defined in Example 11.24, “Query Metadata Document”.

Example 11.26. Executing Named Queries

PersistenceManager pm = ...;
Query query = pm.newNamedQuery (null, "salesReport");
List sales = (List) query.execute ();
for (Iterator itr = sales.iterator (); itr.hasNext ();)
{
    Object[] salesData = (Object[]) itr.next ();
    processSalesData ((String) salesData[0], (Double) salesData[1]);
}
query.close (sales);

query = pm.newNamedQuery (Magazine.class, "findByTitle");
Magazine jdj = (Magazine) query.execute ("JDJ");

 

Skip navigation bar   Back to Top