【问题标题】:Map jooq record data to multiple pojos将 jooq 记录数据映射到多个 pojo
【发布时间】:2020-12-26 02:56:39
【问题描述】:

我们有多个表格,例如:

  • 学校一对多老师
  • 教授一对多科目
  • 一对多授课

实体如下

   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:作为回应,我们不需要所有表中的所有列(变量)。

【问题讨论】:

    标签: spring jooq modelmapper


    【解决方案1】:

    这对于学校作业来说是一个棘手的问题,因为从历史上看,这一直是 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 的原生 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 -&gt; TEACHERCLASS -&gt; TEACHER 之间存在一对一关系。

    另外,你可以看到我仍然使用TEACHER 加入SCHOOL 组,使用JSON_ARRAYAGG() 聚合教师。这是一种选择,对于 SUBJECTCLASS 查询的另一个相关子查询也是可能的。

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

    【讨论】:

    • 感谢您的回答。这对于 jooq 来说确实是一个很棒的附加功能。不幸的是,我们没有采用这种方法,而是通过三个单独的查询来获取所有需要的数据。显然,我的任务“截止日期”很紧,我的“教授”没有给我足够的时间来彻底调查这个问题。 :-) 顺便说一句,我出于好奇尝试了这种方法,它奏效了。
    • @GauravRatnawat:我以为我回答得太晚了(当时功能还没有准备好,我给自己设置了一个提醒,以便在功能准备好时回答)。但我认为这对这个问题的未来访问者非常有用。感谢您确认它有效!
    猜你喜欢
    • 2017-04-20
    • 1970-01-01
    • 2023-03-02
    • 2021-08-18
    • 1970-01-01
    • 2020-06-11
    • 2013-07-15
    • 1970-01-01
    • 2019-09-03
    相关资源
    最近更新 更多