将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 查询。对于单个学校数据,我们得到多行而不是预期的一行。但是,我们无法映射数据。

我们试过了:

有什么办法可以实现吗。我们是不是漏掉了什么?

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 -> TEACHERCLASS -> TEACHER 之间存在 to-one 关系。

此外,您可以看到我仍然使用联接来分组 TEACHER 每个 SCHOOL,使用 JSON_ARRAYAGG() 聚合教师。这是一个选项,另一个与 SUBJECTCLASS 查询相关的子查询也是可能的。

使用 SQL Server's FOR JSON clause 可能有更简单的解决方案,可以在其他方言中效仿。