嵌套类场景下如何用QueryDSL转换查询结果生成层级DTO?
解决方案
首先确认你已经生成了QueryDSL对应的Q实体类QStudent、QSubject、QGrade,按照以下步骤实现嵌套分组转换即可:
第一步:给DTO补充构造方法
QueryDSL的构造器映射需要DTO有匹配参数顺序的全参构造方法:
// 补充StudentTransient全参构造 public class StudentTransient { private Long studentId; private String name; private List<SubjectTansient> subjects; public StudentTransient(Long studentId, String name, List<SubjectTansient> subjects) { this.studentId = studentId; this.name = name; this.subjects = subjects; } // getter、setter按需补充 } // 补充SubjectTansient全参构造 public class SubjectTansient { private Long subjectId; private List<BigDecimal> grades; public SubjectTansient(Long subjectId, List<BigDecimal> grades) { this.subjectId = subjectId; this.grades = grades; } // getter、setter按需补充 }
第二步:编写QueryDSL查询逻辑
核心是使用嵌套GroupBy实现两层分组,先按学生分组,再按学生下的科目分组,最后收集对应成绩:
import static com.querydsl.core.group.GroupBy.*; import com.querydsl.jpa.impl.JPAQueryFactory; import 你的包路径.QStudent; import 你的包路径.QSubject; import 你的包路径.QGrade; // 初始化Q类 QStudent qStudent = QStudent.student; QSubject qSubject = QSubject.subject; QGrade qGrade = QGrade.grade; // 注入JPA的entityManager初始化查询工厂 JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager); List<StudentTransient> result = queryFactory .select(qStudent.id, qStudent.name, qSubject.id, qGrade.value) .from(qStudent) .leftJoin(qStudent.subjects, qSubject) .leftJoin(qSubject.grades, qGrade) // 第一层按学生ID分组,构造StudentTransient .transform( groupBy(qStudent.id).list( Projections.constructor( StudentTransient.class, qStudent.id, qStudent.name, // 第二层按科目ID分组,构造SubjectTansient groupBy(qSubject.id).list( Projections.constructor( SubjectTansient.class, qSubject.id, list(qGrade.value) // 收集当前科目下所有成绩的value字段 ) ) ) ) );
注意事项
- 如果你不想给DTO加构造方法,可以把
Projections.constructor替换为Projections.fields,直接按字段名映射,无需构造参数匹配:Projections.fields( StudentTransient.class, qStudent.id.as("studentId"), // 别名必须和DTO字段名完全一致 qStudent.name.as("name"), // 内层同样替换为fields即可 groupBy(qSubject.id).list( Projections.fields( SubjectTansient.class, qSubject.id.as("subjectId"), list(qGrade.value).as("grades") ) ) ) - 关联查询的join方式可以根据业务需求调整,比如不需要无科目/无成绩的学生可以把
leftJoin改成innerJoin。 - 你示例中的
SubjectTansient属于拼写错误(少了字母r,正确拼写应为SubjectTransient),如果需要修正请同步调整构造方法/字段映射的逻辑。
内容的提问来源于stack exchange,提问作者Diego Macario
相关产品推荐
相关产品推荐

