SPRING/INFLEARN

[๊ฐ•์˜] ์‹ค์ „! Querydsl 1

ozllzL 2022. 8. 22. 05:34

https://www.inflearn.com/course/querydsl-%EC%8B%A4%EC%A0%84

 

์‹ค์ „! Querydsl - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

Querydsl์˜ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์‹ค๋ฌด ํ™œ์šฉ๊นŒ์ง€, ํ•œ๋ฒˆ์— ํ•ด๊ฒฐํ•ด๋ณด์„ธ์š”!, ๋ณต์žกํ•œ ์ฟผ๋ฆฌ, ๋™์  ์ฟผ๋ฆฌ๋Š” ์ด์ œ ์•ˆ๋…•! Querydsl๋กœ ์ž๋ฐ” ๋ฐฑ์—”๋“œ ๊ธฐ์ˆ ์„ ๋‹จ๋‹จํ•˜๊ฒŒ. ๐Ÿšฉ ๋ณธ ๊ฐ•์˜๋Š” ๋กœ๋“œ๋งต ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ๋ณธ ๊ฐ•์˜๋Š” ์ž๋ฐ” ๋ฐฑ์—”

www.inflearn.com

 

0. Querydsl ์†Œ๊ฐœ

์ฟผ๋ฆฌ๋ฅผ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๊ฒŒ ๋„์™€์ฃผ์–ด ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์— ์žก์„ ์ˆ˜ ์žˆ์Œ

๋™์  ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ

๋‹จ์ˆœ ๋ฐ˜๋ณต ์ฝ”๋“œ๊ฐ€ ์ค„์–ด๋“ ๋‹ค

 

1. ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์„ค์ •

ํ•ญ์ƒ ํ•˜๋˜ ํ™˜๊ฒฝ ์„ค์ •์„ ํ•ด์ค€๋‹ค

gradle๋„ intelij๋กœ

ํ˜น์‹œ ์•ˆ๋๋‹ค๋ฉด enable annotation processing๋„ ์ผœ์ค€๋‹ค

 

ํ…Œ์ŠคํŠธ ์šฉ์œผ๋กœ ์—”ํ‹ฐํ‹ฐ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  ์ € gradle์— ์žˆ๋Š” complieQuerydsl ๋”ฐ๋‹ฅ!

ํ˜น์€ ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์—์„œ ./gradlew clean์ด๋‚˜ complieJava ๋ช…๋ น์–ด ์ด์šฉํ•ด์„œ ๋นŒ๋“œ ๊ฐ€๋Šฅ

 

์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ํ•ด๋ณด์ž

๋”๋ณด๊ธฐ
buildscript {
   ext {
      queryDslVersion = "5.0.0"
   }
}

plugins {
   id 'org.springframework.boot' version '2.6.0'
   id 'io.spring.dependency-management' version '1.0.11.RELEASE'
   //querydsl ์ถ”๊ฐ€
   id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
   id 'java'
}

group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
   compileOnly {
      extendsFrom annotationProcessor
   }
}

repositories {
   mavenCentral()
}

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   compileOnly 'org.projectlombok:lombok'
   runtimeOnly 'com.h2database:h2'
   //querydsl ์ถ”๊ฐ€
   implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
   implementation "com.querydsl:querydsl-apt:${queryDslVersion}"


   annotationProcessor 'org.projectlombok:lombok'
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
   useJUnitPlatform()
}

//querydsl ์ถ”๊ฐ€ ์‹œ์ž‘
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
   jpa = true
   querydslSourcesDir = querydslDir
}
sourceSets {
   main.java.srcDir querydslDir
}
compileQuerydsl{
   options.annotationProcessorPath = configurations.querydsl
}
configurations {
   compileOnly {
      extendsFrom annotationProcessor
   }
   querydsl.extendsFrom compileClasspath
}
//querydsl ์ถ”๊ฐ€ ๋

 

๊ทธ๋Ÿผ build ํด๋”์™€ ์ด๋Ÿฐ๊ฒŒ ์ƒ๊ธด๋‹ค.

์–˜๋Š” ์ž๋™์œผ๋กœ generate ๋˜๋Š” ๊ฑฐ๋ผ git์— ์˜ฌ๋ฆฌ๋ฉด ์•ˆ๋œ๋‹ค.(git ignore ํ•ด์•ผํ•จ, ๋ณดํ†ต ๊ธฐ๋ณธ์œผ๋กœ ๋˜์–ด์žˆ๋‹ค)

 

์‚ฌ์šฉ์€ ์ด๋ ‡๊ฒŒ!

@SpringBootTest
@Transactional
class QuerydslApplicationTests {


	@Autowired
	EntityManager em;

	@Test
	void contextLoads() {
		Hello hello = new Hello();
		em.persist(hello);
		JPAQueryFactory query = new JPAQueryFactory(em);
		QHello qHello = QHello.hello;
		Hello result = query
				.selectFrom(qHello)
				.fetchOne();
		Assertions.assertThat(result).isEqualTo(hello);
		Assertions.assertThat(result.getId()).isEqualTo(hello.getId());
	}

}

 

http://querydsl.com/

 

Querydsl - Unified Queries for Java

Unified Queries for Java. Querydsl is compact, safe and easy to learn. <!-- Querydsl Unified Queries for Java Querydsl provides a unified querying layer for multiple backends in Java. Compared to the alternatives Querydsl is more compact, safer and easier

querydsl.com

 

์•„๋ž˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋ฉด ์ฟผ๋ฆฌ์˜ ? ๊ฐ’์ด ๋‚˜์˜จ๋‹ค (์„ฑ๋Šฅ ์ €ํ•˜๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ ๊ดœ์ฐฎ์€์ง€ ๋ณด๊ณ  ์‚ฌ์šฉ)

implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'

org.hibernate.type: trace

2. ์˜ˆ์ œ ๋„๋ฉ”์ธ ๋ชจ๋ธ

 

๋งž์ถฐ์„œ ์—”ํ‹ฐํ‹ฐ ๋งŒ๋“ค๊ณ  ํ…Œ์ŠคํŠธ ๊ตฟ

@SpringBootTest
@Transactional
//@Commit ์—†์œผ๋ฉด ๋กค๋ฐฑ์„ ํ•ด๋ฒ„๋ฆผ ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์™€ ๊ผฌ์ผ ์ˆ˜ ์žˆ์Œ
public class MemberTest {
    @PersistenceContext
    EntityManager em;
    @Test
    public void testEntity() {
        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);

        //์ดˆ๊ธฐํ™”
        em.flush();
        em.clear();

        //ํ™•์ธ
        List<Member> members = em.createQuery("select m from Member m",
                        Member.class)
                .getResultList();
        for (Member member : members) {
            System.out.println("member=" + member);
            System.out.println("-> member.team=" + member.getTeam());
        }
    }
}

3. ๊ธฐ๋ณธ ๋ฌธ๋ฒ•

- JPQL vs Querydsl

@Test
public void startJPQL() {

    String qlString =
            "select m from Member m " +
                    "where m.username = :username";
    Member findMember = em.createQuery(qlString, Member.class)
            .setParameter("username", "member1")
            .getSingleResult();
    Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}

@Test
public void startQuerydsl() {
    JPAQueryFactory queryFactory = new JPAQueryFactory(em);
    QMember m = new QMember("m");
    Member findMember = queryFactory
            .select(m)
            .from(m)
            .where(m.username.eq("member1"))//ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ์ฒ˜๋ฆฌ
            .fetchOne();
    Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}

JPQL์€ ์ฟผ๋ฆฌ๊ฐ€ ํ‹€๋ฆฌ๋ฉด ์‹คํ–‰ ํ•ด์•ผ ์•Œ๋ ค์คŒ

Querydls์€ ์ปดํŒŒ์ผ ์‹œ์ ์— ์˜ค๋ฅ˜๋ฅผ ์žก์•„์ค€๋‹ค.

package study.querydsl;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import study.querydsl.entity.Member;
import study.querydsl.entity.QMember;
import study.querydsl.entity.Team;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;

@SpringBootTest
@Transactional
public class QuerydslBasicTest {
    @PersistenceContext
    EntityManager em;

    JPAQueryFactory queryFactory;
    
    @BeforeEach
    public void before() {
        //๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์— ๋ฌธ์ œ ์—†๊ฒŒ em์—์„œ ์ž˜ ๋˜์–ด์žˆ์–ด์„œ ๊ดœ์ฐฎ์Œ
        //๋™์‹œ์„ฑ ๋ฌธ์ œ ์•ˆ์ƒ๊น€
        queryFactory = new JPAQueryFactory(em);
        
        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);
    }

    @Test
    public void startJPQL() {

        String qlString =
                "select m from Member m " +
                        "where m.username = :username";
        Member findMember = em.createQuery(qlString, Member.class)
                .setParameter("username", "member1")
                .getSingleResult();
        Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
    }
    
    @Test
    public void startQuerydsl() {
        QMember m = new QMember("m");
        Member findMember = queryFactory
                .select(m)
                .from(m)
                .where(m.username.eq("member1"))//ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ์ฒ˜๋ฆฌ
                .fetchOne();
        Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
    }
}

- ๊ธฐ๋ณธ Q-Type ํ™œ์šฉ

    @Test
    public void startQuerydsl() {
        Member findMember = queryFactory
                .select(member)
                .from(member)
                .where(member.username.eq("member1"))//ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ์ฒ˜๋ฆฌ
                .fetchOne();
        Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
    }

์ฝ”๋“œ์ •๋ฆฌ

QMember์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ ์–ธ๋˜์–ด์žˆ๋Š” member ์‚ฌ์šฉ(static import)

 

- ๊ฒ€์ƒ‰ ์กฐ๊ฑด ์ฟผ๋ฆฌ

 

@Test
public void startQuerydsl() {
    Member findMember = queryFactory
            .select(member)
            .from(member)
            .where(member.username.eq("member1")
                    .and(member.age.eq(10)))
            .fetchOne();
    Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}

and๋Š” ์ด๋ ‡๊ฒŒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค

@Test
public void startQuerydsl() {
    Member findMember = queryFactory
            .select(member)
            .from(member)
            .where(
                    member.username.eq("member1")
                    ,member.age.eq(10)
            )
            .fetchOne();
    Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");
}

์˜จ๊ฐ– ์กฐ๊ฑด๋“ค

๋”๋ณด๊ธฐ

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%’ ๊ฒ€์ƒ‰

- ๊ฒฐ๊ณผ ์กฐํšŒ

๋”๋ณด๊ธฐ

fetch() : ๋ฆฌ์ŠคํŠธ ์กฐํšŒ, ๋ฐ์ดํ„ฐ ์—†์œผ๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
fetchOne() : ๋‹จ ๊ฑด ์กฐํšŒ
    ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด : null
    ๊ฒฐ๊ณผ๊ฐ€ ๋‘˜ ์ด์ƒ์ด๋ฉด : com.querydsl.core.NonUniqueResultException
fetchFirst() : limit(1).fetchOne()
fetchResults() : ํŽ˜์ด์ง• ์ •๋ณด ํฌํ•จ, total count ์ฟผ๋ฆฌ ์ถ”๊ฐ€ ์‹คํ–‰
fetchCount() : count ์ฟผ๋ฆฌ๋กœ ๋ณ€๊ฒฝํ•ด์„œ count ์ˆ˜ ์กฐํšŒ

๋ฆฌ์ŠคํŠธ. ํŒ€ ์ฟผ๋ฆฌ ๊ฐœ์ˆ˜๋งŒํผ ๋‚˜๊ฐ

fetchOne์€ ์—ฌ๋Ÿฌ๊ฐœ๋ผ ์˜ค๋ฅ˜๋‚จ ์ƒ๋žต

ํ•˜๋‚˜๋งŒ ์ฟผ๋ฆฌ ๋‚ด๊ณ  ๋ง์•˜์Œ
count ์ฟผ๋ฆฌ

 

- ์ •๋ ฌ

@Test
public void sort() {
    em.persist(new Member(null, 100));
    em.persist(new Member("member5", 100));
    em.persist(new Member("member6", 100));
    //๋‚˜์ด ๋‚ด๋ฆผ์ฐจ, ์ด๋ฆ„ ์˜ค๋ฆ„์ฐจ ์ˆœ
    List<Member> result = queryFactory
            .selectFrom(member)
            .where(member.age.eq(100))
            .orderBy(member.age.desc(), member.username.asc().nullsLast())
            .fetch();
    Member member5 = result.get(0);
    Member member6 = result.get(1);
    Member memberNull = result.get(2);
    
    //์ด๋ฆ„์ด null์ธ ์‚ฌ๋žŒ์ด ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋‚˜์™€์•ผ ํ•œ๋‹ค (.nullsLast())
    //๋ฐ˜๋Œ€๋Š” nullFirst๋„ ์žˆ์Œ
    assertThat(member5.getUsername()).isEqualTo("member5");
    assertThat(member6.getUsername()).isEqualTo("member6");
    assertThat(memberNull.getUsername()).isNull();
}

- ํŽ˜์ด์ง•

@Test
public void paging1() {
    List<Member> result = queryFactory
            .selectFrom(member)
            .orderBy(member.username.desc())
            .offset(1) //0๋ถ€ํ„ฐ ์‹œ์ž‘(zero index)
            .limit(2) //์ตœ๋Œ€ 2๊ฑด ์กฐํšŒ
            .fetch();
    assertThat(result.size()).isEqualTo(2);
}

@Test
    public void paging2() {
        QueryResults<Member> queryResults = queryFactory
                .selectFrom(member)
                .orderBy(member.username.desc())
                .offset(1)
                .limit(2)
                .fetchResults();
        assertThat(queryResults.getTotal()).isEqualTo(4);
        assertThat(queryResults.getLimit()).isEqualTo(2);
        assertThat(queryResults.getOffset()).isEqualTo(1);
        assertThat(queryResults.getResults().size()).isEqualTo(2);
    }

- ์ง‘ํ•ฉ

@Test
public void aggregation() throws Exception {
    List<Tuple> result = queryFactory
            .select(member.count(),
                    member.age.sum(),
                    member.age.avg(),
                    member.age.max(),
                    member.age.min())
            .from(member)
            .fetch();
    Tuple tuple = result.get(0);
    assertThat(tuple.get(member.count())).isEqualTo(4);
    assertThat(tuple.get(member.age.sum())).isEqualTo(100);
    assertThat(tuple.get(member.age.avg())).isEqualTo(25);
    assertThat(tuple.get(member.age.max())).isEqualTo(40);
    assertThat(tuple.get(member.age.min())).isEqualTo(10);
}

@Test
public void group() throws Exception {
    List<Tuple> result = queryFactory
            .select(team.name, member.age.avg())
            .from(member)
            .join(member.team, team)
            .groupBy(team.name)
            .fetch();
    Tuple teamA = result.get(0);
    Tuple teamB = result.get(1);
    assertThat(teamA.get(team.name)).isEqualTo("teamA");
    assertThat(teamA.get(member.age.avg())).isEqualTo(15);
    assertThat(teamB.get(team.name)).isEqualTo("teamB");
    assertThat(teamB.get(member.age.avg())).isEqualTo(35);
}

sql๊ณผ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค having๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

 

- ์กฐ์ธ - ๊ธฐ๋ณธ์กฐ์ธ

join() , innerJoin() : ๋‚ด๋ถ€ ์กฐ์ธ(inner join)
leftJoin() : left ์™ธ๋ถ€ ์กฐ์ธ(left outer join)
rightJoin() : rigth ์™ธ๋ถ€ ์กฐ์ธ(rigth outer join)

@Test
public void join() throws Exception {
    QMember member = QMember.member;
    QTeam team = QTeam.team;
    List<Member> result = queryFactory
            .selectFrom(member)
            .join(member.team, team)
            .where(team.name.eq("teamA"))
            .fetch();
    assertThat(result)
            .extracting("username")
            .containsExactly("member1", "member2");
}

thetaJoin : ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์กฐ์ธ

from์— ์—ฌ๋Ÿฌ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์„ ํƒํ•˜์—ฌ ๋ƒ…๋‹ค ๊ณฑํ•˜๊ธฐ

์™ธ๋ถ€ ์กฐ์ธ ๋ถˆ๊ฐ€๋Šฅ, ์กฐ์ธ on์ ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ์™ธ๋ถ€ ์กฐ์ธ๋„ ๊ฐ€๋Šฅ

 

- ์กฐ์ธ - on ์ ˆ

ON์ ˆ์„ ํ™œ์šฉํ•œ ์กฐ์ธ(JPA 2.1๋ถ€ํ„ฐ ์ง€์›)
1. ์กฐ์ธ ๋Œ€์ƒ ํ•„ํ„ฐ๋ง
2. ์—ฐ๊ด€๊ด€๊ณ„ ์—†๋Š” ์—”ํ‹ฐํ‹ฐ ์™ธ๋ถ€ ์กฐ์ธ

 

์˜ˆ์‹œ

* JPQL: SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'teamA'
* SQL: SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.TEAM_ID=t.id and t.name='teamA'

@Test
public void join_on_filtering() throws Exception {
    //select๊ฐ€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํƒ€์ž…์ด๋ผ ํŠœํ”Œ์ž„
    List<Tuple> result = queryFactory
            .select(member, team)
            .from(member)
            .leftJoin(member.team, team).on(team.name.eq("teamA"))
            .fetch();
    for (Tuple tuple : result) {
        System.out.println("tuple = " + tuple);
    }
}

๋‚ด๋ถ€ ์กฐ์ธ์ผ ๋•Œ๋Š” on๊ณผ where์€ ๊ธฐ๋Šฅ์ด ๋˜‘๊ฐ™์Œ

๋” ์ต์ˆ™ํ•œ where์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋„๋ก!

 

* JPQL: SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
* SQL: SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.username = t.name

@Test
public void join_on_no_relation() throws Exception {
    em.persist(new Member("teamA"));
    em.persist(new Member("teamB"));
    List<Tuple> result = queryFactory
            .select(member, team)
            .from(member)
            .leftJoin(team).on(member.username.eq(team.name))
            .fetch();
    for (Tuple tuple : result) {
        System.out.println("t=" + tuple);
    }
}

leftjoin์— team ํ•˜๋‚˜๋งŒ ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์ด ํŠน์ง•

์–ด์ฐจํ”ผ ๋น„๊ตํ•ด์„œ ๋ถ™์ด๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋‘ ๊ฐœ ๋„ฃ์„ ํ•„์š”๊ฐ€ ์—†์Œ

 

- ์กฐ์ธ - ํŽ˜์น˜์กฐ์ธ

์„ฑ๋Šฅ ์ตœ์ ํ™”์— ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

@PersistenceUnit
EntityManagerFactory emf;

@Test
public void fetchJoinNo() throws Exception {
    em.flush();
    em.clear();
    Member findMember = queryFactory
            .selectFrom(member)
            .join(member.team, team)
            .fetchJoin()//์ด๊ฑธ ๋ถ™์ด๋ฉด fetch๊ฐ€ ๋œ๋‹ค
            .where(member.username.eq("member1"))
            .fetchOne();
    boolean loaded =
            emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam());//ํŽ˜์น˜ ๋๋Š”์ง€ ์•ˆ๋๋Š”์ง€ ์—ฌ๋ถ€

}

- ์„œ๋ธŒ ์ฟผ๋ฆฌ

@Test
public void subQuery() throws Exception {
    //๊ฒน์น˜๋ฉด ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ƒˆ๋กœ ์„ ์–ธ(ex. ์„œ๋ธŒ์ฟผ๋ฆฌ์šฉ)
    QMember memberSub = new QMember("memberSub");
    
    List<Member> result = queryFactory
            .selectFrom(member)
            .where(member.age.eq(
                    JPAExpressions
                            .select(memberSub.age.max())
                            .from(memberSub)
            ))
            .fetch();
    assertThat(result).extracting("age")
            .containsExactly(40);
}

eq๋ฟ ์•„๋‹ˆ๋ผ goe, in๋„ ๋˜‘๊ฐ™์ด ๊ฐ€๋Šฅํ•˜๋‹ค

 

select ์ ˆ ์† ์„œ๋ธŒ์ฟผ๋ฆฌ(JPAExpressions static import)

@Test
public void select_subQuery() throws Exception {
    
    QMember memberSub = new QMember("memberSub");
    List<Tuple> fetch = queryFactory
            .select(member.username,
                    select(memberSub.age.avg())
                            .from(memberSub)
            ).from(member)
            .fetch();
    for (Tuple tuple : fetch) {
        System.out.println("username = " + tuple.get(member.username));
        System.out.println("age = " +
                tuple.get(select(memberSub.age.avg())
                        .from(memberSub)));
    }
}

from ์ ˆ์˜ ์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” ์•ˆ๋œ๋‹ค.

-> ํ•ด๊ฒฐ

1. join์œผ๋กœ ๋ณ€๊ฒฝ

2. ์ฟผ๋ฆฌ2๋ฒˆ ๋ถ„๋ฆฌ

3. native SQL ์‚ฌ์šฉ(์ด๊ฑด JPA์˜ ํ•œ๊ณ„)

 

ํ•œ ๋ฐฉ ์ฟผ๋ฆฌ๋ณด๋‹ค๋Š” ์—ฌ๋Ÿฌ ์ฟผ๋ฆฌ๋กœ ๋‚˜๋ˆ ์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ํšจ์œจ์ ์ผ ๋•Œ๊ฐ€ ์žˆ๋‹ค

 

- case๋ฌธ

ํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์™ ๋งŒํ•˜๋ฉด DB์—์„œ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ง์ž

@Test
public void basicCase(){
    List<String> result = queryFactory
            .select(member.age
                    .when(10).then("์—ด์‚ด")
                    .when(20).then("์Šค๋ฌด์‚ด")
                    .otherwise("๊ธฐํƒ€"))
            .from(member)
            .fetch();

    for (String s : result) {
        System.out.println("s = " + s);
    }
}

public void complexCase(){
    List<String> result = queryFactory
            .select(new CaseBuilder()
                    .when(member.age.between(0, 20)).then("0~20์‚ด")
                    .when(member.age.between(21, 30)).then("21~30์‚ด")
                    .otherwise("๊ธฐํƒ€"))
            .from(member)
            .fetch();

    for (String s : result) {
        System.out.println("s = " + s);
    }
}

- ์ƒ์ˆ˜, ๋ฌธ์ž ๋”ํ•˜๊ธฐ

//๋ƒ…๋‹ค ์ƒ์ˆ˜ ๋ถ™์ด๊ธฐ
@Test
public void constant(){
    Tuple result = queryFactory
            .select(member.username, Expressions.constant("A"))
            .from(member)
            .fetchFirst();
}

@Test
public void concat(){
    //.stringValue()๋กœ ์ˆซ์ž -> ๋ฌธ์ž ์ „ํ™˜
    String result = queryFactory
            .select(member.username.concat("_").concat(member.age.stringValue())) //{username_age}
            .from(member)
            .where(member.username.eq("member1"))
            .fetchOne();
}