Tuple 데이터값 꺼내기

강낭콩·2023년 7월 4일

JPA 쿼리 문제

JPA를 이용해서 Custom으로 getBoard에서 bno에 해당하는 게시물 + 댓글 값을 가져오려고 한다. 근데 결과가 한개 밖에 나오지 않는다

List<Tuple> fetch = from(board)
                .select(board, reply, reply.count())
                .leftJoin(reply).on(reply.board.eq(board))
                .where(board.bno.eq(bno))
                .groupBy(board)
                .fetch();
        System.out.println("fetch = " + fetch);

아래처럼 원래 board가 한개 Reply은 3개가 나와야 한다. 근데 한개 나오고 카운트가 3개가 나온다

fetch = [[Board(bno=3, title=title...3, content=content...3), Reply(rno=8, content=content...8, replyer=강낭콩8, writeReplyDate=2023-07-03T00:00), 3]]

해결 : reply.count()를 지우니까 잘 나온다. size는 결과 나온 fetch.size()로 하니 3으로 나와서 이걸로 대체


다음 할거는 이 데이터들을 어떻게 가져올 것이냐 문제다.
Board가 연속 3번 같은 데이터로 나오고 댓글도 3개가 나온다.

fetch = [[Board(bno=3, title=title...3, content=content...3), Reply(rno=8, content=content...8, replyer=강낭콩8, writeReplyDate=2023-07-03T00:00)], [Board(bno=3, title=title...3, content=content...3), Reply(rno=49, content=content...49, replyer=강낭콩49, writeReplyDate=2023-07-03T00:00)], [Board(bno=3, title=title...3, content=content...3), Reply(rno=61, content=content...61, replyer=강낭콩61, writeReplyDate=2023-07-03T00:00)]]

해결 : get을 이용해서 맨처음 board는 그냥 빼고 reply은 for문을 통해서 size를 알았으니 하나씩 빼서 돌려준다.

List<Object> list = new ArrayList<Object>();
        list.add(fetch.get(0).get(board));
        for (int i = 0; i < fetch.size(); i++) {
            list.add(fetch.get(i).get(reply));
        }

list결과

list = [Board(bno=3, title=title...3, content=content...3), Reply(rno=8, content=content...8, replyer=강낭콩8, writeReplyDate=2023-07-03T00:00), Reply(rno=49, content=content...49, replyer=강낭콩49, writeReplyDate=2023-07-03T00:00), Reply(rno=61, content=content...61, replyer=강낭콩61, writeReplyDate=2023-07-03T00:00)]

이제 완성하고 View로 데이터를 전송 하려고 하는데 문제가 발생 했다.
jackson이 변환을 못 시켜주는 것 같다. @ManyToOne같은걸 사용하면 변환하지 못하는 모양이다.
다시 보니 Entity를 그냥 보내줘서 DTO로 전환 후 반환해야 겠다.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.exam.mix.entity.board.Board["writer"]->com.exam.mix.entity.user.UserHibernateProxyHibernateProxyQb24hjmy["hibernateLazyInitializer"])

도전 : list를 만들면서 DTO로 변환해서 넣어보려고 했는데 실패
list.add(fetch.get(0).get(Board.build.board.getbno())); 처럼 하려고했는데 board에서 값이 안나온다.

도전2 : list에서 꺼내서 다시 만들기를 하다가 문뜩 생각이 난다. for문으로 800개의 댓글이 오면 for문을 2번이상 쓸것인가?

도전3 :

일단 문제는 FetchType으로 Lazy를 걸어놓으면 @ManyToOne있는 필드에 접근할때 오류가 발생한다. 그래서 아래 어노테이션을 사용하는 클래스에 붙여놓으니 잘 작동이 된다.

  • @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    근데 결과가 이상하게 나온다. board타입이여서 bno만 나올줄 알았는데 전체 데이터가 나와서
[
   {
       "regDate": "2023-06-29T15:08:32.234067",
       "modDate": "2023-06-29T15:08:32.234067",
       "bno": 3,
       "title": "title...3",
       "content": "content...3",
       "writer": {
           "uid": 3,
           "hakbun": "3... @naver.com",
           "password": "13",
           "nickname": "강낭콩3",
           "createdDate": "2023-06-28T11:21:18.14682"
       }
   },
   {
       "rno": 8,
       "content": "content...8",
       "replyer": "강낭콩8",
       "board": {
           "regDate": "2023-06-29T15:08:32.234067",
           "modDate": "2023-06-29T15:08:32.234067",
           "bno": 3,
           "title": "title...3",
           "content": "content...3",
           "writer": {
               "uid": 3,
               "hakbun": "3... @naver.com",
               "password": "13",
               "nickname": "강낭콩3",
               "createdDate": "2023-06-28T11:21:18.14682"
           }
       },
       "writeReplyDate": "2023-07-03T00:00:00"
   },
   {
       "rno": 49,
       "content": "content...49",
       "replyer": "강낭콩49",
       "board": {
           "regDate": "2023-06-29T15:08:32.234067",
           "modDate": "2023-06-29T15:08:32.234067",
           "bno": 3,
           "title": "title...3",
           "content": "content...3",
           "writer": {
               "uid": 3,
               "hakbun": "3... @naver.com",
               "password": "13",
               "nickname": "강낭콩3",
               "createdDate": "2023-06-28T11:21:18.14682"
           }
       },
       "writeReplyDate": "2023-07-03T00:00:00"
   },
   {
       "rno": 61,
       "content": "content...61",
       "replyer": "강낭콩61",
       "board": {
           "regDate": "2023-06-29T15:08:32.234067",
           "modDate": "2023-06-29T15:08:32.234067",
           "bno": 3,
           "title": "title...3",
           "content": "content...3",
           "writer": {
               "uid": 3,
               "hakbun": "3... @naver.com",
               "password": "13",
               "nickname": "강낭콩3",
               "createdDate": "2023-06-28T11:21:18.14682"
           }
       },
       "writeReplyDate": "2023-07-03T00:00:00"
   }
]

해결

전에 list.add(fetch.get(0).get(board.getbno())); 여기서 board.하면 안나온다 했는데 그 괄호 밖에서 list.add(fetch.get(0).get(board).getbno()); 하니 잘된다.. build로 설정해보자.
Entity 타입의 데이터로 하면 위에처럼 나왔는데 DTO로 빌드 후 하니까 잘 나온다.

//쿼리 보내고 나온 결과 Tuple<List>를 하나씩 꺼내서 DTO로 변환후 List<Object>로 변환 후 반환
    private List<Object> TupleToList(List<Tuple> fetch) {
        QBoard board = QBoard.board;
        QReply reply = QReply.reply;

        List<Object> list = new ArrayList<Object>();
        list.add(BoardDTO.builder()
                .bno(fetch.get(0).get(board).getBno())
                .title(fetch.get(0).get(board).getTitle())
                .content(fetch.get(0).get(board).getContent())
                .writer(fetch.get(0).get(board).getWriter().getNickname())
                .replyCount(fetch.size())
                .regDate(fetch.get(0).get(board).getRegDate())
                .modDate(fetch.get(0).get(board).getModDate())
                .build()
        );
        for (int i = 0; i < fetch.size(); i++) {
            list.add(ReplyDTO.builder()
                    .rno(fetch.get(i).get(reply).getRno())
                    .content(fetch.get(i).get(reply).getContent())
                    .replyer(fetch.get(i).get(reply).getReplyer())
                    .writeReplyDate(fetch.get(i).get(reply).getWriteReplyDate())
                    .bno(fetch.get(i).get(reply).getBoard().getBno())
                    .build()
            );
        }

        System.out.println("list = " + list);

        return list;
    }

결과

[
    {
        "bno": 3,
        "title": "title...3",
        "content": "content...3",
        "writer": "강낭콩3",
        "replyCount": 3,
        "regDate": "2023-06-29T15:08:32.234067",
        "modDate": "2023-06-29T15:08:32.234067"
    },
    {
        "rno": 8,
        "replyer": "강낭콩8",
        "content": "content...8",
        "writeReplyDate": "2023-07-03T00:00:00",
        "bno": 3
    },
    {
        "rno": 49,
        "replyer": "강낭콩49",
        "content": "content...49",
        "writeReplyDate": "2023-07-03T00:00:00",
        "bno": 3
    },
    {
        "rno": 61,
        "replyer": "강낭콩61",
        "content": "content...61",
        "writeReplyDate": "2023-07-03T00:00:00",
        "bno": 3
    }
]

0개의 댓글