![](/img/trans.png)
[英]jOOQ fetchGroups does not return an empty collection for a one to many relationship
[英]jooq single query with one to many relationship
我有一个表格实验和一个表格标签。 一个实验可能有很多标签。 架构:
-------- --------
|Table1| 1 n |Table2|
| | <--------------> | |
| | | |
-------- --------
(experiment) (tags)
是否可以使用 jooq 创建一个查询来返回实验和相应的标签列表?
类似Result<Record>
东西,其中 Record 是一个List<TagRecord>
和一个标签列表,或者一个map<experimentRecord
, List<TagRecord>
。
我也有一个只返回一个结果的查询,有什么方便的吗?
编辑:java8,最新的jooq。
有很多方法可以使用 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())
));
这个问题不需要它,但其他人可能会发现这个问题,以寻找一种与 jOOQ 嵌套对多关系的方法。 我在这里提供了答案。 从 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
嵌套集合甚至比上面更好, 您可以使用 SQL/XML 或 SQL/JSON 隐藏在 jOOQ 3.15 的新MULTISET
运算符支持后面。 假设上述 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) {}
您现在可以使用SimpleFlatMapper将您的结果映射到Tuple2<ExperimentRecord, List<TagRecord>>
。 您需要做的就是。
1 - 创建一个映射器,指定键列,假设它是 id
JdbcMapper mapper =
JdbcMapperFactory
.newInstance()
.addKeys(EXPERIMENT.ID.getName())
.newMapper(new TypeReference<Tuple2<ExperimentRecord, List<TagRecord>>>() {});
2 - 在查询的 ResultSet 上使用映射器
try (ResultSet rs = DSL.using(configuration)
.select()
.from(EXPERIMENT)
.join(TAGS)
.on(...)
.fetchResultSet()) {
Stream<Tuple2<ExperimentRecord, List<TagRecord>>> stream = mapper.stream(rs);
....
}
请参阅此处了解更多详情
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.