sql >> Databasteknik >  >> RDS >> Mysql

jooq singelfråga med en till många relation

Det finns många sätt att materialisera en kapslad samling med SQL och/eller med jOOQ. Jag går bara igenom några av dem:

Använda joins

Om du inte kapar in dessa samlingar på djupet, avnormaliserar (planerar) dina resultat med en JOIN kan göra susen för dig, utan att lägga till för mycket overhead eftersom data dupliceras. I huvudsak kommer du att skriva:

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

Kartan ovan innehåller experimentposter som nycklar och kapslade samlingar som innehåller alla taggar som värden.

Skapar två frågor

Om du vill materialisera en komplex objektgraf kanske det inte längre är optimalt att använda kopplingar. Istället vill du förmodligen samla in data i din klient från två distinkta frågor:

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

Och

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

Och slå nu samman de två resultaten i din klients minne, t.ex.

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

Inkapsla samlingar med SQL/XML eller SQL/JSON

Den här frågan krävde det inte, men andra kanske hittar den här frågan i jakten på ett sätt att bygga ihop till många relationer med jOOQ. Jag har gett ett svar här . Från och med jOOQ 3.14 kan du använda din RDBMS:s SQL/XML- eller SQL/JSON-funktioner och sedan använda Jackson, Gson eller JAXB för att kapsla samlingar så här:

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

Där Experiment är en anpassad Java-klass så här:

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

class Tag {
  long id;
  String name;
}

Inkapsla samlingar med MULTISET

Ännu bättre än ovan, du kan gömma dig med SQL/XML eller SQL/JSON bakom jOOQ 3.15s nya MULTISET operatörssupport . Förutsatt att ovanstående Java-klasser är Java 16-poster (eller andra oföränderliga klasser), kan du till och med mappa kapslade samlingstyper säkert till dina DTO:er:

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

Där Experiment är en anpassad Java-klass så här:

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

Se även detta blogginlägg för mer information .



  1. Hur kan man iterera över lagrade procedurresultat från en annan lagrad procedur...utan markörer?

  2. SQL-fråga:Hur man får objekt från en kol ihopparad med en annan men inte vice versa

  3. XML som parameter i lagrad procedur (sql-server)

  4. Hur konfigurerar man rätt tidszon i JDBC?