Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Seleção um-para-muitos em Jooq

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:
  1. Buscando todos os livros
  2. 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()