Ved brug af JOIN
virker ikke til dette.
Din forespørgsel vil være ret ineffektiv, fordi hvis du bruger joinforbindelser på denne måde, opretter du et kartesisk produkt mellem bøgerne og artiklertabellen, hvilket resulterer i en del hukommelse og CPU-forbrug både i databasen og i din Java-klient, før du de-duplikerer alle de meningsløse kombinationer.
Den "korrekte" SQL-tilgang ville være at bruge MULTISET
som beskrevet i denne artikel her
. jOOQ 3.9 understøtter desværre ikke MULTISET
endnu
(og heller ikke mange databaser). Så du bør oprette to separate forespørgsler:
- Henter alle bøgerne
- Henter alle artiklerne
Og brug så noget som Java 8 Streams til at kortlægge dem til et enkelt objekt.
Brug af MULTISET
startende fra jOOQ 3.15
Heldigvis er der fra jOOQ 3.15 en klar løsning til at indlejre samlinger i SQL ved hjælp af MULTISET
. Din forespørgsel ville se sådan ud:
Brug af refleksion
List<Author> authors =
ctx.select(
AUTHOR.ID,
AUTHOR.NAME,
multiset(
select(BOOKS.TITLE)
.from(BOOKS)
.where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
).as("books"),
multiset(
select(ARTICLES.TITLE)
.from(ARTICLES)
.where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
).as("articles")
)
.from(AUTHOR)
.where(AUTHOR.ID.eq(id))
.fetchInto(Author.class);
Brug af typen sikker, annonce -hoc-konvertering
List<Author> authors =
ctx.select(
AUTHOR.ID,
AUTHOR.NAME,
multiset(
select(BOOKS.TITLE)
.from(BOOKS)
.where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
).as("books").convertFrom(r -> r.map(Record1::value1)),
multiset(
select(ARTICLES.TITLE)
.from(ARTICLES)
.where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
).as("articles").convertFrom(r -> r.map(Record1::value1))
)
.from(AUTHOR)
.where(AUTHOR.ID.eq(id))
.fetch(Records.mapping(Author::new));
For mere information om MULTISET
, se venligst dette blogindlæg
, eller de manuelle sektioner:
Brug af SQL/XML eller SQL/JSON fra jOOQ 3.14
Fra jOOQ 3.14 kan du indlejre samlinger via SQL/XML eller SQL/JSON, hvis dit RDBMS understøtter det. Du kan producere et dokument og derefter bruge noget som Gson, Jackson eller JAXB til at kortlægge det tilbage til dine Java-klasser. For eksempel:
List<Author> authors =
ctx.select(
AUTHOR.ID,
AUTHOR.NAME,
field(
select(jsonArrayAgg(BOOKS.TITLE))
.from(BOOKS)
.where(BOOKS.AUTHOR_ID.eq(AUTHOR.ID))
).as("books"),
field(
select(jsonArrayAgg(ARTICLES.TITLE))
.from(ARTICLES)
.where(ARTICLES.AUTHOR_ID.eq(AUTHOR.ID))
).as("articles")
)
.from(AUTHOR)
.where(AUTHOR.ID.eq(id))
.fetchInto(Author.class);
Bemærk, at JSON_ARRAYAGG()
samler tomme sæt til NULL
, ikke i en tom []
. Hvis det er et problem, skal du bruge COALESCE()