2.7. 콜렉션 쿼리

생성된 쿼리 타입을 이용하거나 또는 쿼리 타입 없이 querydsl-collections 모듈을 사용할 수 있다. 첫 번째 절에서는 생성된 쿼리 타입 없이 사용하는 방법을 설명한다.

2.7.1. 생성된 쿼리 타입 없이 사용하기

생성된 쿼리 타입 없이 querydsl-collections 모듈을 사용하려면, Querydsl 별칭 기능을 사용해야 한다. 다음은 몇 가지 예다.

먼저 다음의 정적 임포트를 추가한다.

// needed for access of the Querydsl Collections API
import static com.mysema.query.collections.CollQueryFactory.*;
// needed, if you use the $-invocations
import static com.mysema.query.alias.Alias.*;

이제 Cat 클래스에 대한 별칭 인스턴스를 만들어보자. 기본 생성자를 가진 non-final 클래스에 대해서만 Alias 인스턴스를 만들수 있다.

$ 메서드로 감싸는 방법으로 Cat 타입의 별칭 인스턴스 및 그것의 getter 메서드 호출을 경로로 바꾼다. 예를 들어, c.getKittens()에 대한 호출은 $ 메서드를 통해 c.kittends 경로로 바뀐다.

Cat c = alias(Cat.class, "cat");
for (String name : from($(c),cats)
  .where($(c.getKittens()).size().gt(0))
  .list($(c.getName()))) {
    System.out.println(name);
}

다음은 앞 예제를 다르게 작성해본 것이다. 아래 코드는 List의 size() 메서드를 $ 메서드로 감쌌다.

Cat c = alias(Cat.class, "cat");
for (String name : from($(c),cats)
  .where($(c.getKittens().size()).gt(0))
  .list($(c.getName()))) {
    System.out.println(name);
}

별칭의 모든 비-기본타입과 non-final 타입 프로퍼티는 별칭 그 자체이다. 따라서, $ 메서드 범위안에서 기본 타입이나 non-final 타입 (예, java.lang.String)을 만날 때 까지 연속된 메서드 호출이 가능하다.

예를 들어,

$(c.getMate().getName())

이 코드는 c.mate.name으로 바뀐다. 하지만, 아래 코드는 올바르게 바뀌지 않는다.

$(c.getMate().getName().toLowerCase())

그 이유는 toLowerCase() 호출은 추적되지 않기 때문이다.

별칭 타입에 대해 getter, size(), contains(Object), get(int) 만 호출할 수 있다. 나머지 다른 메서드에 대한 호출은 익셉션을 발생시킨다.

2.7.2. 생성된 쿼리 타입을 갖고 사용하기

앞서 예제를 생성된 쿼리 타입을 이용하면 다음과 같이 표현할 수 있다.

QCat cat = new QCat("cat");
for (String name : from(cat,cats)
  .where(cat.kittens.size().gt(0))
  .list(cat.name)) {
    System.out.println(name);
}

생성된 쿼리 타입을 사용하면, 별칭 인스턴스 대신 표현식을 생성할 수 있고 $ 메서드를 사용할 필요 없이 프로퍼티 경로를 바로 사용할 수 있다.

2.7.3. 메이븐 통합

다음 의존을 메이븐 프로젝트에 추가한다.

<dependency>
  <groupId>com.mysema.querydsl</groupId>
  <artifactId>querydsl-apt</artifactId>
  <version>${querydsl.version}</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>com.mysema.querydsl</groupId>
  <artifactId>querydsl-collections</artifactId>
  <version>${querydsl.version}</version>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.1</version>
</dependency>

JPA나 JDO를 사용하지 않는다면, 도메인 타입에 com.mysema.query.annotations.QueryEntity 애노테이션을 적용하고 메이븐 설정(pom.xml)에 다음 플러그인 설정을 추가함으로써 표현식 타입을 생성할 수 있다.

<project>
  <build>
  <plugins>
    ...
    <plugin>
      <groupId>com.mysema.maven</groupId>
      <artifactId>apt-maven-plugin</artifactId>
      <version>1.1.3</version>
      <executions>
        <execution>
          <goals>
            <goal>process</goal>
          </goals>
          <configuration>
            <outputDirectory>target/generated-sources/java</outputDirectory>
            <processor>com.mysema.query.apt.QuerydslAnnotationProcessor</processor>
          </configuration>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
  </build>
</project>

2.7.4. Ant 통합

클래스패스에 full-deps에 포함된 jar 파일들을 위치시키고, 다음 태스크를 이용해서 Querydsl 코드를 생성한다.

    <!-- APT based code generation -->
    <javac srcdir="${src}" classpathref="cp">
      <compilerarg value="-proc:only"/>
      <compilerarg value="-processor"/>
      <compilerarg value="com.mysema.query.apt.QuerydslAnnotationProcessor"/>
      <compilerarg value="-s"/>
      <compilerarg value="${generated}"/>
    </javac>

    <!-- compilation -->
    <javac classpathref="cp" destdir="${build}">
      <src path="${src}"/>
      <src path="${generated}"/>
    </javac>

src를 메인 소스 폴더로 변경하고, generated를 생성된 소스를 위한 폴더로 변경하고, build를 클래스 생성 폴더로 변경한다.

2.7.5. Hamcrest matchers

Querydsl Collections 모듈은 Hamcrest matchers를 제공한다. 다음의 import를 통해 사용하면 된다.

import static org.hamcrest.core.IsEqual.equalTo;
import static com.mysema.query.collections.PathMatcher.hasValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

다음과 같이 사용할 수 있다.

Car car = new Car();
car.setHorsePower(123);

assertThat(car, hasValue($.horsePower));
assertThat(car, hasValue($.horsePower, equalTo(123)));

Jeroen van Schagen가 Hamcrest matchers를 기여했다.