将jooq记录数据映射到多个pojo
Map jooq record data to multiple pojos
我们有多个 table 像 :
- 学校一对多老师
- 教师一对多科目
- 老师一对多类
实体如下
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(无法找到将多个基本水平(table)记录转换为垂直的方法)
intoGroups() 只工作到
单连接(bw 两个 tables)
simpleflatmapper 同样的问题
有什么办法可以实现吗。我们是不是漏掉了什么?
PS:作为回应,我们不需要所有 table 中的所有列(变量)。
这对于学校作业来说是一个棘手的问题,因为从历史上看,这一直是 jOOQ 最缺失的功能之一:)
使用 MULTISET 的 jOOQ 3.15+ 解决方案
除了以下基于SQL/XML或SQL/JSON的解决方案,jOOQ 3.15现在支持标准SQL MULTISET
value constructor operator as well as a synthetic 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()
overloads along with 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 的本机 XML 或 JSON 支持直接在 SQL 中嵌套集合。 (所有其他使用连接并尝试删除重复数据和 shoe-horn 将平面结果集放入嵌套数据结构的方法都无法正常工作,正如您所注意到的)
您可以像这样编写查询(假设您使用代码生成器,并假设您对顶部带有 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
之间存在 to-one 关系。
此外,您可以看到我仍然使用联接来分组 TEACHER
每个 SCHOOL
,使用 JSON_ARRAYAGG()
聚合教师。这是一个选项,另一个与 SUBJECT
和 CLASS
查询相关的子查询也是可能的。
使用 SQL Server's FOR JSON
clause 可能有更简单的解决方案,可以在其他方言中效仿。
我们有多个 table 像 :
- 学校一对多老师
- 教师一对多科目
- 老师一对多类
实体如下
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(无法找到将多个基本水平(table)记录转换为垂直的方法)
intoGroups() 只工作到 单连接(bw 两个 tables)
simpleflatmapper 同样的问题
有什么办法可以实现吗。我们是不是漏掉了什么?
PS:作为回应,我们不需要所有 table 中的所有列(变量)。
这对于学校作业来说是一个棘手的问题,因为从历史上看,这一直是 jOOQ 最缺失的功能之一:)
使用 MULTISET 的 jOOQ 3.15+ 解决方案
除了以下基于SQL/XML或SQL/JSON的解决方案,jOOQ 3.15现在支持标准SQL MULTISET
value constructor operator as well as a synthetic 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()
overloads along with 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 的本机 XML 或 JSON 支持直接在 SQL 中嵌套集合。 (所有其他使用连接并尝试删除重复数据和 shoe-horn 将平面结果集放入嵌套数据结构的方法都无法正常工作,正如您所注意到的)
您可以像这样编写查询(假设您使用代码生成器,并假设您对顶部带有 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
之间存在 to-one 关系。
此外,您可以看到我仍然使用联接来分组 TEACHER
每个 SCHOOL
,使用 JSON_ARRAYAGG()
聚合教师。这是一个选项,另一个与 SUBJECT
和 CLASS
查询相关的子查询也是可能的。
使用 SQL Server's FOR JSON
clause 可能有更简单的解决方案,可以在其他方言中效仿。