繁体   English   中英

具有一对多关系的 jooq 单个查询

[英]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())
           ));

使用 SQL/XML 或 SQL/JSON 嵌套集合

这个问题不需要它,但其他人可能会发现这个问题,以寻找一种与 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM