Existem muitas maneiras de materializar uma coleção aninhada com SQL e/ou com jOOQ. Estou passando por alguns deles:
Usando junções
Se você não aninhar profundamente essas coleções, desnormalizando (achatando) seus resultados com um
JOIN
pode fazer o truque para você, sem adicionar muita sobrecarga à medida que os dados estão sendo duplicados. Essencialmente, você escreverá:Map<ExperimentRecord, Result<Record>> map =
DSL.using(configuration)
.select()
.from(EXPERIMENT)
.join(TAGS)
.on(...)
.fetchGroups(EXPERIMENT);
O mapa acima contém registros de experimentos como chaves e coleções aninhadas contendo todas as tags como valores.
Criando duas consultas
Se você deseja materializar um gráfico de objeto complexo, o uso de junções pode não ser mais ideal. Em vez disso, você provavelmente deseja coletar os dados em seu cliente de duas consultas distintas:
Result<ExperimentRecord> experiments =
DSL.using(configuration)
.selectFrom(EXPERIMENT)
.fetch();
E
Result<TagsRecord> tags =
DSL.using(configuration)
.selectFrom(TAGS)
.where(... restrict to the previous experiments ...)
.fetch();
E agora, mescle os dois resultados na memória do seu cliente, por exemplo
experiments.stream()
.map(e -> new ExperimentWithTags(
e,
tags.stream()
.filter(t -> e.getId().equals(t.getExperimentId()))
.collect(Collectors.toList())
));
Aninhando coleções usando SQL/XML ou SQL/JSON
Esta pergunta não exigia isso, mas outros podem encontrar essa pergunta em busca de uma maneira de aninhar muitos relacionamentos com jOOQ. Forneci uma resposta aqui . A partir do jOOQ 3.14, você pode usar os recursos SQL/XML ou SQL/JSON do seu RDBMS e, em seguida, usar Jackson, Gson ou JAXB para aninhar coleções como esta:
List<Experiment> experiments =
ctx.select(
EXPERIMENT.asterisk(),
field(
select(jsonArrayAgg(jsonObject(TAGS.fields())))
.from(TAGS)
.where(TAGS.EXPERIMENT_ID.eq(EXPERIMENT.ID))
).as("tags")
)
.from(EXPERIMENT)
.fetchInto(Experiment.class);
Onde
Experiment
é uma classe Java personalizada como esta:class Experiment {
long id;
String name;
List<Tag> tags;
}
class Tag {
long id;
String name;
}
Aninhando coleções usando MULTISET
Ainda melhor que o acima, você pode se esconder usando SQL/XML ou SQL/JSON atrás do novo
MULTISET
do jOOQ 3.15 suporte ao operador
. Supondo que as classes Java acima sejam registros Java 16 (ou quaisquer outras classes imutáveis), você pode até mapear o tipo de coleções aninhadas com segurança em seus DTOs:List<Experiment> experiments =
ctx.select(
EXPERIMENT.ID,
EXPERIMENT.NAME,
multiset(
select(TAGS.ID, TAGS.NAME)
.from(TAGS)
.where(TAGS.EXPERIMENT_ID.eq(EXPERIMENT.ID))
).as("tags").convertFrom(r -> r.map(Records.mapping(Tag::new)))
)
.from(EXPERIMENT)
.fetch(Records.mapping(Experiment::new));
Onde
Experiment
é uma classe Java personalizada como esta:record Experiment(long id, String name, List<Tag> tags) {}
record Tag(long id, String name) {}
Veja também esta postagem do blog para obter mais informações .