@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에 대해서 공부하게 되었다.