Расширенный запрос в Apache Cayenne
1. обзор
Previously, мы сосредоточились на том, как начать работу с Apache Cayenne.
В этой статье мы расскажем, как писать простые и сложные запросы с помощью ORM.
2. Настроить
Настройка аналогична той, которая использовалась в предыдущей статье.
Кроме того, перед каждым тестом мы сохраняем трех авторов и в конце удаляем их:
-
Пол Ксавье
-
Пол Смит
-
Вики Сарра
3. ObjectSelectс
Давайте начнем с простого и посмотрим, как мы можем получить всех авторов с именами, содержащими слово «Paul»:
@Test
public void whenContainsObjS_thenWeGetOneRecord() {
List authors = ObjectSelect.query(Author.class)
.where(Author.NAME.contains("Paul"))
.select(context);
assertEquals(authors.size(), 1);
}
Затем давайте посмотрим, как мы можем применить тип запроса LIKE без учета регистра в столбце имени автора:
@Test
void whenLikeObjS_thenWeGetTwoAuthors() {
List authors = ObjectSelect.query(Author.class)
.where(Author.NAME.likeIgnoreCase("Paul%"))
.select(context);
assertEquals(authors.size(), 2);
}
Затем выражениеendsWith() вернет только одну запись, так как только один автор имеет соответствующее имя:
@Test
void whenEndsWithObjS_thenWeGetOrderedAuthors() {
List authors = ObjectSelect.query(Author.class)
.where(Author.NAME.endsWith("Sarra"))
.select(context);
Author firstAuthor = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(firstAuthor.getName(), "Vicky Sarra");
}
Более сложным является запрос авторов, имена которых находятся в списке:
@Test
void whenInObjS_thenWeGetAuthors() {
List names = Arrays.asList(
"Paul Xavier", "pAuL Smith", "Vicky Sarra");
List authors = ObjectSelect.query(Author.class)
.where(Author.NAME.in(names))
.select(context);
assertEquals(authors.size(), 3);
}
nin наоборот, здесь в результате будет только «Вики»:
@Test
void whenNinObjS_thenWeGetAuthors() {
List names = Arrays.asList(
"Paul Xavier", "pAuL Smith");
List authors = ObjectSelect.query(Author.class)
.where(Author.NAME.nin(names))
.select(context);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
Обратите внимание, что эти два следующих кода одинаковы, так как они оба создадут выражение одного типа с одним и тем же параметром:
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul");
Author.NAME.containsIgnoreCase("Paul");
Вот список некоторых доступных выражений в классахExpression иExpressionFactory:
-
likeExp: для построения выражения LIKE
-
likeIgnoreCaseExp: используется для построения выражения LIKE_IGNORE_CASE
-
containsExp: выражение для запроса LIKE с сопоставлением с образцом в любом месте строки
-
containsIgnoreCaseExp: то же, что иcontainsExp, но с использованием подхода без учета регистра
-
startsWithExp: шаблон должен соответствовать началу строки
-
startsWithIgnoreCaseExp: аналогичноstartsWithExp, но с использованием подхода без учета регистра
-
endsWithExp: выражение, которое соответствует концу строки
-
endsWithIgnoreCaseExp: выражение, которое соответствует концу строки с использованием подхода без учета регистра
-
expTrue: для логического выраженияtrue
-
expFalse: для логического выраженияfalse
-
andExp: используется для объединения двух выражений в цепочку с операторомand
-
orExp: объединить два выражения в цепочку с помощью оператораor
Дополнительные письменные тесты доступны в исходном коде статьи, пожалуйста, проверьте репозиторийGithub.
4. SelectQueryс
Это наиболее широко используемый тип запроса в пользовательских приложениях. SelectQuery описывает простой и мощный API, который действует как синтаксис SQL, но все же с объектами и методами Java, за которыми следуют шаблоны построителя для построения более сложных выражений.
Здесь мы говорим о языке выражений, в котором мы создаем запросы, используя классыExpression (для построения выражений), также известные как квалификатор, иOrdering (для сортировки результатов), которые затем преобразуются ORM в собственный SQL.
Чтобы увидеть это в действии, мы собрали несколько тестов, которые на практике показывают, как создавать выражения и сортировать данные.
Давайте применим запрос LIKE, чтобы получить авторов с таким именем, как «Paul»:
@Test
void whenLikeSltQry_thenWeGetOneAuthor() {
Expression qualifier
= ExpressionFactory.likeExp(Author.NAME.getName(), "Paul%");
SelectQuery query
= new SelectQuery(Author.class, qualifier);
List authorsTwo = context.performQuery(query);
assertEquals(authorsTwo.size(), 1);
}
Это означает, что если вы не предоставите какое-либо выражение для запроса (SelectQuery), результатом будут все записи таблицы Author.
Аналогичный запрос можно выполнить с помощью выраженияcontainsIgnoreCaseExp, чтобы получить всех авторов с именем, содержащим Paul, независимо от регистра букв:
@Test
void whenCtnsIgnorCaseSltQry_thenWeGetTwoAuthors() {
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul");
SelectQuery query
= new SelectQuery(Author.class, qualifier);
List authors = context.performQuery(query);
assertEquals(authors.size(), 2);
}
Аналогичным образом, давайте получим авторов с именами, содержащими «Paul», без учета регистра (containsIgnoreCaseExp) и с именем, которое заканчивается (endsWithExp) буквой h:
@Test
void whenCtnsIgnorCaseEndsWSltQry_thenWeGetTwoAuthors() {
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul")
.andExp(ExpressionFactory
.endsWithExp(Author.NAME.getName(), "h"));
SelectQuery query = new SelectQuery(
Author.class, qualifier);
List authors = context.performQuery(query);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "pAuL Smith");
}
Порядок возрастания может быть выполнен с помощью классаOrdering:
@Test
void whenAscOrdering_thenWeGetOrderedAuthors() {
SelectQuery query = new SelectQuery(Author.class);
query.addOrdering(Author.NAME.asc());
List authors = query.select(context);
Author firstAuthor = authors.get(0);
assertEquals(authors.size(), 3);
assertEquals(firstAuthor.getName(), "Paul Xavier");
}
Здесь вместо использованияquery.addOrdering(Author.NAME.asc()), мы можем просто использовать классSortOrder для получения порядка возрастания:
query.addOrdering(Author.NAME.getName(), SortOrder.ASCENDING);
Относительно есть нисходящий порядок:
@Test
void whenDescOrderingSltQry_thenWeGetOrderedAuthors() {
SelectQuery query = new SelectQuery(Author.class);
query.addOrdering(Author.NAME.desc());
List authors = query.select(context);
Author firstAuthor = authors.get(0);
assertEquals(authors.size(), 3);
assertEquals(firstAuthor.getName(), "pAuL Smith");
}
Как мы видели в предыдущем примере, другой способ установить этот порядок:
query.addOrdering(Author.NAME.getName(), SortOrder.DESCENDING);
5. SQLTemplateс
SQLTemplate также является альтернативой, которую мы можем использовать с Cayenne, чтобы не использовать запросы объектного стиля.
Создание запросов сSQLTemplate напрямую связано с написанием собственных операторов SQL с некоторыми параметрами. Давайте реализуем несколько быстрых примеров.
Вот как мы удаляем всех авторов после каждого теста:
@After
void deleteAllAuthors() {
SQLTemplate deleteAuthors = new SQLTemplate(
Author.class, "delete from author");
context.performGenericQuery(deleteAuthors);
}
Чтобы найти всех записанных авторов, нам просто нужно применить SQL-запросselect * from Author, и мы сразу увидим, что результат правильный, поскольку у нас есть ровно три сохраненных автора:
@Test
void givenAuthors_whenFindAllSQLTmplt_thenWeGetThreeAuthors() {
SQLTemplate select = new SQLTemplate(
Author.class, "select * from Author");
List authors = context.performQuery(select);
assertEquals(authors.size(), 3);
}
Затем давайте возьмем автора с именем «Вики Сарра»:
@Test
void givenAuthors_whenFindByNameSQLTmplt_thenWeGetOneAuthor() {
SQLTemplate select = new SQLTemplate(
Author.class, "select * from Author where name = 'Vicky Sarra'");
List authors = context.performQuery(select);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
6. EJBQLQueryс
Затем давайте запросим данные черезEJBQLQuery,, которые были созданы в рамках эксперимента по внедрению Java Persistence API в Cayenne.
Здесь запросы применяются с параметризованным стилем объекта; давайте посмотрим на несколько практических примеров.
Во-первых, поиск всех сохраненных авторов будет выглядеть так:
@Test
void givenAuthors_whenFindAllEJBQL_thenWeGetThreeAuthors() {
EJBQLQuery query = new EJBQLQuery("select a FROM Author a");
List authors = context.performQuery(query);
assertEquals(authors.size(), 3);
}
Давайте снова выполним поиск по автору с именем «Вики Сарра», но теперь сEJBQLQuery:
@Test
void givenAuthors_whenFindByNameEJBQL_thenWeGetOneAuthor() {
EJBQLQuery query = new EJBQLQuery(
"select a FROM Author a WHERE a.name = 'Vicky Sarra'");
List authors = context.performQuery(query);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
Еще лучший пример - обновление автора:
@Test
void whenUpdadingByNameEJBQL_thenWeGetTheUpdatedAuthor() {
EJBQLQuery query = new EJBQLQuery(
"UPDATE Author AS a SET a.name "
+ "= 'Vicky Edison' WHERE a.name = 'Vicky Sarra'");
QueryResponse queryResponse = context.performGenericQuery(query);
EJBQLQuery queryUpdatedAuthor = new EJBQLQuery(
"select a FROM Author a WHERE a.name = 'Vicky Edison'");
List authors = context.performQuery(queryUpdatedAuthor);
Author author = authors.get(0);
assertNotNull(author);
}
Если мы просто хотим выбрать столбец, мы должны использовать этот запрос“select a.name FROM Author a”. Дополнительные примеры доступны в исходном коде статьи наGithub.
7. SQLExecс
SQLExec - это также новый свободный API запросов, представленный в версии M4 Cayenne.
Простая вставка выглядит так:
@Test
void whenInsertingSQLExec_thenWeGetNewAuthor() {
int inserted = SQLExec
.query("INSERT INTO Author (name) VALUES ('example')")
.update(context);
assertEquals(inserted, 1);
}
Далее мы можем обновить автора на основе его имени:
@Test
void whenUpdatingSQLExec_thenItsUpdated() {
int updated = SQLExec.query(
"UPDATE Author SET name = 'example' "
+ "WHERE name = 'Vicky Sarra'")
.update(context);
assertEquals(updated, 1);
}
Мы можем получить более подробную информацию изdocumentation.
8. Заключение
В этой статье мы рассмотрели несколько способов написания простых и более сложных запросов с помощью Cayenne.
Как всегда, исходный код этой статьи можно найти вover on GitHub.