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进行审计。我还有以下端点来检索实体列表:
现在,我想通过@QuerydslPredicate
注释使用new QueryDSL support that Spring offers。这适用于大多数字段或子实体,但它似乎不适用于子实体的集合。文档,博客文章等似乎不包括这种情况 - 我能找到的唯一信息是它支持简单集合的“in”(即字符串集合等)。
所以,我的实体设置如下:
Person.java
@Data
@Entity
@Audited
public class Person {
@Id
private long id;
private String name;
private List<Pet> pets = new ArrayList<>();
}
Pet.java
@Data
@Entity
@Audited
public class Pet {
@Id
private long id;
private int age;
}
我使用com.mysema.maven:apt-maven-plugin
生成我的Q类,它使用以下字段生成我的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);
如果我尝试查询,我会得到一个例外:
查询:
例外:
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]
现在这个查询看起来好像正在尝试解析propertyPath Person.pets.age
。它正确地将Person.pets
标识为ListPath
,然后尝试识别CompanyAddress.addressLine1
(这似乎是正确的)。问题是,它试图使用实体路径来获取类,即ListPath
而不是QPet
:
Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment());
Object value = ReflectionUtils.getField(field, entityPath);
以下查询按预期工作:
我的期望是,通过使用?pets.age=5
,将构建以下谓词:
QPerson.person.pets.any().age.eq(5)
目前Spring的QuerydslPredicate支持是否可行?或者我应该从查询参数手动构建谓词吗?
作为一个额外的问题,QuerydslPredicate有以下几种可能。假设我在pet上有firstName和lastName,我想只用name=Bob
运行查询:
我希望查询谓词的构建方式如下:
final BooleanBuilder petBuilder = new BooleanBuilder();
petBuilder.and(QPet.firstName.equals("Bob").or(QPet.lastName.equals("Bob")));
这可能吗?通过查看QuerydslBinderCustomizer
的自定义方法,它似乎不会,因为您需要绑定Q类的字段。我猜我不想支持。
如果这些不可能,那么我将坚持手动创建谓词,并将其传递给存储库。
答案 0 :(得分: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);
});
}
}
答案 1 :(得分:1)
我遇到了同样的错误。但是我注意到使用QuerydslAnnotationProcessor插件(而不是JPA注释处理器)允许我按预期查询实体的子集合。您只需使用@QueryEntity注释标记所有实体类。 (JPA注释处理器自动为@Entity注释类生成查询类。)
在你的pom中:
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/annotations</outputDirectory>
<processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>4.1.3</version>
</dependency>
</dependencies>
</plugin>
我相信我遇到了你遇到的异常,因为我从JPA Annotation Processor更改为QuerydslAnnotationProcessor,由于某些原因我不记得了,并且忽略了用@标记列表中的实体类。 QueryEntity注释。但是我也相信我有另一个Spring-Data-Rest \ JPA支持的API,它使用2017年8月构建的JPA Annotation Processor,我相信查询实体的子集合可以按预期工作。我将能够在今天晚些时候确认,并提供相关依赖项的版本(如果是这种情况)。也许这个问题已得到修复。