이런 테이블 구조가 있을때, 나는 {room_id, title, black_user_name, white_user_name, status} 정보를 가져오고 싶었다.
그러나 room 테이블의 필드는 user_name이 아닌 user_id였기 때문에 user_name은 room 테이블의 black_user_id와 white_user_id를 통해 얻어와야 했다.
제일 처음에는 join 쿼리를 사용하여 한 번에 {room_id, title, black_user_name, white_user_name, status} 정보를 가져왔다.
그러나 위 그림을 보고 Controller 계층과 Service 계층 사이의 데이터 이동시에는 DTO를, Service 계층과 Repository 계층의 데이터 이동 시 도메인 모델을 사용하려고 했다.
하지만 여기서 이런 궁금증이 들었다.
Q. 서로 다른 테이블을 join해서 결과를 얻어내는 경우 테이블과 1:1 매칭되는 엔티티가 존재하지 않는데, 이 경우는 어떻게 데이터를 받아와야할까? 해당 쿼리와 매칭되는 모델을 만들면 결국 DTO와 똑같은 것이 아닌가?🤔
결국 DTO를 사용하지 않으려면 join을 사용하지 않고, DAO별로 쿼리를 나눠서 각 쿼리의 결과를 각각 엔티티로 받아온 다음, service 계층에서 여러 엔티티를 DTO로 변환해주는식으로 해야했다.
그런데 이렇게 join을 사용하지 않고 dao별로 쿼리를 나눠서 실행시키는 경우 db 요청이 많아지니까 join을 사용할때보다 상대적으로 느릴 수 있다.
크로플과 이 주제에 대해 이야기해보고 리뷰어님들께도 물어봤다.
Q. 서로 다른 테이블을 join해서 결과를 얻어내는 경우 테이블과 1:1 매칭되는 엔티티가 존재하지 않는데, 이 경우는 어떻게 값을 받아야하나 고민이 됐어요. 현재는 join을 사용하지 않고, DAO별로 쿼리를 나눠서 각 쿼리를 엔티티로 받은 다음 service단에서 DTO로 조합하는 식으로 변경했어요.
그런데 이렇게 join을 사용하지 않고 쿼리를 나눠서 실행시키는 경우 느리다고 판단되면 join의 결과로 나오는 필드를 가지고 있는 새로운 도메인을 만들어서 값을 받기도 한다고 하는데, 이 경우는 결국 DTO를 사용하는 것이라는 생각이 들더라고요. 서로 다른 테이블에서 값을 가져올 때 어떤 방식을 사용하시나요?? 또 join은 어느 경우에 사용해야할까요?
재연링의 답변
DAO는 Table Data Gateway로 테이블과 1:1로 존재하기 때문에 조인을 담당하는 클래스를 따로 만들어줄 것 같아요!
Repository에 조건은 부합하지 않지만.. 일단 Repository라는 이름으로 만들어서 해당 역할을 넘겨줄 것 같네요 ㅎㅎ
미립의 답변
질문하신 내용에 대해서는 여러가지 방법이 있는것 같아요.
1. JOIN 의 결과를 담는 객체를 만든다.
2. 한쪽 객체에 조인하는 객체의 정보를 포함한다.
3. 각각 조회해서 객체의 관계를 맺어준다.
각각의 쓰임새가 조금씩 달라서 어떤게 좋다 말씀드리긴 어렵고, 필요에 따라 잘 사용해야 겠지요 😱
제가 생각하는 DTO 랑 도메인의 궁극적인 차이점은 비지니스 로직의 존재라고 생각해요. 따라서 둘을 합쳐서 만든 데이터 셋이 비지니스 로직을 가지지 않는다면 에어가 말씀하신대로 DTO 라고 할 수 있겠죠.
조인은 말그대로 두 테이블을 함께 조회할 필요가 있을때 사용하는데, 요새는 조인하지 않고 각각 가져오는 경우도 많은 것 같아요.
단 1:1 이 아니라 1: N 의 경우 각각 가져오면 부하가 심하겠죠?
상황에 맞게 적용해보는게 가장 좋겠지만, 현재 시점(2021.05.08)의 생각은 일단은 join을 사용하지 말고, 쿼리를 나눠서 해보자
이다. 아직 성능 차이를 느껴보지 못한 것도 있고, DTO를 만드는 것 보다는 각각 엔티티로 처리하는게 더 일관성있다는 생각이 든다. 추후에 여러 경험이 쌓이면서 언제든지 바뀔 수 있다고 생각한다.