PlayData 백엔드 부트캠프 정리

다시 시작하는 부트 캠프 하루 후기 6일차

효건 2024. 10. 31. 17:53

<JPAQuery>

    SELECT
        G.group_name
        I.gender,
        COUNT(I.idol_id)
    FROM tbl_idol I
    join tbl_group G
    GROUP BY I.gender, G.group_id
    HAVING COUNT(I.idol_id) <= 3;

이런 쿼리 문을 JPA로 만들게 되면 

List<Tuple> list = factory
        .select(idol.group, idol.gender, idol.count())
        .from(idol)
        .groupBy(idol.gender, idol.group)
        .having(idol.count().loe(3))
        .fetch();

// then
for (Tuple tuple : list) {
    Group group = tuple.get(idol.group);
    String gender = tuple.get(idol.gender);
    Long count = tuple.get(idol.count());

 

위와 같은 식으로 Tuple로 받아서 쓸수있다. 

새부 적으로 보면 selelct는 사실상 그대로 쓰는데 ()안에 기입해야 하면 from도 같고 다 같다. 그러나 having절이 조금 어렵기때문에 추가적인 공부가 불가피해 보인다. 또한 마지막에 fetch를 붙여야 작동함을 알수있다. 그리고 Tuple 방식으로 받기 때문에 iter문법을 사용하여 가져오는 것으로 해야한다. 

<subQuery>

 

SELECT G.group_name, AVG(I.age)
FROM tbl_idol I
JOIN tbl_group G
ON I.group_id = G.group_id
GROUP BY G.group_id
HAVING AVG(I.age) BETWEEN 20 AND 25

 

위와 같은 JOIN이 포함된 쿼리문은 아래와 같이 작성할수있다.

List<Idol> result = factory
        .select(idol)
        .from(idol)
        .where(idol.age.gt(
                JPAExpressions
                        .select(idol.age.avg())
                        .from(idol)
                        .where(idol.group.groupName.eq(groupName))
        ))
        .fetch();

 내부 로직에서 JPAExpressions를 이용하여 query도 중첩구문처럼 사용이 가능한것으로 이해하였다.

세부적으로 보면 다 같으나 where절에 JPAExpressions을 이용하여 다시 select문부터 중첩적으로 사용하는 것을 볼수있따. 안에 있는것이 innerjoin의 값임을 알수있다. 따라서 JPAExtenstion에 어떤것이 들어갈수있고 들어갈지 충분히 헷갈릴수있으므로 차분하게 볼필요가 있다.

 

for (GroupAverageAgeDto dto : result) {
    String groupName = dto.getGroupName();
    Double averageAge = dto.getAverageAge();

또한 Tuple 형식으로 정보가 오기 때문에 위와 같이 iter문을 이용하여 해석해서 확인할수있다.

위와 같은 형식을 편하게 쓰기위해서 SQL 공부를 게을리하지 않아야 할듯하다. 

 

<동적Query>

@Test
@DisplayName("")
void dynamicTest1 () {
    // given
    String name = "null";// -> 값이 전달되지 않았다고 가정하자.

    String gender = "null";

    //동적 쿼리를 위한 BooleanBuilder
    BooleanBuilder booleanBuilder = new BooleanBuilder();

    if (name!=null) {
        booleanBuilder.and(idol.idolName.eq(name));
    }
    if (gender!=null) {
        booleanBuilder.and(idol.gender.eq(gender));
    }

    // when
    List<Idol> result = factory
            .select(QIdol.idol)
            .where(booleanBuilder)
            .fetch();

    // then
            result.forEach(System.out::println);
}

위와 같이 JPA 쿼리문을 사용하게 되면 동적 쿼리라고 한다. 이렇게 사용하게 되면 값이 어떤것이 null일지라도 다른 방식으로 실행하도록 유도한다.

다시말해 함수를 포함시키는 개념인듯하다.

 

 

@Test
@DisplayName("")
void dynamivTest2() {
    // given
    String name = "null";// -> 값이 전달되지 않았다고 가정하자.

    String gender = "null";
    // when
    List<Idol> result = factory
            .select(QIdol.idol)
            .where(nameEq(name), genderEq(gender))
            .fetch();
    result.forEach(System.out::println);
}

private BooleanExpression nameEq(String nameParam) {
        return nameParam != null ? idol.idolName.eq(nameParam) : null;
}
private BooleanExpression genderEq(String genderParam) {
        return genderParam != null ? idol.gender.eq(genderParam) : null;
}

위방식도 동적JPA인데 전에 방식을 더 자세하게 쓰인다고 볼수있다.

BooleanExpression nameEq와 BooleanExpression nameEq의 함수를 보면 null이나오게 유도하는 것은 쿼리문을 없애고 실행하여 오류를 제거하기 위함이고 각각 파라미터값이 들어오면  정상적으로 실행되도록 하게됩니다,

@Test
@DisplayName("동적 정렬을 사용한 아이돌 조회")
void dynamicTest3() {
    // given
    String sortBy ="idolName" // 나이, 이름, 그룹명
    boolean asc = true; // 오름차 true, 내림차 false

    OrderSpecifier<?> specifier = null;
    //동적 정렬 조건 생성
    switch (sortBy){
        case "idolName":
            specifier = asc ? idol.idolName.asc() : idol.idolName.desc();
            break;
        case "gender":
                specifier = asc ? idol.gender.asc() : idol.gender.desc();
        case "age":
                specifier = asc ? idol.age.asc() : idol.age.desc();
    }

    // when
    factory
            .select(idol)
            .orderBy(specifier)
            .fetch();


    // then
}

위와 같은 식으로 응용이 가능하다. ㄹㅇ JAVA는 무궁무진한 방법으로 표현이 가능한것 같다. 

 

 

++추가++

스프링 초기 설정입니다!!!