Usando JOIN
não funciona para isso.
Sua consulta será bastante ineficiente porque, se você estiver usando junções dessa maneira, estará criando um produto cartesiano entre os livros e a tabela de artigos, resultando em bastante memória e consumo de CPU tanto no banco de dados quanto em seu cliente Java, antes de desduplicar todas as combinações sem sentido.
A abordagem SQL "correta" seria usar
MULTISET
conforme descrito neste artigo aqui
. Infelizmente, jOOQ 3.9 não suporta MULTISET
ainda
(nem muitos bancos de dados). Portanto, você deve criar duas consultas separadas:- Buscando todos os livros
- Buscando todos os artigos
E então use algo como Java 8 Streams para mapeá-los em um único objeto.
Usando MULTISET
a partir do jOOQ 3.15
Felizmente, a partir do jOOQ 3.15, existe uma solução pronta para uso para aninhar coleções em SQL usando
MULTISET
. Sua consulta ficaria assim:Usando reflexão
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);
Usando type safe, anúncio -hoc conversão
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));
Para mais informações sobre
MULTISET
, consulte esta postagem do blog
, ou as seções do manual:Usando SQL/XML ou SQL/JSON a partir do jOOQ 3.14
A partir do jOOQ 3.14, você pode aninhar coleções via SQL/XML ou SQL/JSON, se seu RDBMS suportar isso. Você pode produzir um documento e usar algo como Gson, Jackson ou JAXB para mapeá-lo de volta para suas classes Java. Por exemplo:
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);
Observe que
JSON_ARRAYAGG()
agrega conjuntos vazios em NULL
, não em um []
vazio . Se isso for um problema, use COALESCE()