From 6784613b8ecae7c52d8aad7e414b457e047873cf Mon Sep 17 00:00:00 2001 From: haerong22 Date: Tue, 7 Sep 2021 01:11:53 +0900 Subject: [PATCH] querydsl : basic - join, theta join, join on, fetch join, subquery, case, concat --- querydsl/db.mv.db | Bin 40960 -> 49152 bytes .../example/querydsl/QuerydslBasicTest.java | 245 ++++++++++++++++++ 2 files changed, 245 insertions(+) diff --git a/querydsl/db.mv.db b/querydsl/db.mv.db index 80a93da02378d27cbfef9a16d5f2da1b38b5afbc..5b557e6c25a16712a7614fca61eccdabe5f81323 100644 GIT binary patch literal 49152 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 literal 40960 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 S{)pHA$F>`XNsJaiqW=%IjvGAy diff --git a/querydsl/src/test/java/com/example/querydsl/QuerydslBasicTest.java b/querydsl/src/test/java/com/example/querydsl/QuerydslBasicTest.java index ff1ebb1b..7f7edfe1 100644 --- a/querydsl/src/test/java/com/example/querydsl/QuerydslBasicTest.java +++ b/querydsl/src/test/java/com/example/querydsl/QuerydslBasicTest.java @@ -6,6 +6,9 @@ import com.example.querydsl.entity.QTeam; import com.example.querydsl.entity.Team; import com.querydsl.core.QueryResults; import com.querydsl.core.Tuple; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQueryFactory; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -15,11 +18,14 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceUnit; import java.util.List; import static com.example.querydsl.entity.QMember.*; import static com.example.querydsl.entity.QTeam.*; +import static com.querydsl.jpa.JPAExpressions.*; import static org.assertj.core.api.Assertions.*; @SpringBootTest @@ -203,4 +209,243 @@ public class QuerydslBasicTest { assertThat(teamB.get(team.name)).isEqualTo("teamB"); assertThat(teamB.get( member.age.avg())).isEqualTo(35); } + + /** + * 팀 A에 소속된 모든 회원 + */ + @Test + void join() { + List result = queryFactory + .selectFrom(member) + .join(member.team, team) + .where(team.name.eq("teamA")) + .fetch(); + + assertThat(result) + .extracting("username") + .containsExactly("member1", "member2"); + } + + /** + * 세타 조인 - 연관관계 없는 테이블 끼리 조인 + * 회원의 이름이 팀 이름과 같은 회원을 조회 + */ + @Test + void theta_join() { + em.persist(new Member("teamA")); + em.persist(new Member("teamB")); + em.persist(new Member("teamC")); + + List result = queryFactory + .select(member) + .from(member, team) + .where(member.username.eq(team.name)) + .fetch(); + + assertThat(result) + .extracting("username") + .containsExactly("teamA", "teamB"); + } + + /** + * 회원과 팀을 조인하면서, 팀 이름이 teamA인 팀만 조인, 회원은 모두 조인 + * JPQL: select m, t from Member m left join m.team t on t.name = 'teamA' + */ + @Test + void join_on_filtering() { + List 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); + } + } + + /** + * 연관관계 없는 엔티티 외부 조인 + * 회원의 이름이 팀 이름과 같은 대상 외부 조인 + */ + @Test + void join_on_no_relation() { + em.persist(new Member("teamA")); + em.persist(new Member("teamB")); + em.persist(new Member("teamC")); + + List result = queryFactory + .select(member, team) + .from(member) + .leftJoin(team).on(member.username.eq(team.name)) + .fetch(); + + for (Tuple tuple : result) { + System.out.println("tuple = " + tuple); + } + } + + @PersistenceUnit + EntityManagerFactory emf; + + @Test + void fetchJoinNo() { + em.flush(); + em.clear(); + + Member findMember = queryFactory + .selectFrom(member) + .where(member.username.eq("member1")) + .fetchOne(); + + boolean loaded = emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam()); + + assertThat(loaded).as("페치 조인 미적용").isFalse(); + } + + @Test + void fetchJoin() { + em.flush(); + em.clear(); + + Member findMember = queryFactory + .selectFrom(member) + .join(member.team, team).fetchJoin() + .where(member.username.eq("member1")) + .fetchOne(); + + boolean loaded = emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam()); + + assertThat(loaded).as("페치 조인 적용").isTrue(); + } + + /** + * 나이가 가장 많은 회원 조회 + */ + @Test + void subQuery() { + + QMember memberSub = new QMember("memberSub"); + + List result = queryFactory + .selectFrom(member) + .where(member.age.eq( + select(memberSub.age.max()) + .from(memberSub) + )) + .fetch(); + + assertThat(result).extracting("age") + .containsExactly(40); + } + + /** + * 나이가 평균 이상인 회원 조회 + */ + @Test + void subQueryGoe() { + + QMember memberSub = new QMember("memberSub"); + + List result = queryFactory + .selectFrom(member) + .where(member.age.goe( + select(memberSub.age.avg()) + .from(memberSub) + )) + .fetch(); + + assertThat(result).extracting("age") + .containsExactly(30, 40); + } + + @Test + void subQueryIn() { + + QMember memberSub = new QMember("memberSub"); + + List result = queryFactory + .selectFrom(member) + .where(member.age.in( + select(memberSub.age) + .from(memberSub) + .where(memberSub.age.gt(10)) + )) + .fetch(); + + assertThat(result).extracting("age") + .containsExactly(20, 30, 40); + } + + @Test + void selectSubQuery() { + QMember memberSub = new QMember("memberSub"); + + List result = queryFactory + .select(member.username, + select(memberSub.age.avg()) + .from(memberSub)) + .from(member) + .fetch(); + + for (Tuple tuple : result) { + System.out.println("tuple = " + tuple); + } + } + + @Test + void basicCase() { + List result = queryFactory + .select(member.age + .when(10).then("열살") + .when(20).then("스무살") + .otherwise("기타")) + .from(member) + .fetch(); + + for (String s : result) { + System.out.println("s = " + s); + } + } + + @Test + void complexCase() { + List 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 + void constant() { + List result = queryFactory + .select(member.username, Expressions.constant("A")) + .from(member) + .fetch(); + + for (Tuple tuple : result) { + System.out.println("tuple = " + tuple); + } + } + + @Test + void concat() { + // {username}_{age} + List result = queryFactory + .select(member.username.concat("_").concat(member.age.stringValue())) + .from(member) + .where(member.username.eq("member1")) + .fetch(); + + for (String s : result) { + System.out.println("s = " + s); + } + } }