Apache Cayenneでの高度なクエリ

Apache Cayenneの高度なクエリ

1. 概要

Previously、ApacheCayenneの使用を開始する方法に焦点を当てました。

この記事では、ORMを使用して単純で高度なクエリを作成する方法について説明します。

2. セットアップ

セットアップは、前の記事で使用したものと似ています。

さらに、各テストの前に3人の著者を保存し、最後にそれらを削除します。

  • ポール・ザビエル

  • ポールスミス

  • ヴィッキーサッラ

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);
}

次に、一致する名前が1人の作成者だけであるため、endsWith()式は1つのレコードのみを返します。

@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は反対で、ここでは「Vicky」のみが結果に表示されます。

@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");
}

次の2つのコードは同じであり、どちらも同じパラメーターで同じタイプの式を作成することに注意してください。

Expression qualifier = ExpressionFactory
  .containsIgnoreCaseExp(Author.NAME.getName(), "Paul");
Author.NAME.containsIgnoreCase("Paul");

ExpressionおよびExpressionFactoryクラス:で使用可能な式のリストを次に示します。

  • likeExp:LIKE式を作成するため

  • likeIgnoreCaseExp:LIKE_IGNORE_CASE式の作成に使用

  • containsExp:文字列内の任意の場所に一致するパターンを持つLIKEクエリの式

  • containsIgnoreCaseExpcontainsExpと同じですが、大文字と小文字を区別しないアプローチを使用します

  • startsWithExp:パターンは文字列の先頭と一致する必要があります

  • startsWithIgnoreCaseExpstartsWithExpと同様ですが、大文字と小文字を区別しないアプローチを使用します

  • endsWithExp:文字列の終わりに一致する式

  • endsWithIgnoreCaseExp:大文字と小文字を区別しないアプローチを使用して文字列の末尾に一致する式

  • expTrue:ブールtrue式の場合

  • expFalse:ブールfalse式の場合

  • andExpand演算子を使用して2つの式をチェーンするために使用されます

  • orExpor演算子を使用して2つの式をチェーンします

記事のコードソースには、さらに多くの記述されたテストがあります。Githubリポジトリを確認してください。

4. SelectQuery

これは、ユーザーアプリケーションで最も広く使用されているクエリタイプです。 SelectQueryは、SQL構文のように機能するシンプルで強力なAPIを記述しますが、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);
}

同様に、大文字と小文字を区別しない方法(containsIgnoreCaseExp)で、「Paul」を含む名前と、文字hで終わる名前(endsWithExp)を持つ作成者を取得しましょう。

@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で使用できる代替手段の1つでもあります。

SQLTemplateを使用したビルドクエリは、いくつかのパラメータを使用したネイティブSQLステートメントの記述に直接関連しています。 いくつかの簡単な例を実装しましょう。

各テスト後にすべての著者を削除する方法は次のとおりです。

@After
void deleteAllAuthors() {
    SQLTemplate deleteAuthors = new SQLTemplate(
      Author.class, "delete from author");
    context.performGenericQuery(deleteAuthors);
}

記録されたすべての作成者を見つけるには、SQLクエリselect * from Authorを適用するだけで、正確に3人の作成者が保存されているため、結果が正しいことが直接わかります。

@Test
void givenAuthors_whenFindAllSQLTmplt_thenWeGetThreeAuthors() {
    SQLTemplate select = new SQLTemplate(
      Author.class, "select * from Author");
    List authors = context.performQuery(select);

    assertEquals(authors.size(), 3);
}

次に、「VickySarra」という名前の著者を取得しましょう。

@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

次に、CayenneでJava Persistence APIを採用するための実験の一部として作成されたEJBQLQuery,を介してデータをクエリしてみましょう。

ここでは、クエリはパラメータ化されたオブジェクトスタイルで適用されます。いくつかの実用的な例を見てみましょう。

まず、保存されているすべての著者の検索は次のようになります。

@Test
void givenAuthors_whenFindAllEJBQL_thenWeGetThreeAuthors() {
    EJBQLQuery query = new EJBQLQuery("select a FROM Author a");
    List authors = context.performQuery(query);

    assertEquals(authors.size(), 3);
}

「VickySarra」という名前で著者をもう一度検索してみましょう。ただし、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は、CayenneのバージョンM4から導入された新しい流暢なクエリAPIでもあります。

単純な挿入は次のようになります。

@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にあります。