Interrogation avancée dans Apache Cayenne

Interrogation avancée dans Apache Cayenne

1. Vue d'ensemble

Previously, nous nous sommes concentrés sur la façon de démarrer avec Apache Cayenne.

Dans cet article, nous expliquerons comment rédiger des requêtes simples et avancées avec l'ORM.

2. Installer

La configuration est similaire à celle utilisée dans l'article précédent.

De plus, avant chaque test, nous sauvons trois auteurs et à la fin, nous les supprimons:

  • Paul Xavier

  • Paul Smith

  • Vicky Sarra

3. ObjectSelect

Commençons simplement et voyons comment nous pouvons obtenir tous les auteurs dont le nom contient "Paul":

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

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

Voyons ensuite comment appliquer un type de requête LIKE insensible à la casse à la colonne Nom de l'auteur:

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

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

Ensuite, l'expressionendsWith() renverra un seul enregistrement car un seul auteur a le nom correspondant:

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

Une plus complexe interroge les auteurs dont les noms figurent dans une liste:

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

Celui denin est l'inverse, ici seul "Vicky" sera présent dans le résultat:

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

Notez que ces deux codes suivants sont identiques car ils créeront tous deux une expression du même type avec le même paramètre:

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

Voici une liste de quelques expressions disponibles dans les classesExpression etExpressionFactory:

  • likeExp: pour construire l'expression LIKE

  • likeIgnoreCaseExp: utilisé pour construire l'expression LIKE_IGNORE_CASE

  • containsExp: une expression pour une requête LIKE avec le modèle correspondant n'importe où dans la chaîne

  • containsIgnoreCaseExp: identique àcontainsExp mais en utilisant une approche insensible à la casse

  • startsWithExp: le motif doit correspondre au début de la chaîne

  • startsWithIgnoreCaseExp: similaire austartsWithExp mais en utilisant l'approche insensible à la casse

  • endsWithExp: une expression qui correspond à la fin d'une chaîne

  • endsWithIgnoreCaseExp: une expression qui correspond à la fin d'une chaîne en utilisant l'approche insensible à la casse

  • expTrue: pour l'expression booléennetrue

  • expFalse: pour l'expression booléennefalse

  • andExp: utilisé pour enchaîner deux expressions avec l'opérateurand

  • orExp: pour chaîner deux expressions à l'aide de l'opérateuror

D'autres tests écrits sont disponibles dans le code source de l'article, veuillez vérifier le référentielGithub.

4. SelectQuery

Il s'agit du type de requête le plus utilisé dans les applications utilisateur. LeSelectQuery décrit une API simple et puissante qui agit comme la syntaxe SQL, mais toujours avec des objets et des méthodes Java suivis de modèles de générateur pour construire des expressions plus complexes.

Nous parlons ici d'un langage d'expression dans lequel nous construisons des requêtes en utilisant à la fois les classesExpression (pour créer des expressions) aka qualifier etOrdering (pour trier les résultats) qui sont ensuite converties en SQL natif par l'ORM.

Pour voir cela en action, nous avons mis en place des tests qui montrent en pratique comment créer des expressions et trier des données.

Appliquons une requête LIKE pour obtenir les auteurs avec le nom comme "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);
}

Cela signifie que si vous ne fournissez aucune expression à la requête (SelectQuery), le résultat sera tous les enregistrements de la table Author.

Une requête similaire peut être effectuée à l'aide de l'expressioncontainsIgnoreCaseExp pour obtenir tous les auteurs dont le nom contient Paul quelle que soit la casse des lettres:

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

De même, obtenons les auteurs dont les noms contiennent «Paul», sans tenir compte de la casse (containsIgnoreCaseExp) et avec le nom qui se termine (endsWithExp) par la lettre 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 authors = context.performQuery(query);

    Author author = authors.get(0);

    assertEquals(authors.size(), 1);
    assertEquals(author.getName(), "pAuL Smith");
}

Un ordre croissant peut être effectué en utilisant la classeOrdering:

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

Ici, au lieu d'utiliserquery.addOrdering(Author.NAME.asc()),, nous pouvons également simplement utiliser la classeSortOrder pour obtenir l'ordre croissant:

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

Relativement il y a l'ordre décroissant:

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

Comme nous l'avons vu dans l'exemple précédent, une autre façon de définir cet ordre est:

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

5. SQLTemplate

SQLTemplate est également une alternative que nous pouvons utiliser avec Cayenne pour ne pas utiliser les requêtes de style objet.

Construire des requêtes avecSQLTemplate est directement relatif à l'écriture d'instructions SQL natives avec certains paramètres. Mettons en œuvre quelques exemples rapides.

Voici comment nous supprimons tous les auteurs après chaque test:

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

Pour trouver tous les auteurs enregistrés, il suffit d'appliquer la requête SQLselect * from Author et nous verrons directement que le résultat est correct car nous avons exactement trois auteurs enregistrés:

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

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

Ensuite, recherchons l'auteur avec le nom "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

Ensuite, interrogons les données via lesEJBQLQuery, qui ont été créés dans le cadre d'une expérience visant à adopter l'API Java Persistence à Cayenne.

Ici, les requêtes sont appliquées avec un style d'objet paramétré; Jetons un coup d'œil à quelques exemples pratiques.

Premièrement, la recherche de tous les auteurs enregistrés ressemblera à ceci:

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

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

Cherchons à nouveau l'auteur avec le nom "Vicky Sarra", mais maintenant avecEJBQLQuery:

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

Un exemple encore meilleur met à jour l'auteur:

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

Si nous voulons simplement sélectionner une colonne, nous devons utiliser cette requête“select a.name FROM Author a”. D'autres exemples sont disponibles dans le code source de l'article surGithub.

7. SQLExec

SQLExec est également une nouvelle API de requête fluide introduite à partir de la version M4 de Cayenne.

Un insert simple ressemble à ceci:

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

    assertEquals(inserted, 1);
}

Ensuite, nous pouvons mettre à jour un auteur en fonction de son nom:

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

    assertEquals(updated, 1);
}

Nous pouvons obtenir plus de détails à partir desdocumentation.

8. Conclusion

Dans cet article, nous avons examiné un certain nombre de façons d'écrire des requêtes simples et plus avancées à l'aide de Cayenne.

Comme toujours, le code source de cet article peut être trouvéover on GitHub.