JOOQ嵌套对象映射时表名与POJO字段名不一致绑定失败问题
我遇到的问题和Stack Overflow上的「jooq query nested object」问题非常相似。我定义了如下POJO:
public class CourseComposite { private String courseName; private Teacher teacher; private List<Student> students; // getter、setter省略 }
我用JOOQ的DefaultRecordMapper把查询结果映射到这个POJO,查询语句如下:
ctx().select( COURSE.NAME.as("courseName"), TEACHERS, multiset(selectFrom(STUDENT).where(STUDENT.ID_COURSE.eq(COURSE.ID))).as("students") ) .from(COURSE).innerJoin(TEACHERS).on(COURSE.ID.eq(TEACHER.ID_COURSE)) .where(...) .fetchInto(CourseComposite.class);
但teacher字段一直是null,我猜原因是PostgreSQL里的表名叫teachers,但POJO里的字段名是teacher(这是我和那个Stack Overflow问题唯一的区别)。
我试着改了查询语句:
ctx().select(COURSE.NAME.as("courseName"), TEACHERS.as("teacher"), multiset(...))
结果直接抛异常:
missing FROM-clause entry for table "teacher"
请问有没有办法让JOOQ把TEACHERS的数据绑定到Teacher teacher对象上?
解决方法
你不能直接给表对象TEACHERS加as("teacher"),JOOQ会把这个别名当成新表引用,所以才报错。这里有几种可行的解决方式:
1. 用row()构造器包装整行并指定别名
把TEACHERS的所有字段包装成一个row对象,再给这个row对象起别名teacher,这样DefaultRecordMapper就能识别并映射到对应的POJO字段:
ctx().select( COURSE.NAME.as("courseName"), row(TEACHERS.fields()).as("teacher"), multiset(selectFrom(STUDENT).where(STUDENT.ID_COURSE.eq(COURSE.ID))).as("students") ) .from(COURSE).innerJoin(TEACHERS).on(COURSE.ID.eq(TEACHERS.ID_COURSE)) .where(...) .fetchInto(CourseComposite.class);
2. 给每个教师字段加前缀别名
如果你的JOOQ版本不支持row()构造器的这种用法,可以手动给TEACHERS的每个字段加上teacher.前缀,让映射器识别嵌套对象:
ctx().select( COURSE.NAME.as("courseName"), TEACHERS.ID.as("teacher.id"), TEACHERS.NAME.as("teacher.name"), // 其他教师字段都按这个格式添加别名 multiset(selectFrom(STUDENT).where(STUDENT.ID_COURSE.eq(COURSE.ID))).as("students") ) .from(COURSE).innerJoin(TEACHERS).on(COURSE.ID.eq(TEACHERS.ID_COURSE)) .where(...) .fetchInto(CourseComposite.class);
3. 全局配置字段映射策略
要是不想每次查询都手动处理别名,可以全局配置JOOQ的映射策略,让它自动处理表名复数到POJO字段名单数的转换。比如通过DefaultRecordMapperConfiguration自定义字段映射规则,或者在代码生成阶段就配置命名策略,把复数表名转换为单数的POJO字段名。
用上面任意一种方法,都能让teacher字段正确映射到数据。
内容的提问来源于stack exchange,提问作者SGiux

