Spring/JHipster QueryService如何构建深层关联Specification查询
JHipster QueryService 多层关联过滤问题解决方案
问题根因&修复方案
1. 最直接的错误:Specification条件未生效
你在处理grandParentName过滤时,调用specification.and()后没有将生成的新Specification重新赋值给原变量,导致这部分过滤条件直接被丢弃,同时存在变量拼写错误、方法漏返回值的问题:
// 错误代码片段 if (criteria.getGrandParentName() != null) { // 此处仅生成条件,但没有赋值回原变量,条件直接丢失 specification.and(buildJoinSpecification(criteria.getGrandParentName(), Child_.parent, Parent_.grandParent, GrandParent_.name)); } // 变量拼写错误:speficiation → specification speficiation = specification.and(buildReferringEntitySpecification(criteria.getParentName(), Child_.parent, Parent_.name));
修正后代码:
private Specification<Child> createSpecification(ChildCriteria criteria) { Specification<Child> specification = Specification.where(null); if (criteria != null) { if (criteria.getParentName() != null) { // 修正拼写错误 specification = specification.and(buildReferringEntitySpecification(criteria.getParentName(), Child_.parent, Parent_.name)); } if (criteria.getGrandParentName() != null) { // 新增赋值逻辑,把生成的过滤条件合并到原specification specification = specification.and(buildJoinSpecification(criteria.getGrandParentName(), Child_.parent, Parent_.grandParent, GrandParent_.name)); } } // 补全返回值 return specification; }
2. buildJoinSpecification适配性不足
你当前自定义的buildJoinSpecification仅支持contains类型的过滤,没有覆盖equals/startsWith/endsWith等StringFilter的常用操作,会导致部分过滤请求不生效,同时指定左连接可以避免关联为空时的数据被意外过滤:
修正后的ExtendedQueryService代码:
import javax.persistence.criteria.JoinType; public class ExtendedQueryService<ENTITY> extends QueryService<ENTITY>{ protected <REFERENCE, JOIN, FILTER extends Comparable<? super FILTER>> Specification<ENTITY> buildJoinSpecification(StringFilter filter, SingularAttribute<? super ENTITY, REFERENCE> reference, SingularAttribute<REFERENCE, JOIN> joinField, SingularAttribute<JOIN, FILTER> valueField) { Specification<ENTITY> result = Specification.where((Specification) null); if (filter == null) { return result; } // 覆盖全量StringFilter操作逻辑 if (filter.getEquals() != null) { result = result.and((root, query, builder) -> builder.equal(root.join(reference, JoinType.LEFT).join(joinField, JoinType.LEFT).get(valueField), filter.getEquals()) ); } if (filter.getContains() != null) { result = result.and((root, query, builder) -> builder.like( builder.lower(root.join(reference, JoinType.LEFT).join(joinField, JoinType.LEFT).get(valueField)), "%" + filter.getContains().toLowerCase() + "%" ) ); } if (filter.getStartsWith() != null) { result = result.and((root, query, builder) -> builder.like( builder.lower(root.join(reference, JoinType.LEFT).join(joinField, JoinType.LEFT).get(valueField)), filter.getStartsWith().toLowerCase() + "%" ) ); } if (filter.getEndsWith() != null) { result = result.and((root, query, builder) -> builder.like( builder.lower(root.join(reference, JoinType.LEFT).join(joinField, JoinType.LEFT).get(valueField)), "%" + filter.getEndsWith().toLowerCase() ) ); } return result; } }
3. 实体类注解错误修正
你的实体类中存在属性名大小写不匹配的问题,会导致关联查询失败:
- Child类的
@QueryInit("GrandParent")修改为@QueryInit("grandParent"),对应Parent类的属性名是小写开头 - Parent类的
@OneToMany(mappedBy = "Parent")修改为@OneToMany(mappedBy = "parent"),对应Child类的parent属性名 - GrandParent类的
@OneToMany(mappedBy = "GrandParent")修改为@OneToMany(mappedBy = "grandParent"),对应Parent类的grandParent属性名
完成以上三处修改后,多层关联过滤逻辑即可正常运行。
内容的提问来源于stack exchange,提问作者derOtterDieb
相关产品推荐
相关产品推荐

