Met behulp van JOIN
werkt hier niet voor.
Uw zoekopdracht zal nogal inefficiënt zijn, want als u joins op deze manier gebruikt, maakt u een cartesiaans product tussen de boeken en de artikeltabel, wat resulteert in behoorlijk wat geheugen- en CPU-verbruik, zowel in de database als in uw Java-client, voordat u alle zinloze combinaties dedupliceert.
De "juiste" SQL-aanpak zou zijn om MULTISET
zoals beschreven in dit artikel hier
. Helaas biedt jOOQ 3.9 geen ondersteuning voor MULTISET
nog
(noch veel databases). U moet dus twee afzonderlijke zoekopdrachten maken:
- Alle boeken ophalen
- Alle artikelen ophalen
En gebruik dan iets als Java 8 Streams om ze in een enkel object in kaart te brengen.
Gebruik MULTISET
vanaf jOOQ 3.15
Gelukkig is er vanaf jOOQ 3.15 een kant-en-klare oplossing voor het nesten van collecties in SQL met behulp van MULTISET
. Uw zoekopdracht ziet er als volgt uit:
Reflectie gebruiken
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);
Met gebruik van type safe, ad -hoc conversie
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));
Voor meer informatie over MULTISET
, raadpleeg deze blogpost
, of de handleidingen:
SQL/XML of SQL/JSON gebruiken vanaf jOOQ 3.14
Vanaf jOOQ 3.14 kunt u collecties nesten via SQL/XML of SQL/JSON, als uw RDBMS dat ondersteunt. U kunt een document maken en vervolgens iets als Gson, Jackson of JAXB gebruiken om het terug te koppelen aan uw Java-klassen. Bijvoorbeeld:
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);
Merk op dat JSON_ARRAYAGG()
voegt lege sets samen tot NULL
, niet in een lege []
. Als dat een probleem is, gebruik dan COALESCE()