diff --git a/querydsl/db.mv.db b/querydsl/db.mv.db index 80a93da0..5b557e6c 100644 Binary files a/querydsl/db.mv.db and b/querydsl/db.mv.db differ 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); + } + } }