Mysql
 sql >> Base de données >  >> RDS >> Mysql

requête unique jooq avec une relation un à plusieurs

Il existe de nombreuses façons de matérialiser une collection imbriquée avec SQL, et/ou avec jOOQ. Je ne fais que passer en revue certains d'entre eux :

Utiliser des jointures

Si vous n'imbriquez pas profondément ces collections, dénormalisez (aplatissez) vos résultats avec un JOIN pourrait faire l'affaire pour vous, sans ajouter trop de surcharge car les données sont dupliquées. Essentiellement, vous écrivez :

Map<ExperimentRecord, Result<Record>> map =
DSL.using(configuration)
   .select()
   .from(EXPERIMENT)
   .join(TAGS)
   .on(...)
   .fetchGroups(EXPERIMENT);

La carte ci-dessus contient des enregistrements d'expérience en tant que clés et des collections imbriquées contenant toutes les balises en tant que valeurs.

Création de deux requêtes

Si vous souhaitez matérialiser un graphe d'objets complexe, l'utilisation de jointures peut ne plus être optimale. Au lieu de cela, vous souhaitez probablement collecter les données de votre client à partir de deux requêtes distinctes :

Result<ExperimentRecord> experiments = 
DSL.using(configuration)
   .selectFrom(EXPERIMENT)
   .fetch();

Et

Result<TagsRecord> tags =
DSL.using(configuration)
   .selectFrom(TAGS)
   .where(... restrict to the previous experiments ...)
   .fetch();
 

Et maintenant, fusionnez les deux résultats dans la mémoire de votre client, par exemple

experiments.stream()
           .map(e -> new ExperimentWithTags(
                e, 
                tags.stream()
                    .filter(t -> e.getId().equals(t.getExperimentId()))
                    .collect(Collectors.toList())
           ));

Imbriquer des collections à l'aide de SQL/XML ou SQL/JSON

Cette question ne l'exigeait pas, mais d'autres peuvent trouver cette question à la recherche d'un moyen d'imbriquer plusieurs relations avec jOOQ. J'ai fourni une réponse ici . À partir de jOOQ 3.14, vous pouvez utiliser les capacités SQL/XML ou SQL/JSON de votre SGBDR, puis utiliser Jackson, Gson ou JAXB pour imbriquer des collections comme ceci :

List<Experiment> experiments =
ctx.select(
      EXPERIMENT.asterisk(),
      field(
        select(jsonArrayAgg(jsonObject(TAGS.fields())))
        .from(TAGS)
        .where(TAGS.EXPERIMENT_ID.eq(EXPERIMENT.ID))
      ).as("tags")
    )
   .from(EXPERIMENT)
   .fetchInto(Experiment.class);

Experiment est une classe Java personnalisée comme celle-ci :

class Experiment {
  long id;
  String name;
  List<Tag> tags;
}

class Tag {
  long id;
  String name;
}

Imbriquer des collections à l'aide de MULTISET

Encore mieux que ce qui précède, vous pouvez vous cacher en utilisant SQL/XML ou SQL/JSON derrière le nouveau MULTISET de jOOQ 3.15 assistance opérateur . En supposant que les classes Java ci-dessus sont des enregistrements Java 16 (ou toute autre classe immuable), vous pouvez même mapper le type de collections imbriquées en toute sécurité dans vos DTO :

List<Experiment> experiments =
ctx.select(
      EXPERIMENT.ID,
      EXPERIMENT.NAME,
      multiset(
        select(TAGS.ID, TAGS.NAME)
        .from(TAGS)
        .where(TAGS.EXPERIMENT_ID.eq(EXPERIMENT.ID))
      ).as("tags").convertFrom(r -> r.map(Records.mapping(Tag::new)))
    )
   .from(EXPERIMENT)
   .fetch(Records.mapping(Experiment::new));

Experiment est une classe Java personnalisée comme celle-ci :

record Experiment(long id, String name, List<Tag> tags) {}
record Tag(long id, String name) {}

Voir aussi ce billet de blog pour plus d'informations .