«1. Обзор
Ранее мы сосредоточились на том, как начать работу с Apache Cayenne.
В этой статье мы расскажем, как писать простые и сложные запросы с помощью ORM.
2. Настройка
Настройка аналогична той, что использовалась в предыдущей статье.
Кроме того, перед каждым тестом мы сохраняем трех авторов и в конце удаляем их:
-
Paul Xavier pAuL Smith Vicky Sarra
3. ObjectSelect
Давайте начнем с простого и посмотрим, как мы можем получить всех авторов с именами, содержащими «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);
}
Нин наоборот, здесь в результате будет присутствовать только «Vicky»:
@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: для построения выражения LIKE likeIgnoreCaseExp: используется для построения выражения LIKE_IGNORE_CASE containsExp : выражение для запроса LIKE с шаблоном, совпадающим в любом месте строки. containsIgnoreCaseExp: то же, что и containsExp, но с использованием подхода, не учитывающего регистр. endWithExp: выражение, которое соответствует концу строки. endWithIgnoreCaseExp: выражение, которое соответствует концу строки с использованием подхода без учета регистра. expTrue: для логического истинного выражения. оператор orExp: связать два выражения с помощью оператора или
Дополнительные написанные тесты доступны в исходном коде статьи, проверьте репозиторий 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<Author> authorsTwo = context.performQuery(query);
assertEquals(authorsTwo.size(), 1);
}
Это означает, что если вы не укажете какое-либо выражение для запроса (SelectQuery), результатом будут все записи таблицы Автор.
Аналогичный запрос можно выполнить с помощью выражения containsIgnoreCaseExp, чтобы получить всех авторов с именем, содержащим Paul, независимо от регистра букв:
@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», в case без учета регистра (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<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");
}
Здесь вместо использования запроса .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. SQLTemplate
SQLTemplate также является одной из альтернатив, которые мы можем использовать с Cayenne, чтобы не использовать запросы в объектном стиле.
Создание запросов с помощью SQLTemplate напрямую связано с написанием собственных операторов SQL с некоторыми параметрами. Давайте реализуем несколько быстрых примеров.
Вот как мы удаляем всех авторов после каждого теста:
@After
void deleteAllAuthors() {
SQLTemplate deleteAuthors = new SQLTemplate(
Author.class, "delete from author");
context.performGenericQuery(deleteAuthors);
}
«
@Test
void givenAuthors_whenFindAllSQLTmplt_thenWeGetThreeAuthors() {
SQLTemplate select = new SQLTemplate(
Author.class, "select * from Author");
List<Author> authors = context.performQuery(select);
assertEquals(authors.size(), 3);
}
«Чтобы найти всех зарегистрированных авторов, нам просто нужно применить SQL-запрос select * from Author, и мы сразу увидим, что результат правильный, поскольку у нас есть ровно три сохраненных автора:
@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");
}
Далее, давайте получим Author с name «Vicky Sarra»:
6. EJBQLQuery
Далее давайте запросим данные через 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);
}
Сначала поиск всех сохраненных авторов будет выглядеть так:
@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");
}
Давайте снова найдем Автора с именем «Vicky Sarra», но теперь с помощью EJBQLQuery:
@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 запросов, представленным в версии M4 Cayenne.
@Test
void whenInsertingSQLExec_thenWeGetNewAuthor() {
int inserted = SQLExec
.query("INSERT INTO Author (name) VALUES ('Baeldung')")
.update(context);
assertEquals(inserted, 1);
}
Простая вставка выглядит так:
@Test
void whenUpdatingSQLExec_thenItsUpdated() {
int updated = SQLExec.query(
"UPDATE Author SET name = 'Baeldung' "
+ "WHERE name = 'Vicky Sarra'")
.update(context);
assertEquals(updated, 1);
}
Далее мы можем обновить автора на основе его имени:
Более подробную информацию можно получить из документации.
8. Заключение
В этой статье мы рассмотрели несколько способов написания простых и более сложных запросов с помощью Cayenne.