[240313]-LEFTJOIN 중복

XingXi·2024년 3월 12일
0

기록

목록 보기
18/33

문제 발생

@SpringBootTest
@Transactional
class LoginServiceImplTest { 
	...
    
    @BeforeEach
    void createUser(){
		chatMessageRepository.deleteAll();
        
        // CREATE USER
        CreateChatUserDto createChatUserDto = new CreateChatUserDto();
        createChatUserDto.setPw("test1");
        createChatUserDto.setNick("test1");
        createChatUserDto.setEmail("test1");

        CreateChatUserDto createChatUserDto2 = new CreateChatUserDto();
        createChatUserDto2.setPw("test2");
        createChatUserDto2.setNick("test2");
        createChatUserDto2.setEmail("test2");
        userTest1 = chatUserService.createChatUser(createChatUserDto);
        userTest2 = chatUserService.createChatUser(createChatUserDto2);

        //CREATE CHATROOM
        List<String> userPidList = new ArrayList<>();
        userPidList.add("test1");
        userPidList.add("test2");

        CreateChatRoomDto createChatRoomDto = new CreateChatRoomDto();
        createChatRoomDto.setUserNickList(userPidList);

        roomId = chatRoomService.createChatRoom(createChatRoomDto);

        // CREATE CHATTING

        for(int i = 0; i<10 ; i++){
            chatMessageRepository.save(ChatMessage.builder()
                                                .roomId(roomId)
                                                .msg(i+"TEST MESSAGE")
                                                .msgOwnerId(userTest1)
                                                .msgSendingTime(LocalDateTime.now())
                                                .msgSendingTimeL(System.currentTimeMillis())
                                                .build());
        }


        chatUserEntityRepository.getRoomIdCheckingDtoListByUserPid(userTest1)
                .forEach(roomIdCheckingCntDto -> {
                    System.out.println("roomIdCheckingCntDto.getRoomId() : "+roomIdCheckingCntDto.getRoomId());
                    System.out.println("roomIdCheckingCntDto.getCheckingMessageCnt() : "+roomIdCheckingCntDto.getCheckingMessageCnt());
                });

    }

현재 채팅 Application 을 만들고 있다. 위의 코드는
로그인을 하면 사용자의 채팅방 PID 와 채팅방 로딩을 위한 데이터를 가지고 오는데.. 다음과 같은 결과를 가진다.

roomIdCheckingCntDto.getRoomId() : 6f7e423f-5ca3-459f-ab54-b23039d750f9
roomIdCheckingCntDto.getCheckingMessageCnt() : 0
roomIdCheckingCntDto.getRoomId() : 6f7e423f-5ca3-459f-ab54-b23039d750f9
roomIdCheckingCntDto.getCheckingMessageCnt() : 0

@BeforeEach 안의 chatMessageRepository.deleteAll(); 로 인해 mongodb 의 record 가 모두 삭제 되고, Transactional 를 사용하여 RDB 또한 초기화를 하고 Test가 진행되는데 같은 데이터가 중복해서 나타난다.

원인

    @Override
    public List<RoomIdCheckingCntDto> getRoomIdCheckingDtoListByUserPid(String pid) {
        return
                queryFactory.select(
                        Projections.bean(RoomIdCheckingCntDto.class,
                                chatRoomEntity.pid.as("roomId"),
                                chatWithUserEntity.checkingMessageCnt.as("checkingMessageCnt")
                        )
                  ).from(chatRoomEntity)
                        .leftJoin(chatWithUserEntity).on(chatWithUserEntity.chatRoomEntity.eq(chatRoomEntity))
                        .leftJoin(chatUserEntity).on(chatUserEntity.pid.eq(pid))
                        .fetch();
    }

querydsl 을 사용하여 데이터를 가져올 때 leftJoin 을 사용하여 중복된 데이터가 반환되었다. 원인은 ChatRoomEntity 를 기준으로 leftJoin 을 했기 때문이다. chatRoomEntity 기준으로 데이터를 가져온다.
이후 chatWithUserEntity 와 조인한다. user test1 과 test2 의 roomPid 가 같기 때문에 chatRoomEntity 레코드가 2개가 생성이된다.
이후 chatUserEntity 의 pid 를 특정화 해서 조회하기 때문에 이미 2개의 레코드가 생성되었기 때문에 2개가 조회가 된다.

해결 방법

    @Override
    public List<RoomIdCheckingCntDto> getRoomIdCheckingDtoListByUserPid(String pid) {
        return
                queryFactory.select(
                        Projections.bean(RoomIdCheckingCntDto.class,
                                chatRoomEntity.pid.as("roomId"),
                                chatWithUserEntity.checkingMessageCnt.as("checkingMessageCnt")
                        )
                  ).from(chatUserEntity)
                        .leftJoin(chatWithUserEntity).on(chatUserEntity.eq(chatWithUserEntity.chatUserEntity))
                        .leftJoin(chatRoomEntity).on(chatWithUserEntity.chatRoomEntity.eq(chatRoomEntity))
                        .where(chatUserEntity.pid.eq(pid))
                        .fetch();
    }

맨처음 ChatUserEntity를 바탕으로 JOIN 을 했고

roomIdCheckingCntDto.getRoomId() : 6d2c92da-710d-4d60-839e-1339125a7e81
roomIdCheckingCntDto.getCheckingMessageCnt() : 0

다음과 같이 정상적으로 조회되는것을 볼 수 있다.

배운것!

처음에 중복된 데이터가 나와서 DISTINCT 를 사용하다가, 원인이 아닌 것 같아서 순서를 바꿔 보았다. leftJoin 에 대해 많이 미숙한 내 자신을 보게 되었고 leftJoin에 대해서 공부하게 되었다.

0개의 댓글