11.10. Named Queries
Prev | Chapter 11. Query | Next

## 11.10. 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. `extension`s 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");

Prev | Up | Next
11.9. Single-String JDOQL | Home | 11.11. Delete By Query