«1. Обзор

В предыдущей статье этой серии мы показали, как сохранять объекты Java в разных хранилищах данных. Дополнительные сведения см. в Руководстве по объектам данных Java.

JDO поддерживает различные языки запросов, чтобы предоставить разработчику гибкость в использовании наиболее знакомого ему языка запросов.

2. Языки запросов JDO

JDO поддерживает следующие языки запросов:

    JDOQL — язык запросов, использующий синтаксис Java Типизированный JDOQL — следующий синтаксису JDOQL, но предоставляющий API для упрощения использования запросов. SQL — используется только для РСУБД. JPQL — предоставляется Datanucleus, но не является частью спецификаций JDO.

3. API запросов

3.1. Создание запроса

Чтобы создать запрос, нам нужно указать язык, а также строку запроса:

Query query = pm.newQuery(
  "javax.jdo.query.SQL",
  "select * from product_item where price < 10");

Если мы не указываем язык, по умолчанию используется JDOQL:

Query query = pm.newQuery(
  "SELECT FROM com.baeldung.jdo.query.ProductItem WHERE price < 10");

3.2. Создание именованного запроса

Мы также можем определить запрос и обращаться к нему по сохраненному имени.

Для этого мы сначала создадим класс ProductItem:

@PersistenceCapable
public class ProductItem {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.INCREMENT)
    int id;
    String name;
    String status;
    String description;
    double price;

    //standard getters, setters & constructors
}

Затем мы добавим конфигурацию класса в файл META-INF/package.jdo, чтобы определить запрос и назвать его:

<jdo>
    <package name="com.baeldung.jdo.query">
        <class name="ProductItem" detachable="true" table="product_item">
            <query name="PriceBelow10" language="javax.jdo.query.SQL">
            <![CDATA[SELECT * FROM PRODUCT_ITEM WHERE PRICE < 10]]>
            </query>
        </class>
    </package>
</jdo>

~~ ~ Мы определили запрос с именем «PriceBelow10».

Мы можем использовать это в нашем коде:

Query<ProductItem> query = pm.newNamedQuery(
  ProductItem.class, "PriceBelow10");
List<ProductItem> items = query.executeList();

3.3. Закрытие запроса

Для экономии ресурсов мы можем закрыть запросы:

query.close();

Аналогично, мы можем закрыть конкретный результирующий набор, передав его в качестве параметра методу close():

query.close(ResultSet);

3.4 . Компиляция запроса

Если мы хотим проверить запрос, мы можем вызвать метод compile():

query.compile();

Если запрос недействителен, метод выдаст исключение JDOException.

4. JDOQL

JDOQL — это объектно-ориентированный язык запросов, предназначенный для реализации возможностей языка SQL и сохранения отношений объектов Java в модели приложения.

Запросы JDOQL могут быть определены в виде одной строки.

Прежде чем углубиться, давайте рассмотрим некоторые основные понятия:

4.1. Класс-кандидат

Класс-кандидат в JDOQL должен быть сохраняемым классом. Мы используем полное имя класса вместо имени таблицы на языке SQL:

Query query = pm.newQuery("SELECT FROM com.baeldung.jdo.query.ProductItem");
List<ProductItem> r = query.executeList();

Как видно из приведенного выше примера, com.baeldung.jdo.query.ProductItem является здесь классом-кандидатом.

4.2. Фильтр

Фильтр можно написать на Java, но он должен возвращать логическое значение:

Query query = pm.newQuery("SELECT FROM com.baeldung.jdo.query.ProductItem");
query.setFilter("status == 'SoldOut'");
List<ProductItem> result = query.executeList();

4.3. Методы

JDOQL не поддерживает все методы Java, но поддерживает различные методы, которые мы можем вызывать из запроса и которые можно использовать в широком диапазоне:

query.setFilter("this.name.startsWith('supported')");

Для получения более подробной информации о поддерживаемых методах, пожалуйста, проверьте эта ссылка.

4.4. Параметры

Мы можем передавать значения в запросы как параметры. Мы можем определить параметры явно или неявно.

Чтобы определить параметр явно:

Query query = pm.newQuery(
  "SELECT FROM com.baeldung.jdo.query.ProductItem "
  + "WHERE price < threshold PARAMETERS double threshold");
List<ProductItem> result = (List<ProductItem>) query.execute(10);

Этого также можно добиться с помощью метода setParameters:

Query query = pm.newQuery(
  "SELECT FROM com.baeldung.jdo.query.ProductItem "
  + "WHERE price < :threshold");
query.setParameters("double threshold");
List<ProductItem> result = (List<ProductItem>) query.execute(10);

Мы можем сделать это неявно, не определяя тип параметра:

Query query = pm.newQuery(
  "SELECT FROM com.baeldung.jdo.query.ProductItem "
  + "WHERE price < :threshold");
List<ProductItem> result = (List<ProductItem>) query.execute(10);

5 JDOQL Typed

Чтобы использовать JDOQLTypedQueryAPI, нам нужно подготовить среду.

5.1. Установка Maven

<dependency>
    <groupId>org.datanucleus</groupId>
    <artifactId>datanucleus-jdo-query</artifactId>
    <version>5.0.2</version>
</dependency>
...
<plugins>
    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

Последними версиями этих зависимостей являются datanucleus-jdo-query и maven-compiler-plugin.

5.2. Включение обработки аннотаций

Для Eclipse мы можем выполнить следующие шаги, чтобы включить обработку аннотаций:

  1. Go to Java Compiler and make sure the compiler compliance level is 1.8 or above
  2. Go to Java Compiler → Annotation Processing and enable the project specific settings and enable annotation processing
  3. Go to Java Compiler → Annotation Processing → Factory Path, enable the project specific settings and then add the following jars to the list: javax.jdo.jar, datanucleus-jdo-query.jar

Приведенная выше подготовка означает, что всякий раз, когда мы компилируем сохраняемые классы, процессор аннотаций в datanucleus-jdo-query.jar будет генерировать запрос. class для каждого класса, аннотированного @PersistenceCapable.

В нашем случае процессор генерирует класс QProductItem. Сгенерированный класс имеет почти то же имя, что и сохраняемый класс, хотя и с префиксом Q.

5.3. Создайте типизированный запрос JDOQL:

JDOQLTypedQuery<ProductItem> tq = pm.newJDOQLTypedQuery(ProductItem.class);
QProductItem cand = QProductItem.candidate();
tq = tq.filter(cand.price.lt(10).and(cand.name.startsWith("pro")));
List<ProductItem> results = tq.executeList();

Мы можем использовать класс запроса для доступа к полям-кандидатам и использовать его доступные методы Java.

6. SQL

JDO поддерживает язык SQL, если мы используем СУБД.

Давайте создадим SQL-запрос:

Query query = pm.newQuery("javax.jdo.query.SQL","select * from "
  + "product_item where price < ? and status = ?");
query.setClass(ProductItem.class);
query.setParameters(10,"InStock");
List<ProductItem> results = query.executeList();

Мы использовали setClass() для запроса, чтобы получить объекты ProductItem при выполнении запроса. В противном случае он извлекает тип объекта.

7. JPQL

JDO DataNucleus предоставляет язык JPQL.

Давайте создадим запрос, используя JPQL:

Query query = pm.newQuery("JPQL","select i from "
  + "com.baeldung.jdo.query.ProductItem i where i.price < 10"
  + " and i.status = 'InStock'");
List<ProductItem> results = (List<ProductItem>) query.execute();

«

«Имя сущности здесь — com.baeldung.jdo.query.ProductItem. Мы не можем использовать только имя класса. Это связано с тем, что JDO не имеет метаданных для определения имени объекта, такого как JPA. Мы определили ProductItem p, и после этого мы можем использовать p в качестве псевдонима для ссылки на ProductItem.

Для получения дополнительной информации о синтаксисе JPQL перейдите по этой ссылке.

8. Заключение

В этой статье мы показали различные языки запросов, поддерживаемые JDO. Мы показали, как сохранять именованные запросы для повторного использования, объяснили концепции JDOQL и показали, как использовать SQL и JPQL с JDO.