QueryDsl정리

53883 단어 JPAJPA

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);
        }
    }

좋은 웹페이지 즐겨찾기