QueryDsl정리
Setting
plugins {
//querydsl 추가
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}
dependencies{
//querydsl 추가
implementation 'com.querydsl:querydsl-jpa'
}
맨 아래 추가//querydsl 추가
//build -> generate -> querydsl에 querydsl 컴파일시 파일 생성됨
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
configurations {
querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
//querydsl 추가 끝
application.yml
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/querydsl
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create //로딩시점 엔티티 테이블 모두drop 후 다시 생성
properties:
hibernate:
# show_sql: true //system.out으로 봄, 근데 debug모드랑 같은 거라서 두번 보이기 때문에 주석처리
format_sql: true
use_sql_comments : true // sql 쿼리문으로 볼 수 있음
logging.level:
org.hibernate.SQL: debug
# org.hibernate.type: trace
디버깅 모드에 ? 표 값을 알고 싶으면 외부 라이브러리를 추가해줌
https://github.com/gavlyukovskiy/spring-boot-data-source-decorator
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'
BASIC TEST
@SpringBootTest
@Transactional
public class QuerydslBasicTests {
@PersistenceContext
EntityManager em;
@BeforeEach
public void before() {
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
em.persist(teamA);
em.persist(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 20, teamA);
Member member3 = new Member("member3", 30, teamB);
Member member4 = new Member("member4", 40, teamB);
em.persist(member1);
em.persist(member2);
em.persist(member3);
em.persist(member4);
}
//===================JPQL로 작성========================/
@Test
public void startJPQL() {
//member1 찾기
Member findMember = em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", "member1")
.getSingleResult();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
//===================Querydsl로 작성========================/
@Test
public void startQuerydsl() {
//query dsl 쓰기 위해선 factory 호출이 필요
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
//QMember가 없기 때문에 오른족 위 gradle 눌러서 Tasks -> other -> compilequerydsl눌러서 컴파일 후 해당 객체 호출
//호출후 구분짓기 위해 이름 지어줘야함 여기서는 ("m")
QMember m = new QMember("m");
//파라미터 자동으로 바인딩 해줌
Member findMember = queryFactory
.select(m)
.from(m)
.where(m.username.eq("member1"))//파라미터 바인딩 처리
.fetchOne();
assertThat(findMember.getUsername()).isEqualTo("member1");
}
}
아래방법으로 하고 import static으로 선언해서 쓰는게 좋음!
- select + from = selectFrom으로 적을 수 있음
예시
member.username.eq("member1") // username = 'member1'
member.username.ne("member1") //username != 'member1'
member.username.eq("member1").not() // username != 'member1'
member.username.isNotNull() //이름이 is not null
member.age.in(10, 20) // age in (10,20)
member.age.notIn(10, 20) // age not in (10, 20)
member.age.between(10,30) //between 10, 30
member.age.goe(30) // age >= 30
member.age.gt(30) // age > 30
member.age.loe(30) // age <= 30
member.age.lt(30) // age < 30
member.username.like("member%") //like 검색
member.username.contains("member") // like ‘%member%’ 검색
member.username.startsWith("member") //like ‘member%’ 검색
@Test
public void searchAndParam() {
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List<Member> result1 = queryFactory
.selectFrom(member)
.where( //where 안에 콤마로 넘기면 자동 and 조건
member.username.eq("member1"),
member.age.eq(10))
.fetch();
assertThat(result1.size()).isEqualTo(1);
}
프로젝션과 결과 반환
프로젝션 : select 대상
//프로젝션 대상이 하나인 경우
@Test
public void simpleProjection() {
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List<String> result = queryFactory
.select(member.username)
.from(member)
.fetch();
for (String s : result) {
System.out.println("Member = " + s);
}
}
//튜플로 조회하는 경우(프로젝션 대상이 2개 이상
@Test
public void tupleProjection() {
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List<Tuple> result = queryFactory
.select(member.username, member.age) //조회 대상이 2개
.from(member)
.fetch();
for (Tuple tuple : result){
String username = tuple.get(member.username);
Integer age = tuple.get(member.age);
System.out.println("username = " + username);
System.out.println("age = " + age);
}
}
조회시는 queydsl, 외부로 보낼때는 DTO로 바꿔서 반환
JPA조회시
//DTO로 조회(JPA)
@Test
public void findDtoByJPQL(){
List<MemberDto> result = em.createQuery("select new study.querydsl.dto.MemberDto(m.username, m.age) from Member m", MemberDto.class)
.getResultList();
for(MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}
직접 생성자 호출해서 객체 만드는 것처럼 new를통해 패키지로 접근
QueryDsl 3가지 방법으로 조회
//============Querydsl // setter로 조회 ===============//
@Test
public void findDtoBySetter(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List <MemberDto> result = queryFactory
//Projection.bean을 호출하고 인자값으로(조회할 클래스, 조회할 섹션)받음
.select(Projections.bean(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
} // 이 방법은 MemberDto(조회하려는 클래스)에 기본 생성자가 있어야 한다.
//============Querydsl // fields로 조회 ===============//
@Test
public void findDtoByField(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List <MemberDto> result = queryFactory
//위와 코드가 같지만 fields를 호출함
.select(Projections.fields(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}//이 방법은 Dto 클래스에 기본생성자가 없어도 호출할 수 있다.
//============Querydsl // 생성자 접근방법으로 조회 ===============//
@Test
public void findDtoByConstructor(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List <MemberDto> result = queryFactory
//Projectin에서 constructor를 호출
.select(Projections.constructor(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
} //이 방법은 해당 Dto 클래스의 변수의 타입을 맞춰서 호출해줘야 한다 .
별칭이 다른 경우
package study.querydsl.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class UserDto {
private String name;
private int age;
}
//============userDto 조회 ===============//
@Test
public void findUserDto(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List <UserDto> result = queryFactory
.select(Projections.fields(UserDto.class,
member.username.as("name), //별칭이다를경우 해당 변수 별칭 적어줌
member.age))
.from(member)
.fetch();
for (UserDto userDto : result) {
System.out.println("memberDto = " + userDto);
}
}
//dto 클래스의 변수별칭이 다를 경우
//============서브쿼리를 이용한 조회 ===============//
List<UserDto> fetch = queryFactory
.select(Projections.fields(UserDto.class,
member.username.as("name"),
ExpressionUtils.as(
JPAExpressions
.select(memberSub.age.max())
.from(memberSub), "age")
)
).from(member)
.fetch();
//=== 아니면 생성자를 이용하면 된다 ====//
List<MemberDto> result = queryFactory
.select(Projections.constructor(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
}
반환방법 2
해당 Dto클래스에 querydsl을 생성(어노테이션 붙임으로서) 그리고 compilequerydsl 해줘야함
package study.querydsl.dto;
import com.querydsl.core.annotations.QueryProjection;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.repository.Query;
@Data
@NoArgsConstructor
public class MemberDto {
private String username;
private int age;
//이 어노테이션을 붙여줘야 한다!!
@QueryProjection
public MemberDto(String username, int age){
this.username = username;
this.age = age;
}
}
//------------------TEST-------------//@Test
@Test
public void findDtoByQueryProjection(){
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List<MemberDto> result = queryFactory
.select(new QMemberDto(member.username, member.age))
.from(member)
.fetch();
for(MemberDto memberDto : result) {
System.out.println("memberDto =" + memberDto);
}
}
Author And Source
이 문제에 관하여(QueryDsl정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@kurikuri/QueryDsl정리저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)