1. Обзор
Ранее мы сосредоточились на том, как начать работу с Apache Cayenne.
В этой статье мы расскажем, как писать простые и сложные запросы с помощью ORM.
2. Настройка
Настройка аналогична той, что использовалась в предыдущей статье.
Дополнительно перед каждым тестом мы сохраняем трех авторов и в конце удаляем их:
- Пол Ксавьер
- Пол Смит
- Вики Сарра
3. Выбор объекта
Давайте начнем с простого и посмотрим, как мы можем получить всех авторов с именами, содержащими «Paul»:
@Test
public void whenContainsObjS_thenWeGetOneRecord() {
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.contains("Paul"))
.select(context);
assertEquals(authors.size(), 1);
}
Далее давайте посмотрим, как мы можем применить тип запроса LIKE без учета регистра к столбцу имени автора:
@Test
void whenLikeObjS_thenWeGetTwoAuthors() {
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.likeIgnoreCase("Paul%"))
.select(context);
assertEquals(authors.size(), 2);
}
Затем выражение endWith()
вернет только одну запись, так как только один автор имеет совпадающее имя:
@Test
void whenEndsWithObjS_thenWeGetOrderedAuthors() {
List<Author> 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<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.in(names))
.select(context);
assertEquals(authors.size(), 3);
}
У нин
наоборот, здесь в результате будет присутствовать только «Вики»:
@Test
void whenNinObjS_thenWeGetAuthors() {
List names = Arrays.asList(
"Paul Xavier", "pAuL Smith");
List<Author> 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
: для построения выражения LIKElikeIgnoreCaseExp
: используется для построения выражения LIKE_IGNORE_CASE.containsExp
: выражение для запроса LIKE с шаблоном, совпадающим в любом месте строки.containsIgnoreCaseExp
: то же, что иcontainsExp
, но с использованием подхода без учета регистра .startWithExp
: шаблон должен соответствовать началу строкиstartWithIgnoreCaseExp
: похоже наstartWithExp,
но с использованием подхода без учета регистра .endWithExp
: выражение, соответствующее концу строкиendWithIgnoreCaseExp
: выражение, которое соответствует концу строки с использованием подхода без учета регистра.expTrue
: для логическогоистинного
выраженияexpFalse
: для логическоголожного
выраженияandExp
: используется для объединения двух выражений с помощью оператораand
orExp
: объединить два выражения в цепочку с помощью оператораили
Дополнительные письменные тесты доступны в исходном коде статьи, пожалуйста, проверьте репозиторий Github .
4. Выберите запрос
Это наиболее широко используемый тип запроса в пользовательских приложениях. SelectQuery описывает
простой и мощный API, который действует как синтаксис SQL, но все же с объектами и методами Java, за которыми следуют шаблоны построителя для создания более сложных выражений.
Здесь мы говорим о языке выражений, в котором мы строим запросы, используя как классы Expression
(для построения выражений), также известные как квалификаторы, так и классы Ordering
(для сортировки результатов), которые затем преобразуются в собственный SQL с помощью ORM.
Чтобы увидеть это в действии, мы собрали несколько тестов, которые на практике показывают, как создавать некоторые выражения и сортировать данные.
Давайте применим запрос LIKE, чтобы получить авторов с именем вроде «Paul» :
@Test
void whenLikeSltQry_thenWeGetOneAuthor() {
Expression qualifier
= ExpressionFactory.likeExp(Author.NAME.getName(), "Paul%");
SelectQuery query
= new SelectQuery(Author.class, qualifier);
List<Author> authorsTwo = context.performQuery(query);
assertEquals(authorsTwo.size(), 1);
}
Это означает, что если вы не предоставите какое-либо выражение для запроса ( SelectQuery
), результатом будут все записи таблицы Author.
Аналогичный запрос можно выполнить с помощью выражения containsIgnoreCaseExp
, чтобы получить всех авторов с именем, содержащим Пол, независимо от регистра букв:
@Test
void whenCtnsIgnorCaseSltQry_thenWeGetTwoAuthors() {
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul");
SelectQuery query
= new SelectQuery(Author.class, qualifier);
List<Author> authors = context.performQuery(query);
assertEquals(authors.size(), 2);
}
Точно так же давайте получим авторов с именами, содержащими «Paul», без учета регистра ( containsIgnoreCaseExp
) и с именами, которые заканчиваются ( endWithExp
) на букву 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<Author> 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<Author> 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<Author> 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. Шаблон SQL
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<Author> 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<Author> authors = context.performQuery(select);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
6. EJBQL-запрос
Далее давайте запросим данные через EJBQLQuery,
который был создан как часть эксперимента по внедрению Java Persistence API в Cayenne.
Здесь запросы применяются с параметризованным стилем объекта; давайте посмотрим на некоторые практические примеры.
Сначала поиск всех сохраненных авторов будет выглядеть так:
@Test
void givenAuthors_whenFindAllEJBQL_thenWeGetThreeAuthors() {
EJBQLQuery query = new EJBQLQuery("select a FROM Author a");
List<Author> 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<Author> 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<Author> authors = context.performQuery(queryUpdatedAuthor);
Author author = authors.get(0);
assertNotNull(author);
}
Если мы просто хотим выбрать столбец, мы должны использовать этот запрос «выбрать a.name FROM Author a»
. Больше примеров доступно в исходном коде статьи на Github .
7. SQLExec
SQLExec
также является новым API-интерфейсом запросов Fluent, представленным в версии M4 Cayenne.
Простая вставка выглядит так:
@Test
void whenInsertingSQLExec_thenWeGetNewAuthor() {
int inserted = SQLExec
.query("INSERT INTO Author (name) VALUES ('ForEach')")
.update(context);
assertEquals(inserted, 1);
}
Далее мы можем обновить автора на основе его имени:
@Test
void whenUpdatingSQLExec_thenItsUpdated() {
int updated = SQLExec.query(
"UPDATE Author SET name = 'ForEach' "
+ "WHERE name = 'Vicky Sarra'")
.update(context);
assertEquals(updated, 1);
}
Более подробную информацию мы можем получить из документации .
8. Заключение
В этой статье мы рассмотрели несколько способов написания простых и более сложных запросов с помощью Cayenne.
Как всегда, исходный код этой статьи можно найти на GitHub .