«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.