java Spring / Jhipster QueryService如何构建深度规范

disho6za  于 2023-02-18  发布在  Java
关注(0)|答案(2)|浏览(185)

我对使用Jhispter生成的QueryService不熟悉,我正在尝试使用它们来过滤实体列表。
当我过滤这个实体的字段时,它工作得很好,但是现在我必须做一些更复杂的事情。
我有这个数据集:

  • 儿童〈-----我上面所说的实体
  • 父级〈-----其中包含子级列表
  • 祖父母〈-----它有一个

我要做的是:

  • 通过www.example.com过滤查尔兹Parent.name
  • 通过www.example.com过滤查尔兹GrandParent.name

所以到目前为止我所做的是:

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));
        }
    }
}

子项、父项、祖父母和子项标准的摘录:

@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;
    }
}

父名字的过滤器是有效的,我也想对祖父名字做同样的过滤。对于这个,我尝试了一些我在this上找到的技巧,但是没有任何效果。
通过这个链接,我目前得到的信息如下:

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中扩展了这个类,其中我使用了buildJoinSpecification方法。
如果我尝试用它过滤,它会返回一个空列表。

q8l4jmvw

q8l4jmvw1#

好的,我在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 doc中找到的,也是我的函数所基于的:

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和其他Filter。不过,您可能需要为某些Filter类执行特定的函数。

zphenhs4

zphenhs42#

tech.jhipster.service.QueryService可能很快变得复杂。我在6个月后查看我的代码,我不再明白我做了什么,不得不重新思考东西,只是因为我想添加一点东西。因此:如果可以避免,就不要使用它。
对于复杂的过滤,我建议在数据库中创建一个视图,将我想要过滤的内容Map到一个String或Boolean,在Spring中创建一个实体(注意ID是非空的,并与原始实体匹配,因此只需通过视图添加字段,不要过滤掉内容或意外复制实体),然后过滤它。
SQL比使用位于hibernates Criteria API之上的API要简单得多,后者本身也比SQL复杂一些。
在我的例子中,我想一次根据多个属性进行过滤-在QueryService中没有简单的方法来实现这一点,但是case... when...输出一个枚举,然后可以通过QuerySerivice进行过滤是足够简单的(我将在一年内理解我所做的)。

相关问题