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]]
다음 할거는 이 데이터들을 어떻게 가져올 것이냐 문제다.
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 = [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.UserQb24hjmy["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
}
]