Spring @QuerydslPredicate 问题
Spring Boot 1.3.2.RELEASE
Spring Boot 1.3.2.RELEASE
查询DSL 3.7.2
QueryDSL 3.7.2
QueryDSL Maven 插件 1.1.3
QueryDSL Maven Plugin 1.1.3
休眠 4.3.11.Final
Hibernate 4.3.11.Final
目前,我有一个 Spring Boot 应用程序,它使用 Spring Data JPA(由 Hibernate 支持)具有一些基本的 CRUD 功能,并使用 Spring Data Envers 进行审计.我还有以下端点可以从中检索实体列表:
Currently, I have a Spring Boot application that has some basic CRUD functionality using Spring Data JPA (backed by Hibernate), and auditing using Spring Data Envers. I also have the following endpoint to retrieve a list of entities from:
http://localhost:8080/test-app/list
现在,我想使用 Spring 通过 @QuerydslPredicate
注释提供的新 QueryDSL 支持.这适用于大多数字段或子实体,但它似乎不适用于子实体的集合.文档、博客文章等似乎没有涵盖这种情况——我能找到的唯一信息是它支持简单集合的输入"(即字符串集合等).
Now, I wanted to use the new QueryDSL support that Spring offers through the @QuerydslPredicate
annotation. This works fine for most fields or sub-entities, but it doesn't appear to work for collections of sub-entities. The documentation, blog posts, etc. don't seem to cover this case - and the only information I could find is that it supports "in" for simple collections (i.e. collections of String, etc.).
所以,我的实体是这样设置的:
So, my entity is set up something like so:
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
并带有以下字段:
I generate my Q classes using the com.mysema.maven:apt-maven-plugin
, which generates my QPerson
with the following field:
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);
如果我尝试对此进行查询,则会收到异常:
If I try to query on this though, I get an exception:
查询:
http://localhost:8080/test-app/list?pets.年龄=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]
现在这个查询看起来像是在尝试解析 propertyPath Person.pets.age
.它正确地将 Person.pets
识别为 ListPath
,然后尝试识别 CompanyAddress.addressLine1
(这似乎是正确的).问题是,它尝试使用实体路径来获取类,即 ListPath
而不是 QPet
:
Now this query look like it's trying to resolve the propertyPath Person.pets.age
. It correctly identifies Person.pets
as a ListPath
, and then tries to identify CompanyAddress.addressLine1
(which seems correct). The problem is, it tries to use the entity path to get the class, which is the ListPath
instead of the QPet
:
Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment());
Object value = ReflectionUtils.getField(field, entityPath);
以下查询按预期工作:
http://localhost:8080/test-app/list?name=Bob
我的期望是通过使用 ?pets.age=5
,将构建以下谓词:
My expectation was that by using ?pets.age=5
, the following predicate would be built:
QPerson.person.pets.any().age.eq(5)
目前这可以通过 Spring 的 QuerydslPredicate 支持实现吗?还是应该从查询参数手动构建谓词?
Is this currently possible with Spring's QuerydslPredicate support? Or should I manually build the predicates from the query parameters?
作为一个附加问题,QuerydslPredicate 是否可能出现以下问题.假设我在 pet 上有名和姓,我想只用 name=Bob
运行查询:
As an additional question, is the following possible with QuerydslPredicate. Say I have a firstName and lastName on pet, and I want to run a query with just name=Bob
:
http://localhost:8080/test-app/pet/list?姓名=鲍勃
我希望这样构建查询谓词:
I would want the query predicate to be built like this:
final BooleanBuilder petBuilder = new BooleanBuilder();
petBuilder.and(QPet.firstName.equals("Bob").or(QPet.lastName.equals("Bob")));
这可能吗?从 QuerydslBinderCustomizer
的自定义方法来看,它似乎不是这样,因为您需要绑定 Q 类的一个字段.我猜我想做的事情不被支持.
Is that possible? From looking at the customize method of the QuerydslBinderCustomizer
it doesn't seem like it would be, since you need to bind off a field of the Q class. I'm guessing that what I want to do is not supported.
如果这些都不可能,那么我将坚持手动创建谓词,并将其传递到存储库.
If these aren't possible, then I'll stick with manually creating the predicate, and passing that on to the repository.
推荐答案
你可以使用QuerydslBinderCustomizer
来达到你的目的.下面是一些可以帮助您的示例代码:
You can use QuerydslBinderCustomizer
to achieve your purpose. Heres some sample code that can help you out:
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);
});
}
}
相关文章