带有嵌套列表的 jOOQ 查询

Dev*_*ips 5 java sql orm jooq

jOOQ 可以将查询结果映射到 POJO 中的多个嵌套列表吗?例如,我有一个 POJO VM,它代表一个虚拟机。它有一个“networks”属性,它是一个网络类型的列表。它还有一个“hdds”属性,它是一个“HDD”类型的列表。该查询连接了 VM、HDD 和 Networks 表。我可以“获取”到 VM.class 并期望 jOOQ“做正确的事”吗?

Luk*_*der 4

MULTISET在 jOOQ 3.15 中使用

从 jOOQ 3.15 开始,这里的首选方法是使用MULTISET. 假设你有:

record Vm(String name, List<Network> networks, List<Hdd> hdds) {}
Run Code Online (Sandbox Code Playgroud)

你可以写

List<Vm> result =
ctx.select(
      VM.NAME,
      multiset(
        select(
          // Using implicit joins can help here, though entirely optional
          NETWORK_TO_VM.network().ID, 
          NETWORK_TO_VM.network().NAME)
        .from(NETWORK_TO_VM)
        .where(NETWORK_TO_VM.VM_ID.eq(VM.VM_ID))
      ).convertFrom(r -> r.map(Records.mapping(Network::new))),
      multiset(
        select(
          HDD_TO_VM.hdd().ID,
          HDD_TO_VM.hdd().NAME)
        .from(HDD_TO_VM)
        .where(HDD_TO_VM.VM_ID.eq(VM.VM_ID))
      ).convertFrom(r -> r.map(Records.mapping(Hdd::new)))
   )
   .from(VM)
   .fetch(Records.mapping(Vm::new));
Run Code Online (Sandbox Code Playgroud)

请注意,上述方法结合了:

所有这些都是为了确保您可以直接从 SQL 查询中键入检查对象层次结构,从而一次性获取所有数据。

在 jOOQ 3.14 中使用 SQL/XML 或 SQL/JSON 嵌套集合

从 jOOQ 3.14 开始,这里的一个选项是使用 SQL/XML 或 SQL/JSON 直接在 SQL 中嵌套集合。例如:

class Vm {
  String name;
  List<Network> networks;
  List<Hdd> hdds;
}
Run Code Online (Sandbox Code Playgroud)

现在,你可以写:

List<Vm> result =
ctx.select(
      VM.NAME,
      field(
        select(jsonArrayAgg(jsonObject(
          key("id").value(NETWORK.ID),
          key("name").value(NETWORK.NAME),
          // ...
        )))
        .from(NETWORK)
        .join(NETWORK_TO_VM).on(NETWORK.NETWORK_ID.eq(NETWORK_TO_VM.NETWORK_ID))
        .where(NETWORK_TO_VM.VM_ID.eq(VM.VM_ID))
      ).as("networks"),
      field(
        select(jsonArrayAgg(jsonObject(
          key("id").value(HDD.ID),
          key("name").value(HDD.NAME),
          // ...
        )))
        .from(HDD)
        .join(HDD_TO_VM).on(HDD.HDD_ID.eq(HDD_TO_VM.HDD_ID))
        .where(HDD_TO_VM.VM_ID.eq(VM.VM_ID))
      ).as("hdds")
   )
   .from(VM)
   .fetchInto(Vm.class);
Run Code Online (Sandbox Code Playgroud)

请注意,将JSON_ARRAYAGG()空集聚合为NULL,而不是聚合为空[]如果有问题,请使用COALESCE()

历史答案(jOOQ 3.14 之前)

这种映射功能在像 jOOQ 这样的库中只能在有限范围内实现的主要原因是,通过连接表和反规范化结果,jOOQ 不再具有正确删除顶级元组所需的信息(在您的情况下VM) 。实现 JPA 的流行 ORM 不受此限制,因为它们不允许您表达任意连接。

但是您有一定的可能性将非规范化结果集映射到嵌套集合中: