数据访问

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.idtable.tenantKeytable.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(...)

仍有疑问?按反馈清单整理复现信息 →