Spring数据规范-带联接的RSQL

时间:2019-07-18 17:54:23

标签: java spring-boot join spring-data-jpa spring-data

我正在尝试使用规范和RSQL开发搜索API。遵循了本教程-https://www.baeldung.com/rest-api-search-language-rsql-fiql

我有一个User实体,该实体与UserProfile具有OneToOne关系。

@Entity
public class User{

    @Column(nullable = false)
    private String firstName;

    @OneToOne(targetEntity = UserProfile.class, fetch = FetchType.EAGER)
    @JoinColumn(nullable = false, name = "user_profile_id")
    private UserProfile userProfile;
...

@Entity
public class UserProfile{

    @Column(nullable = false)
    private String education;

    ...

和谓词功能

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
    List<Object> args = castArguments(root);
    Object argument = args.get(0);

    switch (RsqlSearchOperation.getSimpleOperator(operator)) {

    case EQUAL: {
            if (argument instanceof String) {               
                return builder.like(root.get(property), argument.toString().replace('*', '%'));
            } else if (argument == null) {
                return builder.isNull(root.get(property));
            } else {
                return builder.equal(root.get(property), argument);
            }
        }
        case NOT_EQUAL: {

....

当我使用参数?search = firstName == John调用API时,它会按预期返回结果。我需要的是按教育程度搜索,然后返回受过教育的用户。我按如下所示尝试了Join,但是它不起作用。

if (argument instanceof String) {
                Join<User, UserProfile> profileJoin = root.join("user_profile_id");

                return builder.like(root.get(property), profileJoin.get(property));
            } else if (argument == null) {

任何具有通用性的解决方案都会非常有帮助。

2 个答案:

答案 0 :(得分:0)

好像没有通用的具体解决方案。所以我做到了,这几乎是通用的。

switch (RsqlSearchOperation.getSimpleOperator(operator)) {

        case EQUAL: {
            if (doesClassContainProperty(UserProfile.class, property)) {
                Join<User, UserProfile> profileJoin = root.join("user_profile_id");
                return builder.equal(profileJoin.get(property), argument);
            } else {
                return builder.equal(root.get(property), argument);
            }
        }

这是检查传递的参数是在根类中还是在连接类中的方法

public boolean doesClassContainProperty(Class<?> genericClass, String fieldName) {
        return Arrays.stream(genericClass.getDeclaredFields()).anyMatch(f -> f.getName().equals(fieldName));
    }

答案 1 :(得分:0)

我想向您推荐另一个库,它可以让您构建动态过滤器而不必弄乱编码,它支持逻辑运算符、比较器、枚举、日期、布尔值、搜索关系/连接(没有 n+1 查询问题)、函数等等:https://github.com/turkraft/spring-filter

示例查询:

<块引用>

/search?filter= average(评分)> 4.5 brand.name ('奥迪'、'路虎')(年份> 2018公里< 50000)和颜色“白色”事故为空

用法:

@GetMapping(value = "/search")
public List<Entity> search(@EntityFilter Specification<Entity> spec, Pageable page) {
  return repo.findAll(spec, page);
}

不要忘记依赖:

<dependency>
    <groupId>com.turkraft</groupId>
    <artifactId>spring-filter</artifactId>
    <version>0.9.5</version>
</dependency>
相关问题