使用 jOOQ 加载 PostgreSQL 树
Load PostgreSQL tree with jOOQ
我在 PostgreSQL 中有以下结构:
TableA has many TableB has many TableC
这三张表(简体)如下:
create table TableA (
idA int,
nameA varchar(100));
create table TableB (
idA int,
idB int,
nameB varchar(100));
create table TableC (
idA int,
idB int,
idC int,
nameC varchar(100));
我需要 运行 在 PostgreSQL 上使用 jOOQ select of TableA
,但它还应该从 TableB
和 TableC
加载任何相关行.有没有办法 运行 单个 jOOQ 语句来加载这棵树?我知道我可以用 join
s 做到这一点,但我试图避免 Java.
中的任何循环
jOOQ 3.15 解决方案使用 MULTISET
从 jOOQ 3.15 开始,您可以使用 standard SQL MULTISET
operator, which is emulated using SQL/XML or SQL/JSON
嵌套集合
var result =
ctx.select(
TABLE_A.ID_A, TABLE_A.NAME_A,
multiset(
select(
TABLE_B.ID_B, TABLE_B.NAME_B,
multiset(
select(TABLE_C.ID_C, TABLE_C.NAME_C)
.from(TABLE_C)
.where(TABLE_C.ID_B.eq(TABLE_B.ID_B))
.and(TABLE_C.ID_A.eq(TABLE_B.ID_A))
).as("c")
)
.from(TABLE_B)
.where(TABLE_B.ID_A.eq(TABLE_A.ID_A))
).as("b")
)
.from(TABLE_A)
.fetch();
result
的类型推断为:
Result<Record3<
Integer, // TABLE_A.ID_A
String, // TABLE_A.NAME_A
Result<Record3<
Integer, // TABLE_B.ID_B
String, // TABLE_B.NAME_B
Result<Record2<
Integer, // TABLE_C.ID_C
String // TABLE_C.NAME_C
>>
>>
>> result = ...
如果您希望将其映射到某些自定义 DTO 数据结构中,例如
record TableC(int idC, String nameC) {}
record TableB(int idB, String nameB, List<TableC> c) {}
record TableA(int idA, String nameA, List<TableB> b) {}
您可以使用 jOOQ 3.15's new ad-hoc conversion feature 轻松完成此操作:
List<TableA> result =
ctx.select(
TABLE_A.ID_A, TABLE_A.NAME_A,
multiset(
select(
TABLE_B.ID_B, TABLE_B.NAME_B,
multiset(
select(TABLE_C.ID_C, TABLE_C.NAME_C)
.from(TABLE_C)
.where(TABLE_C.ID_B.eq(TABLE_B.ID_B))
.and(TABLE_C.ID_A.eq(TABLE_B.ID_A))
).as("c").convertFrom(r -> r.map(Records.mapping(TableC::new)))
)
.from(TABLE_B)
.where(TABLE_B.ID_A.eq(TABLE_A.ID_A))
).as("b").convertFrom(r -> r.map(Records.mapping(TableB::new)))
)
.from(TABLE_A)
.fetch(Records.mapping(TableA::new));
所有映射都是类型安全的、编译时检查的和无反射的
jOOQ 3.14 解决方案使用 SQL/XML 或 SQL/JSON
您可以使用 jOOQ 3.14 的 SQL/XML 或 SQL/JSON 支持,see this blog post here
如果您在 class 路径上有 Gson 或 Jackson,它们可用于将 XML 或 JSON 结构映射回您的 Java class 层次结构。 manual's page about ConverterProvider
中给出了一个例子
本质上:
ctx.select(
jsonObject(
key("idA").value(TABLE_A.ID_A),
key("nameA").value(TABLE_A.NAME_A),
key("b").value(
select(jsonArrayAgg(jsonObject(
key("idB").value(TABLE_B.ID_B),
key("nameB").value(TABLE_B.NAME_B),
key("c").value(
select(jsonArrayAgg(jsonObject(
key("idC").value(TABLE_C.ID_C),
key("nameC").value(TABLE_C.NAME_C)
)))
.from(TABLE_C)
.where(TABLE_C.ID_B.eq(TABLE_B.ID_B))
)
)))
.from(TABLE_B)
.where(TABLE_B.ID_A.eq(TABLE_A.ID_A))
)
)
)
.from(TABLE_A)
.fetch();
另请参阅此处的相关问题:
- jOOQ - nested object with many to many relationship
- JOOQ pojos with one-to-many and many-to-many relations
请注意,JSON_ARRAYAGG()
将空集聚合到 NULL
,而不是空集 []
。
我在 PostgreSQL 中有以下结构:
TableA has many TableB has many TableC
这三张表(简体)如下:
create table TableA (
idA int,
nameA varchar(100));
create table TableB (
idA int,
idB int,
nameB varchar(100));
create table TableC (
idA int,
idB int,
idC int,
nameC varchar(100));
我需要 运行 在 PostgreSQL 上使用 jOOQ select of TableA
,但它还应该从 TableB
和 TableC
加载任何相关行.有没有办法 运行 单个 jOOQ 语句来加载这棵树?我知道我可以用 join
s 做到这一点,但我试图避免 Java.
jOOQ 3.15 解决方案使用 MULTISET
从 jOOQ 3.15 开始,您可以使用 standard SQL MULTISET
operator, which is emulated using SQL/XML or SQL/JSON
var result =
ctx.select(
TABLE_A.ID_A, TABLE_A.NAME_A,
multiset(
select(
TABLE_B.ID_B, TABLE_B.NAME_B,
multiset(
select(TABLE_C.ID_C, TABLE_C.NAME_C)
.from(TABLE_C)
.where(TABLE_C.ID_B.eq(TABLE_B.ID_B))
.and(TABLE_C.ID_A.eq(TABLE_B.ID_A))
).as("c")
)
.from(TABLE_B)
.where(TABLE_B.ID_A.eq(TABLE_A.ID_A))
).as("b")
)
.from(TABLE_A)
.fetch();
result
的类型推断为:
Result<Record3<
Integer, // TABLE_A.ID_A
String, // TABLE_A.NAME_A
Result<Record3<
Integer, // TABLE_B.ID_B
String, // TABLE_B.NAME_B
Result<Record2<
Integer, // TABLE_C.ID_C
String // TABLE_C.NAME_C
>>
>>
>> result = ...
如果您希望将其映射到某些自定义 DTO 数据结构中,例如
record TableC(int idC, String nameC) {}
record TableB(int idB, String nameB, List<TableC> c) {}
record TableA(int idA, String nameA, List<TableB> b) {}
您可以使用 jOOQ 3.15's new ad-hoc conversion feature 轻松完成此操作:
List<TableA> result =
ctx.select(
TABLE_A.ID_A, TABLE_A.NAME_A,
multiset(
select(
TABLE_B.ID_B, TABLE_B.NAME_B,
multiset(
select(TABLE_C.ID_C, TABLE_C.NAME_C)
.from(TABLE_C)
.where(TABLE_C.ID_B.eq(TABLE_B.ID_B))
.and(TABLE_C.ID_A.eq(TABLE_B.ID_A))
).as("c").convertFrom(r -> r.map(Records.mapping(TableC::new)))
)
.from(TABLE_B)
.where(TABLE_B.ID_A.eq(TABLE_A.ID_A))
).as("b").convertFrom(r -> r.map(Records.mapping(TableB::new)))
)
.from(TABLE_A)
.fetch(Records.mapping(TableA::new));
所有映射都是类型安全的、编译时检查的和无反射的
jOOQ 3.14 解决方案使用 SQL/XML 或 SQL/JSON
您可以使用 jOOQ 3.14 的 SQL/XML 或 SQL/JSON 支持,see this blog post here
如果您在 class 路径上有 Gson 或 Jackson,它们可用于将 XML 或 JSON 结构映射回您的 Java class 层次结构。 manual's page about ConverterProvider
本质上:
ctx.select(
jsonObject(
key("idA").value(TABLE_A.ID_A),
key("nameA").value(TABLE_A.NAME_A),
key("b").value(
select(jsonArrayAgg(jsonObject(
key("idB").value(TABLE_B.ID_B),
key("nameB").value(TABLE_B.NAME_B),
key("c").value(
select(jsonArrayAgg(jsonObject(
key("idC").value(TABLE_C.ID_C),
key("nameC").value(TABLE_C.NAME_C)
)))
.from(TABLE_C)
.where(TABLE_C.ID_B.eq(TABLE_B.ID_B))
)
)))
.from(TABLE_B)
.where(TABLE_B.ID_A.eq(TABLE_A.ID_A))
)
)
)
.from(TABLE_A)
.fetch();
另请参阅此处的相关问题:
- jOOQ - nested object with many to many relationship
- JOOQ pojos with one-to-many and many-to-many relations
请注意,JSON_ARRAYAGG()
将空集聚合到 NULL
,而不是空集 []
。