我们有多个表,例如:
- 学校一对多老师
- 教授一对多学科
- 教授一对多类(class)
实体如下
public class School {
private String name;
private long id;
private List<teacher> teachers;
public School() {
}
}
public class teachers {
private String name;
private Long id;
private List<Subject> subjects;
private List<Classes> classes;
}
public class Subject {
private String name;
private long id;
public Subject() {
}
}
public class Classes{
private String name;
private long id;
public Classes() {
}
}
我们已经为必填字段编写了 jooq 查询。对于单个学校数据,我们得到多行而不是预期的一行。但是,我们无法映射数据。
我们尝试过:
ModelMapper(无法找到将多个基本水平(表格)记录转换为垂直的方法)
intoGroups() 只工作到 单连接(bw 两个表)
simpleflatmapper 同样的问题
有什么办法可以实现吗?我们是否遗漏了什么?
PS:作为回应,我们不需要所有表中的所有列(变量)。
最佳答案
这对于学校作业来说是一个棘手的问题,因为从历史上看,这一直是 jOOQ 最缺失的功能之一:)
使用 MULTISET 的 jOOQ 3.15+ 解决方案
除了以下基于 SQL/XML 或 SQL/JSON 的解决方案外,jOOQ 3.15 现在还支持标准 SQL MULTISET
value constructor运算符以及合成 MULTISET_AGG
aggregate function ,可以这样使用:
List<School> schools =
ctx.select(
SCHOOL.NAME,
SCHOOL.ID,
multisetAgg(
TEACHER.NAME,
TEACHER.ID,
multiset(
select(SUBJECT.NAME, SUBJECT.ID)
.from(SUBJECT)
.where(SUBJECT.TEACHER_ID.eq(TEACHER.ID))
).as("subjects").convertFrom(r -> r.map(Records.mapping(Subject::new))),
multiset(
select(CLASS.NAME, CLASS.ID)
.from(CLASS)
.where(CLASS.TEACHER_ID.eq(TEACHER.ID))
).as("classes").convertFrom(r -> r.map(Records.mapping(Classes::new)))
).as("teachers").convertFrom(r -> r.map(Records.mapping(Teachers::new)))
)
.from(SCHOOL)
.join(TEACHER).on(TEACHER.SCHOOL_ID.eq(SCHOOL.ID))
.groupBy(SCHOOL.NAME, SCHOOL.ID)
.fetch(Records.mapping(School::new));
上述方法使用了各种 Records.mapping()
与 ad-hoc data type conversion 一起重载假定存在不可变的构造函数,例如如果您的类是 Java 16 记录,您会得到:
record Subject (String name, long id) {}
使用 SQL/XML 或 SQL/JSON 的 jOOQ 3.14+ 解决方案
从jOOQ 3.14 and the new SQL/XML and SQL/JSON support开始,这将相对容易实现。本质上,您将使用 RDBMS 的 native XML 或 JSON 支持直接在 SQL 中嵌套集合。 (如您所注意到的,所有其他使用连接并尝试删除重复数据并将扁平结果集插入嵌套数据结构的方法都无法很好地工作)
您可以这样编写查询(假设您使用代码生成器,并假设您对顶部带有 School
的树结构感兴趣):
List<School> schools =
ctx.select(jsonObject(
jsonEntry("name", SCHOOL.NAME),
jsonEntry("id", SCHOOL.ID),
jsonEntry("teachers", jsonArrayAgg(jsonObject(
jsonEntry("name", TEACHER.NAME),
jsonEntry("id", TEACHER.ID),
jsonEntry("subjects", field(
select(jsonArrayAgg(jsonObject(SUBJECT.NAME, SUBJECT.ID)))
.from(SUBJECT)
.where(SUBJECT.TEACHER_ID.eq(TEACHER.ID))
)),
jsonEntry("classes", field(
select(jsonArrayAgg(jsonObject(CLASS.NAME, CLASS.ID)))
.from(CLASS)
.where(CLASS.TEACHER_ID.eq(TEACHER.ID))
))
)))
))
.from(SCHOOL)
.join(TEACHER).on(TEACHER.SCHOOL_ID.eq(SCHOOL.ID))
.groupBy(SCHOOL.NAME, SCHOOL.ID)
.fetchInto(School.class);
此解决方案基于您的架构假设,即 SUBJECT -> TEACHER
之间存在一对一关系和 CLASS -> TEACHER
.
此外,您还可以看到我仍然使用联接来分组 TEACHER
每SCHOOL
, 聚集教师使用 JSON_ARRAYAGG()
.这是一个选项,关于 SUBJECT
的另一个相关子查询和 CLASS
查询也是可能的。
使用 SQL Server's FOR JSON
clause 可能有更简单的解决方案, 可以在其他方言中效仿。
关于spring - 将jooq记录数据映射到多个pojo,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63781763/