Spring @QuerydslPredicate问题

Ken*_*nco 7 java spring querydsl spring-data

使用的图书馆

Spring Boot 1.3.2.RELEASE

QueryDSL 3.7.2

QueryDSL Maven插件1.1.3

Hibernate 4.3.11.Final

问题

目前,我有一个Spring Boot应用程序,它使用Spring Data JPA(由Hibernate支持)具有一些基本的CRUD功能,并使用Spring Data Envers进行审计.我还有以下端点来检索实体列表:

HTTP://本地主机:8080 /测试应用程序/名单

现在,我想使用Spring通过@QuerydslPredicate注释提供新QueryDSL支持.这适用于大多数字段或子实体,但它似乎不适用于子实体的集合.文档,博客文章等似乎不包括这种情况 - 我能找到的唯一信息是它支持简单集合的"in"(即字符串的集合等).

所以,我的实体设置如下:

Person.java

@Data
@Entity
@Audited
public class Person {

    @Id
    private long id;

    private String name;

    private List<Pet> pets = new ArrayList<>();

}
Run Code Online (Sandbox Code Playgroud)

Pet.java

@Data
@Entity
@Audited
public class Pet {

    @Id
    private long id;

    private int age;

}
Run Code Online (Sandbox Code Playgroud)

我使用the生成我的Q类com.mysema.maven:apt-maven-plugin,它QPerson使用以下字段生成我:

public final ListPath<com.test.Pet, com.test.QPet> pets = this.<com.test.Pet, com.test.QPet>createList("pets", com.test.Pet.class, com.test.QPet.class, PathInits.DIRECT2);
Run Code Online (Sandbox Code Playgroud)

如果我尝试查询这个,我得到一个例外:

查询:

HTTP://本地主机:8080 /测试应用程式内/列表pets.age = 5

例外:

10:21:37,523 ERROR [org.springframework.boot.context.web.ErrorPageFilter] (http-/127.0.0.1:8080-1) Forwarding to error page from request [/list] due to exception [null]: java.lang.NullPointerException
    at org.springframework.util.ReflectionUtils.getField(ReflectionUtils.java:143) [spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.reifyPath(QuerydslPredicateBuilder.java:185) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.reifyPath(QuerydslPredicateBuilder.java:188) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.getPath(QuerydslPredicateBuilder.java:167) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.invokeBinding(QuerydslPredicateBuilder.java:136) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.getPredicate(QuerydslPredicateBuilder.java:111) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.data.web.querydsl.QuerydslPredicateArgumentResolver.resolveArgument(QuerydslPredicateArgumentResolver.java:106) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.data.web.querydsl.QuerydslPredicateArgumentResolver.resolveArgument(QuerydslPredicateArgumentResolver.java:48) [spring-data-commons-1.11.2.RELEASE.jar:]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
Run Code Online (Sandbox Code Playgroud)

现在这个查询看起来像是在尝试解析propertyPath Person.pets.age.它正确识别Person.pets为a ListPath,然后尝试识别CompanyAddress.addressLine1(这似乎是正确的).问题是,它试图使用实体路径来获取类,而ListPath不是QPet:

Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment());
Object value = ReflectionUtils.getField(field, entityPath);
Run Code Online (Sandbox Code Playgroud)

以下查询按预期工作:

HTTP://本地主机:8080 /测试应用程序/列表名称=鲍勃

我的期望是通过使用?pets.age=5,将构建以下谓词:

QPerson.person.pets.any().age.eq(5)
Run Code Online (Sandbox Code Playgroud)

Spring的QuerydslPredicate支持目前是否可以实现?或者我应该从查询参数手动构建谓词?

附加问题

作为一个额外的问题,QuerydslPredicate有以下几种可能.假设我在pet上有firstName和lastName,我想用以下命令运行查询name=Bob:

HTTP://本地主机:8080 /测试应用程式内/ PET /列表名称=鲍勃

我希望查询谓词像这样构建:

final BooleanBuilder petBuilder = new BooleanBuilder();
petBuilder.and(QPet.firstName.equals("Bob").or(QPet.lastName.equals("Bob")));
Run Code Online (Sandbox Code Playgroud)

那可能吗?从查看自定义方法QuerydslBinderCustomizer看起来不像它,因为你需要绑定Q类的字段.我猜我不想支持我想做的事情.

如果这些不可能,那么我将坚持手动创建谓词,并将其传递给存储库.

Fai*_*roz 2

您可以使用它QuerydslBinderCustomizer来实现您的目的。下面是一些可以帮助您的示例代码:

public interface PersonRepository extends JpaRepository<Job, Integer>,
        QueryDslPredicateExecutor<Person>, QuerydslBinderCustomizer<QJob> {

    @Override
    public default void customize(final QuerydslBindings bindings, final QPerson person)     {
        bindings.bind(person.pets.any().name).first((path, value) -> {
            return path.eq(value);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)