有很多方法可以使用 SQL 和/或 jOOQ 实现嵌套集合。我只是浏览了其中的一些:
使用连接
如果您没有深度嵌套这些集合,则使用 JOIN 对结果进行非规范化(展平)可能会为您解决问题,而不会在复制数据时增加太多开销。基本上,你会写:
Map<ExperimentRecord, Result<Record>> map =
DSL.using(configuration)
.select()
.from(EXPERIMENT)
.join(TAGS)
.on(...)
.fetchGroups(EXPERIMENT);
上图包含实验记录作为键,嵌套集合包含所有标签作为值。
创建两个查询
如果您想具体化一个复杂的对象图,使用连接可能不再是最佳选择。相反,您可能希望从两个不同的查询中收集客户端中的数据:
Result<ExperimentRecord> experiments =
DSL.using(configuration)
.selectFrom(EXPERIMENT)
.fetch();
和
Result<TagsRecord> tags =
DSL.using(configuration)
.selectFrom(TAGS)
.where(... restrict to the previous experiments ...)
.fetch();
现在,将两个结果合并到客户的内存中,例如
experiments.stream()
.map(e -> new ExperimentWithTags(
e,
tags.stream()
.filter(t -> e.getId().equals(t.getExperimentId()))
.collect(Collectors.toList())
));
使用 SQL/XML 或 SQL/JSON 嵌套集合
这个问题不需要它,但其他人可能会在寻找与 jOOQ 嵌套对多关系的方法时发现这个问题。 I've provided an answer here。从 jOOQ 3.14 开始,您可以使用 RDBMS 的 SQL/XML 或 SQL/JSON 功能,然后使用 Jackson、Gson 或 JAXB 来嵌套集合,如下所示:
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);
Experiment 是一个自定义 Java 类,如下所示:
class Experiment {
long id;
String name;
List<Tag> tags;
}
class Tag {
long id;
String name;
}
使用MULTISET 嵌套集合
比上面的还要好,you can hide using SQL/XML or SQL/JSON behind jOOQ 3.15's new MULTISET operator support。假设上述 Java 类是 Java 16 记录(或任何其他不可变类),您甚至可以将嵌套集合类型安全地映射到您的 DTO:
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));
Experiment 是一个自定义 Java 类,如下所示:
record Experiment(long id, String name, List<Tag> tags) {}
record Tag(long id, String name) {}
See also this blog post for more information.