Pomocí JOIN
na to nefunguje.
Váš dotaz bude spíše neefektivní, protože pokud používáte spojení tímto způsobem, vytváříte karteziánský produkt mezi knihami a tabulkou článků, což vede ke značné spotřebě paměti a CPU v databázi i ve vašem Java klientovi, než deduplikujete všechny nesmyslné kombinace.
„Správným“ přístupem SQL by bylo použití MULTISET
jak je popsáno v tomto článku zde
. Bohužel jOOQ 3.9 nepodporuje MULTISET
ještě
(ani mnoho databází). Měli byste tedy vytvořit dva samostatné dotazy:
- Načítání všech knih
- Načítání všech článků
A pak použít něco jako Java 8 Streams k jejich mapování do jednoho objektu.
Pomocí MULTISET
počínaje jOOQ 3.15
Naštěstí od jOOQ 3.15 existuje hotové řešení pro vnořování kolekcí do SQL pomocí MULTISET
. Váš dotaz by vypadal takto:
Použití odrazu
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);
Použití typu safe, reklama -hoc konverze
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));
Další informace o MULTISET
, přejděte na tento blogový příspěvek
, nebo sekce manuálu:
Použití SQL/XML nebo SQL/JSON počínaje jOOQ 3.14
Počínaje jOOQ 3.14 můžete kolekce vnořovat pomocí SQL/XML nebo SQL/JSON, pokud to vaše RDBMS podporuje. Můžete vytvořit dokument a pak použít něco jako Gson, Jackson nebo JAXB k jeho mapování zpět do vašich tříd Java. Například:
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);
Všimněte si, že JSON_ARRAYAGG()
agreguje prázdné sady do NULL
, nikoli do prázdného []
. Pokud se jedná o problém, použijte COALESCE()