JPA QueryDSL 代码编写指南
遵守 JPA 与 QueryDSL 实体、仓储及条件表达式约定。
浏览全部手册
本页目录
文档来源与 Markdown 原文
权威正文:ineed-core/docs/project-development/jpa-querydsl-code-guide.md。网站按工作区快照同步,原文中的历史日期和验证范围保留。
开始编码前核对同版本源码;跨仓文件引用可在源码定位目录查找。
下载 Markdown 原文 ↓本文约定业务模块中 *-jpa 子模块的标准 QueryDSL 写法。目标是让 JPA 自定义查询继续使用 QueryDSL 生成的 Q* 元数据,同时把实体字段投影、关联字段扩展和查询条件边界收口到稳定位置,避免业务 Manager 中散落重复字段清单。
核心原则
- JPA 自定义查询优先使用 Spring Data 派生查询或 QueryDSL,不写 native SQL。
buildVOQBean()中实体自身字段必须通过QuerydslUtil.projectionFields(entityClass, entityPath)或QuerydslUtil.projectionBean(entityClass, entityPath)提取。- 只有 join 出来的扩展字段才在业务
Manager中显式追加,例如group.groupKey.as("groupKey")。 - 不要在
buildVOQBean()中手写完整的table.id、table.tenantKey、table.createdTimestamp、业务字段等长列表;这类列表应该由 core 按实体字段统一提取。 IBaseSearch#buildVOQBean()默认仍返回null,不强制所有 JPA 查询走 QBean 投影;只有需要 join 填充额外 VO 字段时才覆盖。
实体字段投影
当查询只需要实体自身字段时,优先直接使用 core 工具:
@Override
public QBean<SampleEntity> buildVOQBean() {
return QuerydslUtil.projectionBean(SampleEntity.class, QSampleEntity.sampleEntity);
}
当查询还需要 join 字段时,实体字段仍由 core 提取,业务代码只追加额外字段:
@Override
public QBean<Parameter> buildVOQBean() {
final QParameter table = QParameter.parameter;
final QParameterGroup group = QParameterGroup.parameterGroup;
final List<Expression<?>> fields = new ArrayList<>(List.of(QuerydslUtil.projectionFields(Parameter.class, table)));
fields.add(group.applicationKey.as("applicationKey"));
fields.add(group.groupKey.as("groupKey"));
fields.add(group.groupName.as("groupName"));
//@formatter:off
return Projections.fields(
Parameter.class,
fields.toArray(new Expression[0]));
//@formatter:on
}
这种写法有两个好处:
- 实体新增、删除字段时,投影字段自动跟随实体持久化字段变化。
- join 字段一眼可见,代码审查时能快速识别哪些字段来自关联表。
Join 查询
buildQuery(...) 只负责表达关联关系,不再顺带维护实体字段投影清单:
@Override
public <T> JPAQuery<T> buildQuery(final JPAQuery<T> query) {
final QParameter table = QParameter.parameter;
final QParameterGroup group = QParameterGroup.parameterGroup;
return query.leftJoin(group).on(group.id.eq(table.groupId));
}
如果 join 字段要映射到 VO / 查询返回对象,必须在 buildVOQBean() 中使用 as("propertyName") 明确别名,别名应对应目标对象属性名。
禁止写法
不要在 buildVOQBean() 中维护实体字段全量列表:
return Projections.fields(
Parameter.class,
table.id,
table.tenantKey,
table.orderWeight,
table.dataStatus,
table.createdTimestamp,
table.groupId,
table.parameterKey,
table.parameterName,
table.parameterDescription,
group.groupKey.as("groupKey"));
这个写法的问题是实体字段来源和 join 字段混在一起。实体字段变化时容易漏改,多个 Manager 也会产生重复字段列表。
验证
改造或新增 JPA QueryDSL 自定义查询后,至少执行对应模块编译:
mvn -pl <module>/<module>-jpa -am install -DskipTests
同时建议扫描业务 JPA Manager 是否仍残留全量实体字段手写投影:
rg -n "buildVOQBean|Projections\\.fields|table\\.id|table\\.tenantKey|table\\.createdTimestamp" <module> -g '*Manager.java'
允许保留少量业务 join 字段追加,但实体自身字段应优先来自 QuerydslUtil.projectionFields(...)。
仍有疑问?按反馈清单整理复现信息 →