Mysql
 sql >> Datenbank >  >> RDS >> Mysql

jooq Einzelabfrage mit Eins-zu-Viele-Beziehung

Es gibt viele Möglichkeiten, eine verschachtelte Sammlung mit SQL und / oder mit jOOQ zu materialisieren. Ich gehe nur einige davon durch:

Joins verwenden

Wenn Sie diese Sammlungen nicht tief verschachteln, denormalisieren (glätten) Sie Ihre Ergebnisse mit einem JOIN könnte den Trick für Sie erledigen, ohne zu viel Overhead hinzuzufügen, da Daten dupliziert werden. Im Wesentlichen schreiben Sie:

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

Die obige Karte enthält Experimentdatensätze als Schlüssel und verschachtelte Sammlungen, die alle Tags als Werte enthalten.

Zwei Abfragen erstellen

Wenn Sie einen komplexen Objektgraphen materialisieren möchten, ist die Verwendung von Joins möglicherweise nicht mehr optimal. Stattdessen möchten Sie wahrscheinlich die Daten in Ihrem Client aus zwei unterschiedlichen Abfragen erfassen:

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

Und

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

Und jetzt führen Sie die beiden Ergebnisse im Gedächtnis Ihres Kunden zusammen, z. B.

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

Verschachtelung von Sammlungen mit SQL/XML oder SQL/JSON

Für diese Frage war es nicht erforderlich, aber andere finden diese Frage möglicherweise auf der Suche nach einer Möglichkeit, viele Beziehungen mit jOOQ zu verschachteln. Ich habe hier eine Antwort gegeben . Beginnend mit jOOQ 3.14 können Sie die SQL/XML- oder SQL/JSON-Fähigkeiten Ihres RDBMS verwenden und dann Jackson, Gson oder JAXB verwenden, um Sammlungen wie diese zu verschachteln:

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

Wobei Experiment ist eine benutzerdefinierte Java-Klasse wie diese:

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

class Tag {
  long id;
  String name;
}

Verschachtelung von Sammlungen mit MULTISET

Noch besser als das obige, Sie können sich mit SQL/XML oder SQL/JSON hinter dem neuen MULTISET von jOOQ 3.15 verstecken Bedienerunterstützung . Angenommen, die obigen Java-Klassen sind Java 16-Datensätze (oder andere unveränderliche Klassen), können Sie sogar verschachtelte Sammlungstypen sicher Ihren DTOs zuordnen:

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

Wobei Experiment ist eine benutzerdefinierte Java-Klasse wie diese:

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

Siehe auch diesen Blogbeitrag für weitere Informationen .