왜 쿼리 DSL 을 사용하는가?
- 자바 코드로 조건 문을 표현할 수 있음 Type-Safe
- Predicate 인터페이스로 조건을 조합하고, 조건을 표현하고, 조건을 모아서 관리할 수 있다.
핵심 인터페이스 QuerydslPredicateExecutor
- Spring Data 에 포함
- Optional<T> findOne(Predicate)
- List<T> | Page<T> | Iterable<T> findAll(Predicate [Pageable])
연동방법
- 의존성 추가 / http://www.querydsl.com/static/querydsl/4.1.3/reference/html_single/#jpa_integration
- querydsl-apt 는 쿼리를 생성해주는 모듈
- 플러그인추가
- apt-maven-plugin
- 스프링 부트에 의해 버전관리가 안되므로 버전추가
- goal을 작성한 후 goal 실행 시 자동생성 클래스 저장디렉토리 설정
- 사용할 프로세서 지정
- maven Compile 라이프 사이클 실행
<!-- apt 는 쿼리를 생성해주는 모듈 -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
필요 플러그인 과 의존
<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.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
지정했던 plugin : goal 실행 확인
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< me.soomin:querydsl >-------------------------
[INFO] Building querydsl 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- apt-maven-plugin:1.1.3:process (default) @ querydsl ---
[INFO]
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ querydsl ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] The encoding used to copy filtered properties files have not been set. This means that the same encoding will be used to copy filtered properties files as when copying other filtered resources. This might not be what you want! Run your build with --debug to see which files might be affected. Read more at https://maven.apache.org/plugins/maven-resources-plugin/examples/filtering-properties-files.html
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ querydsl ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 4 source files to C:\Users\doli0\Desktop\Inflearn\querydsl\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.898 s
[INFO] Finished at: 2020-11-17T15:30:46+09:00
[INFO] ------------------------------------------------------------------------
Entity 에 대한 Querydsl 을 만든 클래스를 제공한다.
리포지토리 인터페이스 적용
- QuerydslPredicateExecutor<Domain> 상속
public interface AccountRepository extends JpaRepository<Account,Long>, QuerydslPredicateExecutor<Account> {
}
Predicate 객체를 통해서 조건을 직접 정의하는 모습을 보여준다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class AccountRepositoryTest {
@Autowired
private AccountRepository accountRepository;
@Test
public void curd(){
QAccount qAccount = QAccount.account;
Predicate predicate = qAccount.firstName.containsIgnoreCase("soomin")
.and(qAccount.lastName.startsWith("Jung"));
Optional<Account> one = accountRepository.findOne(predicate);
assertThat(one).isEmpty();
}
}
Hibernate:
select
account0_.id as id1_0_,
account0_.first_name as first_na2_0_,
account0_.last_name as last_nam3_0_,
account0_.username as username4_0_
from
account account0_
where
(
lower(account0_.first_name) like ? escape '!'
)
and (
account0_.last_name like ? escape '!'
)
2020-11-17 15:38:50.509 TRACE 12016 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [%soomin%]
2020-11-17 15:38:50.510 TRACE 12016 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [Jung%]
기본 커스텀 리포지토리에서의 구현
- 기본 리포지토리와 구현체를 커스텀리포지토리로 정해놓은 상태.
- 그러므로 공통 리포지토리 인터페이스가 QuerydslPredicateExecutor<Domain> 을 상속하더라도 구현체에 구현정보가 없어 에러가 난다.
- QuerydeslPredicateExecutor 의 구현체인 QuerydslJpaRepository 가 JpaRepository 의 구현체인 SimpleJpaRepository 를 상속하고 있음.
- 그러므로 기본 리포지토리 구현체가 QuerydslJpaRepository 를 상속하게 하자.
JpaRepository 의 구현체인 SimpleJpaRepository 를 상속 + QuerydslPredicateExecutor 의 구현 = QuerydslJpaRepository 이고
커스텀 리포지토리 인터페이스 의 구현체 = MyCommonRepositoryImpl 이므로
MyCommonRepositoryImpl 는 JpaRepository + QuerydslPredicateExecutor + MyCommonRepository 의 구현체가 된다.
// 중간 리포지토리
@NoRepositoryBean
public interface MyCommonRepository<T, Id extends Serializable> extends JpaRepository<T, Id> {
boolean contatins(T entity);
}
// 기본 커스텀 리포지토리 인터페이스가 QuerydslPredicateExecutor 와 중간 리포지토리 상속 중
public interface PostRepository extends MyCommonRepository<Post, Long>, QuerydslPredicateExecutor<Post> {
}
// 기본 커스텀 리포지토리의 구현체는 QuerydslJpaRepository 를 상속해야 한다.
public class MyCommonRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements MyCommonRepository<T, ID> {
private EntityManager entityManager;
public MyCommonRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
@Override
public boolean contatins(T entity) {
return entityManager.contains(entity);
}
}
@Test
@Rollback(false)
public void testQueryDsl(){
Post post = new Post();
post.setTitle("Hibernate");
postRepository.save(post);
QPost qPost = QPost.post;
Predicate predicate = qPost.title.containsIgnoreCase("Hi");
Optional<Post> one = postRepository.findOne(predicate);
assertThat(one).isNotEmpty();
}
Hibernate:
select
post0_.id as id1_0_,
post0_.content as content2_0_,
post0_.created as created3_0_,
post0_.title as title4_0_
from
post post0_
where
lower(post0_.title) like ? escape '!'
2020-11-17 16:05:34.792 TRACE 12120 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [%hi%]
2020-11-17 16:05:34.797 TRACE 12120 --- [ main] o.h.type.descriptor.sql.BasicExtractor : extracted value ([id1_0_] : [BIGINT]) - [1]
'springframework > Spring Data JPA' 카테고리의 다른 글
Spring Data Common : Web 소개 (0) | 2020.11.17 |
---|---|
Spring Datat Common : QueryDSL 변경사항 (0) | 2020.11.17 |
Spring Data Common : Domain Event (0) | 2020.11.17 |
Spring Data Common : 공통 리포지토리 커스터마이징 (0) | 2020.11.16 |
Spring Data Common : 커스텀 리포지토리 생성 (0) | 2020.11.16 |