Erweiterte Abfrage in Apache Cayenne

Erweiterte Abfrage in Apache Cayenne

1. Überblick

Previously haben wir uns darauf konzentriert, wie Sie mit Apache Cayenne beginnen können.

In diesem Artikel erfahren Sie, wie Sie einfache und erweiterte Abfragen mit dem ORM schreiben.

2. Konfiguration

Das Setup ähnelt dem im vorherigen Artikel verwendeten.

Zusätzlich speichern wir vor jedem Test drei Autoren und entfernen sie am Ende:

  • Paul Xavier

  • Paul Smith

  • Vicky Sarra

3. ObjectSelect

Beginnen wir einfach und schauen wir uns an, wie wir alle Autoren mit Namen erhalten können, die "Paul" enthalten:

@Test
public void whenContainsObjS_thenWeGetOneRecord() {
    List authors = ObjectSelect.query(Author.class)
      .where(Author.NAME.contains("Paul"))
      .select(context);

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

Als nächstes wollen wir sehen, wie wir eine Abfrage vom Typ LIKE ohne Berücksichtigung der Groß- und Kleinschreibung auf die Namensspalte des Autors anwenden können:

@Test
void whenLikeObjS_thenWeGetTwoAuthors() {
    List authors = ObjectSelect.query(Author.class)
      .where(Author.NAME.likeIgnoreCase("Paul%"))
      .select(context);

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

Als nächstes gibt der AusdruckendsWith()nur einen Datensatz zurück, da nur ein Autor den passenden Namen hat:

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

Komplexer ist die Abfrage von Autoren, deren Namen in einer Liste enthalten sind:

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

Dasnin ist das Gegenteil, hier wird nur "Vicky" im Ergebnis vorhanden sein:

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

Beachten Sie, dass diese beiden folgenden Codes identisch sind, da beide einen Ausdruck desselben Typs mit demselben Parameter erstellen:

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

Hier ist eine Liste einiger verfügbarer Ausdrücke in den KlassenExpression undExpressionFactory:

  • likeExp: zum Erstellen des LIKE-Ausdrucks

  • likeIgnoreCaseExp: Wird zum Erstellen des Ausdrucks LIKE_IGNORE_CASE verwendet

  • containsExp: Ein Ausdruck für eine LIKE-Abfrage, deren Muster an einer beliebigen Stelle in der Zeichenfolge übereinstimmt

  • containsIgnoreCaseExp: WiecontainsExp, jedoch ohne Berücksichtigung der Groß- und Kleinschreibung

  • startsWithExp: Das Muster sollte mit dem Anfang der Zeichenfolge übereinstimmen

  • startsWithIgnoreCaseExp: Ähnlich wiestartsWithExp, jedoch unter Verwendung des Ansatzes ohne Berücksichtigung der Groß- und Kleinschreibung

  • endsWithExp: Ein Ausdruck, der dem Ende einer Zeichenfolge entspricht

  • endsWithIgnoreCaseExp: Ein Ausdruck, der mit dem Ende einer Zeichenfolge übereinstimmt, wobei die Groß- und Kleinschreibung nicht berücksichtigt wird

  • expTrue: für den booleschen Ausdrucktrue

  • expFalse: für den booleschen Ausdruckfalse

  • andExp: Wird verwendet, um zwei Ausdrücke mit dem Operatorand zu verketten

  • orExp: Zum Verketten von zwei Ausdrücken mit dem Operatoror

Weitere schriftliche Tests finden Sie in der Codequelle des Artikels. Überprüfen Sie das Repository vonGithub.

4. SelectQuery

Dies ist der am häufigsten verwendete Abfragetyp in Benutzeranwendungen. SelectQuery beschreibt eine einfache und leistungsstarke API, die sich wie die SQL-Syntax verhält, jedoch weiterhin Java-Objekte und -Methoden enthält, denen Builder-Muster folgen, um komplexere Ausdrücke zu erstellen.

Hier geht es um eine Ausdruckssprache, in der wir Abfragen sowohl mitExpression (zum Erstellen von Ausdrücken) als Qualifier- als auch mitOrdering-Klassen (zum Sortieren von Ergebnissen) erstellen, die vom ORM als nächstes in natives SQL konvertiert werden.

Um dies in Aktion zu sehen, haben wir einige Tests zusammengestellt, die in der Praxis zeigen, wie einige Ausdrücke erstellt und Daten sortiert werden.

Wenden wir eine LIKE-Abfrage an, um Autoren mit dem Namen "Paul": zu erhalten

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

Das heißt, wenn Sie der Abfrage keinen Ausdruck geben (SelectQuery), sind das Ergebnis alle Datensätze der Autorentabelle.

Eine ähnliche Abfrage kann mit dem AusdruckcontainsIgnoreCaseExpdurchgeführt werden, um alle Autoren mit dem Namen zu erhalten, der Paul enthält, unabhängig vom Fall der Buchstaben:

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

In ähnlicher Weise erhalten wir Autoren mit Namen, die "Paul" enthalten, wobei die Groß- und Kleinschreibung nicht berücksichtigt wird (containsIgnoreCaseExp) und der Name, der mit dem Buchstaben h endet (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");
}

Eine aufsteigende Reihenfolge kann mit der KlasseOrderingausgeführt werden:

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

Anstattquery.addOrdering(Author.NAME.asc()), zu verwenden, können wir hier auch einfach die KlasseSortOrder verwenden, um die aufsteigende Reihenfolge zu erhalten:

query.addOrdering(Author.NAME.getName(), SortOrder.ASCENDING);

Relativ gibt es die absteigende Reihenfolge:

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

Wie wir im vorherigen Beispiel gesehen haben, können Sie diese Reihenfolge auch wie folgt festlegen:

query.addOrdering(Author.NAME.getName(), SortOrder.DESCENDING);

5. SQLTemplate

SQLTemplate ist auch eine Alternative, die wir mit Cayenne verwenden können, um keine Abfrage im Objektstil zu verwenden.

Das Erstellen von Abfragen mitSQLTemplate ist direkt relativ zum Schreiben nativer SQL-Anweisungen mit einigen Parametern. Lassen Sie uns einige kurze Beispiele implementieren.

So löschen wir nach jedem Test alle Autoren:

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

Um alle aufgezeichneten Autoren zu finden, müssen wir nur die SQL-Abfrageselect * from Author anwenden und wir werden direkt sehen, dass das Ergebnis korrekt ist, da wir genau drei gespeicherte Autoren haben:

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

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

Als nächstes holen wir uns den Autor mit dem Namen "Vicky Sarra":

@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

Lassen Sie uns als Nächstes Daten überEJBQLQuery, abfragen, die im Rahmen eines Experiments zur Übernahme der Java-Persistenz-API in Cayenne erstellt wurden.

Hier werden die Abfragen mit einem parametrisierten Objektstil angewendet. Schauen wir uns einige praktische Beispiele an.

Zunächst sieht die Suche aller gespeicherten Autoren so aus:

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

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

Suchen wir den Autor erneut mit dem Namen "Vicky Sarra", jetzt jedoch mitEJBQLQuery:

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

Ein noch besseres Beispiel ist die Aktualisierung des Autors:

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

Wenn wir nur eine Spalte auswählen möchten, sollten wir diese Abfrage“select a.name FROM Author a” verwenden. Weitere Beispiele finden Sie im Quellcode des Artikels zuGithub.

7. SQLExec

SQLExec ist auch eine neue fließende Abfrage-API, die ab Version M4 von Cayenne eingeführt wurde.

Eine einfache Einfügung sieht folgendermaßen aus:

@Test
void whenInsertingSQLExec_thenWeGetNewAuthor() {
    int inserted = SQLExec
      .query("INSERT INTO Author (name) VALUES ('example')")
      .update(context);

    assertEquals(inserted, 1);
}

Als nächstes können wir einen Autor basierend auf seinem Namen aktualisieren:

@Test
void whenUpdatingSQLExec_thenItsUpdated() {
    int updated = SQLExec.query(
      "UPDATE Author SET name = 'example' "
      + "WHERE name = 'Vicky Sarra'")
      .update(context);

    assertEquals(updated, 1);
}

Wir können mehr Details vondocumentation erhalten.

8. Fazit

In diesem Artikel haben wir uns mit verschiedenen Möglichkeiten befasst, einfache und erweiterte Abfragen mit Cayenne zu schreiben.

Der Quellcode für diesen Artikel befindet sich wie immer inover on GitHub.