Mysql
 sql >> Database >  >> RDS >> Mysql

jooq singola query con relazione uno a molti

Esistono molti modi per materializzare una raccolta nidificata con SQL e/o con jOOQ. Ne sto solo esaminando alcuni:

Utilizzo dei join

Se non annidi profondamente quelle raccolte, denormalizzando (appiattendo) i tuoi risultati con un JOIN potrebbe fare il trucco per te, senza aggiungere troppo sovraccarico poiché i dati vengono duplicati. In sostanza, scriverai:

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

La mappa sopra contiene record di esperimenti come chiavi e raccolte nidificate contenenti tutti i tag come valori.

Creazione di due query

Se vuoi materializzare un grafico di oggetti complessi, l'uso dei join potrebbe non essere più ottimale. Invece, probabilmente vorrai raccogliere i dati nel tuo client da due query distinte:

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

E

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

E ora, unisci i due risultati nella memoria del tuo cliente, ad es.

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

Nidificazione di raccolte utilizzando SQL/XML o SQL/JSON

Questa domanda non lo richiedeva, ma altri potrebbero trovare questa domanda alla ricerca di un modo per annidare relazioni a molti con jOOQ. Ho fornito una risposta qui . A partire da jOOQ 3.14, puoi utilizzare le funzionalità SQL/XML o SQL/JSON del tuo RDBMS, quindi utilizzare Jackson, Gson o JAXB per annidare raccolte in questo modo:

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

Dove Experiment è una classe Java personalizzata come questa:

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

class Tag {
  long id;
  String name;
}

Nidificazione di raccolte utilizzando MULTISET

Ancora meglio di quanto sopra, puoi nasconderti usando SQL/XML o SQL/JSON dietro il nuovo MULTISET di jOOQ 3.15 supporto dell'operatore . Supponendo che le classi Java di cui sopra siano record Java 16 (o qualsiasi altra classe immutabile), puoi persino mappare il tipo di raccolte nidificate in modo sicuro nei tuoi 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));

Dove Experiment è una classe Java personalizzata come questa:

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

Vedi anche questo post del blog per ulteriori informazioni .