복붙노트

[SPRING] Spring @QuerydslPredicate Questions

SPRING

Spring @QuerydslPredicate Questions

봄 부팅 1.3.2. 릴리스

QueryDSL 3.7.2

QueryDSL 메이븐 플러그인 1.1.3

최대 절전 모드 4.3.11. 최종

현재 Spring Data JPA (Hibernate 지원)를 사용하는 기본 CRUD 기능과 Spring Data Envers를 사용하여 감사하는 Spring Boot 응용 프로그램이 있습니다. 엔티티 목록을 검색하는 다음 엔드 포인트가 있습니다.

이제 Spring이 @QuerydslPredicate 주석을 통해 제공하는 새로운 QueryDSL 지원을 사용하고자했습니다. 대부분의 필드 나 하위 엔티티에서는 정상적으로 작동하지만 하위 엔티티의 수집에는 작동하지 않습니다. 문서, 블로그 게시물 등은이 사례를 다루지 않는 것 같아요. 내가 찾을 수있는 유일한 정보는 간단한 컬렉션 (즉, String 컬렉션 등)에 대해 "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;

}

다음 필드로 내 QPerson을 생성하는 com.mysema.maven : apt-maven-plugin을 사용하여 Q 클래스를 생성합니다.

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 (올바른 것으로 보임)을 식별하려고 시도합니다. 문제는 엔티티 경로를 사용하여 QPet 대신 ListPath 인 클래스를 가져 오는 것입니다.

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의 customize 메소드를 살펴보면 Q 클래스의 필드를 바인드해야하기 때문에 그렇게되지는 않습니다. 나는 내가하고 싶은 일이 지원되지 않는다고 생각합니다.

이것이 가능하지 않다면, 필자는 수동으로 술어를 생성하고 그것을 저장소로 전달할 것입니다.

해결법

  1. ==============================

    1.당신은 목적을 달성하기 위해 QuerydslBinderCustomizer를 사용할 수 있습니다. 당신을 도울 수있는 몇 가지 샘플 코드가 있습니다.

    당신은 목적을 달성하기 위해 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);
            });
        }
    }
    
  2. ==============================

    2.나는 같은 오류를 만났다. 그러나 JPA 주석 프로세서 대신 QuerydslAnnotationProcessor 플러그인을 사용하면 하위 컬렉션을 예상대로 쿼리 할 수 ​​있습니다. 모든 엔티티 클래스를 @QueryEntity 주석으로 표시하면됩니다. JPA 주석 프로세서는 @Entity 주석이있는 클래스에 대한 쿼리 클래스를 자동으로 생성합니다.

    나는 같은 오류를 만났다. 그러나 JPA 주석 프로세서 대신 QuerydslAnnotationProcessor 플러그인을 사용하면 하위 컬렉션을 예상대로 쿼리 할 수 ​​있습니다. 모든 엔티티 클래스를 @QueryEntity 주석으로 표시하면됩니다. JPA 주석 프로세서는 @Entity 주석이있는 클래스에 대한 쿼리 클래스를 자동으로 생성합니다.

    너의 포룸에서 :

              <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 주석으로 문제의 목록의 엔티티 클래스를 표시하지 않았기 때문이다. 그러나 나는 또한 2017 년 8 월에 지어진 JPA 주석 프로세서를 사용하는 또 다른 Spring-Data-Rest \ JPA 백업 API가 있다고 생각하며 하위 개체 컬렉션을 쿼리하는 것이 예상대로 작동한다고 생각합니다. 나는 나중에 그것을 확인할 수있을 것이고, 그렇다면 관련 종속성의 버전을 제공 할 것이다. 아마도이 문제가 수정되었을 수 있습니다.

  3. from https://stackoverflow.com/questions/35918824/spring-querydslpredicate-questions by cc-by-sa and MIT license