Перейти к основному содержимому

Введение в запросы JDO 2/2

· 6 мин. чтения

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.foreach.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.foreach.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.foreach.jdo.query.ProductItem");
List<ProductItem> r = query.executeList();

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

4.2. Фильтр

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

Query query = pm.newQuery("SELECT FROM com.foreach.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.foreach.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.foreach.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.foreach.jdo.query.ProductItem "
+ "WHERE price < :threshold");
List<ProductItem> result = (List<ProductItem>) query.execute(10);

5. Типизированный JDOQL

Чтобы использовать 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. Перейдите к компилятору Java и убедитесь, что уровень соответствия компилятора 1.8 или выше.
  2. Перейдите в Компилятор Java → Обработка аннотаций и включите специальные настройки проекта и включите обработку аннотаций.
  3. Перейдите в Компилятор Java → Обработка аннотаций → Путь к фабрике , включите специальные настройки проекта, а затем добавьте в список следующие файлы jar: javax.jdo.jar, datanucleus-jdo-query.jar.

Приведенная выше подготовка означает, что всякий раз, когда мы компилируем сохраняемые классы, процессор аннотаций в datanucleus-jdo-query.jar будет генерировать класс запроса для каждого класса, аннотированного @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.foreach.jdo.query.ProductItem i where i.price < 10"
+ " and i.status = 'InStock'");
List<ProductItem> results = (List<ProductItem>) query.execute();

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

Дополнительные сведения о синтаксисе JPQL см. по этой ссылке .

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

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

Примеры кода в статье можно найти на GitHub .