spring - 将jooq记录数据映射到多个pojo

标签 spring jooq modelmapper

我们有多个表,例如:

  • 学校一对多老师
  • 教授一对多学科
  • 教授一对多类(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 .

此外,您还可以看到我仍然使用联接来分组 TEACHERSCHOOL , 聚集教师使用 JSON_ARRAYAGG() .这是一个选项,关于 SUBJECT 的另一个相关子查询和 CLASS查询也是可能的。

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

关于spring - 将jooq记录数据映射到多个pojo,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63781763/

相关文章:

java - 具有组合属性的模型映射器

modelmapper - 如何在 map 阶段跳过字段?

java - 如何注入(inject)SDK接口(interface)的新实现?

java - 如何使用 Jersey Client 针对 WS 上的 Spring Security 进行身份验证

java - 如何从 hibernate 中的实体类的结果中获取数据

java - jooq 配置调用 sp 时的输入参数

java - 如何在 junit 中为 Jooq Select Query 编写单元测试

java - JOOQ 的插入...与 PostgreSQL 10 和 JOOQ 3.10 一起返回?

java - 如何通过 ModelMapper 的 PropertyMap 使用继承

java - 用于生成和使用 JSON 的 Controller 的 Spring RequestMapping