Utilizzando JOIN
non funziona per questo.
La tua query sarà piuttosto inefficiente perché se utilizzi i join in questo modo, stai creando un prodotto cartesiano tra i libri e la tabella degli articoli, con conseguente consumo di memoria e CPU sia nel database che nel client Java, prima di deduplicare tutte le combinazioni senza senso.
L'approccio SQL "corretto" sarebbe quello di utilizzare MULTISET
come descritto in questo articolo qui
. Sfortunatamente, jOOQ 3.9 non supporta MULTISET
ancora
(né molti database). Quindi, dovresti creare due query separate:
- Recupero di tutti i libri
- Recupero di tutti gli articoli
E poi usa qualcosa come Java 8 Streams per mapparli in un singolo oggetto.
Utilizzo di MULTISET
a partire da jOOQ 3.15
Fortunatamente, a partire da jOOQ 3.15, esiste una soluzione pronta all'uso per nidificare le raccolte in SQL utilizzando MULTISET
. La tua richiesta sarebbe simile a questa:
Utilizzo della riflessione
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);
Utilizzando type safe, ad -conversione ad hoc
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));
Per ulteriori informazioni su MULTISET
, fai riferimento a questo post del blog
, o le sezioni del manuale:
Utilizzo di SQL/XML o SQL/JSON a partire da jOOQ 3.14
A partire da jOOQ 3.14, puoi nidificare le raccolte tramite SQL/XML o SQL/JSON, se il tuo RDBMS lo supporta. Puoi produrre un documento e quindi utilizzare qualcosa come Gson, Jackson o JAXB per mapparlo di nuovo alle tue classi Java. Ad esempio:
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);
Nota che JSON_ARRAYAGG()
aggrega gli insiemi vuoti in NULL
, non in un []
vuoto . Se questo è un problema, usa COALESCE()