Q-type class는 QueryDSL 설정을 성공적으로 마치면 @Entity가 붙은 클래스를 찾아 자동으로 생성된다.
예를들어 @Entity가 붙은 User.java 클래스가 있다면 QUser.java 파일이 자동으로 생성된다.
이러한 Q-type의 class들은 QueryDSL을 사용하여 메소드 기반으로 쿼리를 작성할 때 우리가 만든 도메인 클래스의 구조를 설명해주는 메타데이터 역할을 하며 쿼리의 조건을 설정할 때 사용된다.
QueryDSL을 사용하여 쿼리를 Build 하기 위해서는 JPAQueryFactory가 필요하다. JPAQueryFactory를 사용하면 EntityManager를 통해서 질의가 처리되고, JPQL을 사용한다.
참고로 SQLQueryFactory 라는것도 있는데 이 것을 사용하면 JDBC를 사용하여 질의가 처리되고, SQL을 사용한다.
다음과 같이 얻어올 수 있다.
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("com.baeldung.querydsl.intro");
EntityManager em = entityManagerFactory.createEntityManager();
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QUser user = QUser.user;
User c = queryFactory.selectFrom(user)
.where(user.login.eq("David"))
.fetchOne();
QueryFactory의 selectFrom() 메서드 (또는 select)를 호출하면 JPAQuery를 리턴하고 쿼리 build가 시작된다.
(참고로, QueryFactory는 select절부터 적을 수 있지만 JPAQuery는 그렇지 못하다.)
그리고 where()를 호출하여 쿼리의 조건절을 build 한다. 이때, Q-type의 인스턴스를 사용하여 적절한 조건을 설정할 수 있다.
마지막으로 fetchOne()를 호출하여 building chain을 끝내고 데이터베이스에서 데이터를 꺼내와 영속성 컨텍스트에 저장한다.
fetchOne()은 해당하는 데이터가 없으면 null을 반환하고, 데이터가 둘 이상 존재하면 NonUniqueResultException을 throws 한다.
orderBy()를 호출하여 정렬조건을 설정할 수 있다.
List<User> c = queryFactory.selectFrom(user)
.orderBy(user.login.asc())
.fetch();
위와 같이 작성하면 user.login을 기준으로 오름차순 정렬하여 데이터를 가져온다.
NumberPath<Long> count = Expressions.numberPath(Long.class, "c");
List<Tuple> userTitleCounts = queryFactory.select(
blogPost.title, blogPost.id.count().as(count))
.from(blogPost)
.groupBy(blogPost.title)
.orderBy(count.desc())
.fetch();
위의 쿼리는 blog.title로 그룹핑하여 같은 title을 가진 데이터의 개수를 기준을 정렬한다.
count() 필드의 alias를 orderBy의 인자로 사용한 것에 주의하자.
QBlogPost blogPost = QBlogPost.blogPost;
List<User> users = queryFactory.selectFrom(user)
.innerJoin(user.blogPosts, blogPost)
.on(blogPost.title.eq("Hello World!"))
.fetch();
위 코드는 User와 BlogPost를 조인하여 blogPost가 "hello world"인 행을 가져온다.
직접 테스트 해보니 on으로 되어있지만 실제 쿼리의 where처럼 동작하는듯 하다.
innerJoin()하는순간 user.blogPosts.id = blogPost.id 인 것만 가져오는듯 하다.
아래 서브 쿼리를 활용한 코드이다.
List<User> users = queryFactory.selectFrom(user)
.where(user.id.in(
JPAExpressions.select(blogPost.user.id)
.from(blogPost)
.where(blogPost.title.eq("Hello World!"))))
.fetch();
where 조건에 맞는 레코드를 set에 설정한 데이터로 수정할 수 있다.
where 없이 사용하면 모든 레코드를 수정한다.
queryFactory.update(user)
.where(user.login.eq("Ash"))
.set(user.login, "Ash2")
.set(user.disabled, true)
.execute();
where 조건에 맞는 레코드를 삭제한다.
queryFactory.delete(user)
.where(user.login.eq("David"))
.execute();
JPAQueryFactory는 insert()를 가지고 있지 않다.
insert를 하려면 EntityManager를 사용하자! (SQLQueryFactory는 가능하다)
https://www.youtube.com/watch?v=gRqyzi9VGYc ([토크ON세미나] JPA 프로그래밍 기본기 다지기 8강 - Spring Data JPA와 QueryDSL 이해 | T아카데미)
https://www.baeldung.com/intro-to-querydsl
select pet_age, (total / t2.cnt ) * 100 as 퍼센트
from (
select pet_age, count() as total
from pet
group by pet_age
) as t1, (select count() as cnt
from pet) as t2
group by pet_age
order by pet_age asc;
위 코드를 QueryDsl로 사용하려면 어떻게 해야할까요..?
alias같은 걸 어떤식으로 처리해줘야 할지 모르겠습니다 ㅠㅠ