Spring / Jhipster QueryService如何构建深度规范
Spring / Jhipster QueryService how to build a deep specification
我是使用 Jhispter 生成的 QueryService 的新手,我正在尝试使用它们来过滤实体列表。
当我过滤这个实体的字段时它工作正常,但现在我必须做一些更复杂的事情。
我有这个数据集:
- Child <----- 我上面说的实体
- Parent <----- 有一个列表 Child
- GrandParent <----- 有一个 Parent
的列表
我要做的是:
- 按 Parent.name
筛选 Childs
- 按 GrandParent.name
过滤 Childs
到目前为止我所做的是:
private Specification<Child> createSpecification(ChildCriteria criteria) {
Specification<Child> specification = Specification.where(null);
if (criteria != null) {
if (criteria.getParentName() != null) {
speficiation = specification.and(buildReferringEntitySpecification(criteria.getParentName(), Child_.parent, Parent_.name));
}
if (criteria.getGrandParentName() != null) {
specification.and(buildJoinSpecification(criteria.getGrandParentName(), Child_.parent, Parent_.grandParent, GrandParent_.name));
}
}
}
Child、Parent、GrandParent 和 Child 标准的摘录:
@Entity
@Table(name = "Child")
public class Child extends EntityObject {
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties("childs")
@QueryInit("GrandParent")
private Parent parent;
}
@Entity
@Table(name = "Parent")
public class Parent extends EntityObject {
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties("parents")
private GrandParent grandParent;
@OneToMany(mappedBy = "Parent", fetch = FetchType.LAZY)
private Set<Child> childs = new HashSet<>();
}
@Entity
@Table(name = "GrandParent")
public class GrandParent extends EntityObject {
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "GrandParent", fetch = FetchType.LAZY)
private Set<Parent> parrents = new HashSet<>();
}
public class ChildCriteria implements Serializable {
private StringFilter parentName;
private StringFilter grandParentName;
public StringFilter getParentName() {
return parentName;
}
public void setParentName(StringFilter parentName) {
this.parentName= parentName;
}
public StringFilter getGrandParentName() {
return grandParentName;
}
public void setGrandParentName(StringFilter grandParentName) {
this.grandParentName= grandParentName;
}
}
parent 名称的过滤器有效,我想对盛大的 parent 名称做同样的事情。
对于那个,我尝试了一些我在 SO 上找到的技巧,比如 ,但没有任何效果。
根据 link,这是我目前的情况:
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.getContains() != null) {
result = this.containsSpecification(reference, joinField, valueField, filter.getContains());
}
return result;
}
protected <REFERENCE, JOIN, FILTER> Specification<ENTITY> containsSpecification(SingularAttribute<? super ENTITY, REFERENCE> reference, SingularAttribute<REFERENCE, JOIN> joinField, SingularAttribute<JOIN, FILTER> idField, String value) {
return (root, query, builder) ->
builder.equal(root.join(reference).join(joinField).get(idField), value);
}
}
我在我的 ChildQueryService 中扩展了这个 class,我在其中使用了 buildJoinSpecification 方法。
如果我尝试使用它进行过滤,它 returns 是一个空列表。
好的,我在 Jhipster 文档中找到了一些东西。问题是我使用了 StringFilter,当我明白这一点时,我从 Jhipster 函数中修改了一些东西,如下所示:
扩展查询服务:
protected Specification<ENTITY> buildSpecification(StringFilter filter, Function<Root<ENTITY>, Expression<String>> metaclassFunction) {
if (filter.getEquals() != null) {
return equalsSpecification(metaclassFunction, filter.getEquals());
} else if (filter.getIn() != null) {
return valueIn(metaclassFunction, filter.getIn());
} else if (filter.getNotIn() != null) {
return valueNotIn(metaclassFunction, filter.getNotIn());
} else if (filter.getContains() != null) {
return likeUpperSpecification(metaclassFunction, filter.getContains());
} else if (filter.getDoesNotContain() != null) {
return doesNotContainSpecification(metaclassFunction, filter.getDoesNotContain());
} else if (filter.getNotEquals() != null) {
return notEqualsSpecification(metaclassFunction, filter.getNotEquals());
} else if (filter.getSpecified() != null) {
return byFieldSpecified(metaclassFunction, filter.getSpecified());
}
return null;
}
以便我可以在我的 ChildQueryService 中执行此操作:
if (criteria.getGrandParentName() != null) {
specification = specification.and(
buildSpecification(
criteria.getGrandParentName(),
root -> root.join(Child_.parent, JoinType.INNER).join(Parent_.grandParent, JoinType.INNER).get(GrandParent_.name)
)
);
}
现在可以正常使用了!看来你可以通过连接深入到你想要的深度,尽管我没有测试它超过 2 级深度。
郑重声明,这是我在 Jhipster 文档中找到的,以及我的函数基于的内容:
protected <OTHER, MISC, X> Specification<ENTITY> buildReferringEntitySpecification(
Filter<X> filter,
Function<Root<ENTITY>, SetJoin<MISC, OTHER>> functionToEntity,
Function<SetJoin<MISC, OTHER>, Expression<X>> entityToColumn
) {
if (filter.getEquals() != null) {
return equalsSpecification(functionToEntity.andThen(entityToColumn), filter.getEquals());
} else if (filter.getSpecified() != null) {
return byFieldSpecified(root -> functionToEntity.apply(root), filter.getSpecified());
}
return null;
}
例如这样使用的:
buildReferringEntitySpecification(
criteria.getGrandParentName(),
root -> root.get(Child_.parent).join(Parent_.grandParent),
GrandParent_.name
)
同时使用两者可以处理 StringFilter 和其他过滤器。不过,您可能必须为某些过滤器执行特定功能 class。
我是使用 Jhispter 生成的 QueryService 的新手,我正在尝试使用它们来过滤实体列表。
当我过滤这个实体的字段时它工作正常,但现在我必须做一些更复杂的事情。
我有这个数据集:
- Child <----- 我上面说的实体
- Parent <----- 有一个列表 Child
- GrandParent <----- 有一个 Parent 的列表
我要做的是:
- 按 Parent.name 筛选 Childs
- 按 GrandParent.name 过滤 Childs
到目前为止我所做的是:
private Specification<Child> createSpecification(ChildCriteria criteria) {
Specification<Child> specification = Specification.where(null);
if (criteria != null) {
if (criteria.getParentName() != null) {
speficiation = specification.and(buildReferringEntitySpecification(criteria.getParentName(), Child_.parent, Parent_.name));
}
if (criteria.getGrandParentName() != null) {
specification.and(buildJoinSpecification(criteria.getGrandParentName(), Child_.parent, Parent_.grandParent, GrandParent_.name));
}
}
}
Child、Parent、GrandParent 和 Child 标准的摘录:
@Entity
@Table(name = "Child")
public class Child extends EntityObject {
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties("childs")
@QueryInit("GrandParent")
private Parent parent;
}
@Entity
@Table(name = "Parent")
public class Parent extends EntityObject {
@Column(name = "name")
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties("parents")
private GrandParent grandParent;
@OneToMany(mappedBy = "Parent", fetch = FetchType.LAZY)
private Set<Child> childs = new HashSet<>();
}
@Entity
@Table(name = "GrandParent")
public class GrandParent extends EntityObject {
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "GrandParent", fetch = FetchType.LAZY)
private Set<Parent> parrents = new HashSet<>();
}
public class ChildCriteria implements Serializable {
private StringFilter parentName;
private StringFilter grandParentName;
public StringFilter getParentName() {
return parentName;
}
public void setParentName(StringFilter parentName) {
this.parentName= parentName;
}
public StringFilter getGrandParentName() {
return grandParentName;
}
public void setGrandParentName(StringFilter grandParentName) {
this.grandParentName= grandParentName;
}
}
parent 名称的过滤器有效,我想对盛大的 parent 名称做同样的事情。
对于那个,我尝试了一些我在 SO 上找到的技巧,比如
根据 link,这是我目前的情况:
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.getContains() != null) {
result = this.containsSpecification(reference, joinField, valueField, filter.getContains());
}
return result;
}
protected <REFERENCE, JOIN, FILTER> Specification<ENTITY> containsSpecification(SingularAttribute<? super ENTITY, REFERENCE> reference, SingularAttribute<REFERENCE, JOIN> joinField, SingularAttribute<JOIN, FILTER> idField, String value) {
return (root, query, builder) ->
builder.equal(root.join(reference).join(joinField).get(idField), value);
}
}
我在我的 ChildQueryService 中扩展了这个 class,我在其中使用了 buildJoinSpecification 方法。
如果我尝试使用它进行过滤,它 returns 是一个空列表。
好的,我在 Jhipster 文档中找到了一些东西。问题是我使用了 StringFilter,当我明白这一点时,我从 Jhipster 函数中修改了一些东西,如下所示:
扩展查询服务:
protected Specification<ENTITY> buildSpecification(StringFilter filter, Function<Root<ENTITY>, Expression<String>> metaclassFunction) {
if (filter.getEquals() != null) {
return equalsSpecification(metaclassFunction, filter.getEquals());
} else if (filter.getIn() != null) {
return valueIn(metaclassFunction, filter.getIn());
} else if (filter.getNotIn() != null) {
return valueNotIn(metaclassFunction, filter.getNotIn());
} else if (filter.getContains() != null) {
return likeUpperSpecification(metaclassFunction, filter.getContains());
} else if (filter.getDoesNotContain() != null) {
return doesNotContainSpecification(metaclassFunction, filter.getDoesNotContain());
} else if (filter.getNotEquals() != null) {
return notEqualsSpecification(metaclassFunction, filter.getNotEquals());
} else if (filter.getSpecified() != null) {
return byFieldSpecified(metaclassFunction, filter.getSpecified());
}
return null;
}
以便我可以在我的 ChildQueryService 中执行此操作:
if (criteria.getGrandParentName() != null) {
specification = specification.and(
buildSpecification(
criteria.getGrandParentName(),
root -> root.join(Child_.parent, JoinType.INNER).join(Parent_.grandParent, JoinType.INNER).get(GrandParent_.name)
)
);
}
现在可以正常使用了!看来你可以通过连接深入到你想要的深度,尽管我没有测试它超过 2 级深度。
郑重声明,这是我在 Jhipster 文档中找到的,以及我的函数基于的内容:
protected <OTHER, MISC, X> Specification<ENTITY> buildReferringEntitySpecification(
Filter<X> filter,
Function<Root<ENTITY>, SetJoin<MISC, OTHER>> functionToEntity,
Function<SetJoin<MISC, OTHER>, Expression<X>> entityToColumn
) {
if (filter.getEquals() != null) {
return equalsSpecification(functionToEntity.andThen(entityToColumn), filter.getEquals());
} else if (filter.getSpecified() != null) {
return byFieldSpecified(root -> functionToEntity.apply(root), filter.getSpecified());
}
return null;
}
例如这样使用的:
buildReferringEntitySpecification(
criteria.getGrandParentName(),
root -> root.get(Child_.parent).join(Parent_.grandParent),
GrandParent_.name
)
同时使用两者可以处理 StringFilter 和其他过滤器。不过,您可能必须为某些过滤器执行特定功能 class。