@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class Friend {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "from_member")
@JsonIgnore
private ClubMember fromMember;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "to_member")
@JsonIgnore
private ClubMember toMember;
@Enumerated(EnumType.STRING)
private FriendStatus status;
public void changeStatus(FriendStatus status){
this.status=status;
}
// getters and setters
}
현재 위에선 @ManyToOne 을 통해 객체를 직접 가져왔고, 만약 toMember, FromMember의 요소 중 하나가 필요하면, 해당 엔티티를 추가적으로 불러오는 Lazy Loading 수행 중이다.
위와 같이 구성한엔티티에서, 만약 fromMember와 toMember 의 id 가 파라미터로 들어오면, 해당하는 객체를 찾아서 Status( 친구관계) 를 반환해줘야 하는 명세가 있다고 생각해보자.
우선 fromMember, toMember 의 id를 기반으로 매칭되는 friend 객체를 찾아야한다.
Friend findFriend= friendRepository.findByFromMemberIdAndToMemberId(102L, 101L).orElse(null);
이후, 해당 객체의 Status를 바꿔야할 것이다.
findFreind.changeStatus(FriendType.FRIEND);
하지만, 위의 경우, 분명히 실제 Friend 테이블 내에 toMember의 id와 fromMember의 id가 FK 로써 존재함에도 불구하고, toMember, fromMember를 가져오기 위해 join을 수행한다.
Hibernate:
select friend0_.id as id1_4_, friend0_.from_member as from_mem3_4_, friend0_.status as status2_4_, friend0_.to_member as to_membe4_4_
from friend friend0_
left outer join club_member clubmember1_ on friend0_.from_member=clubmember1_.club_member_id
left outer join club_member clubmember2_ on friend0_.to_member=clubmember2_.club_member_id
where clubmember1_.club_member_id=? and clubmember2_.club_member_id=?
이는 연관관계를 걸어줄 때의 한계이다.
이해를 돕기 위해 간단한 에시를 들겠다.
만약 friend 엔티티 객체를 사용해서 toMember의 ID(P.K) 를 가져오기위해서 어떻게 해야할까?
friend.getToMember().getId(); 와 같이, 연관된 toMember 에서 id 값을 가져와야만한다.
(friend 엔티티의 필드에 toMember의 id에 대한 필드가 직접적으로 없기에, friend.getToMemberId()는 불가능하다!)
따라서, 실제로 테이블에 toMember의 P.K, fromMember의 P.K 가 존재함에도 불구하고, 해당 키값으로 실제 toMember, fromMember 객체를 가져오고, 거기서 P.K 를 가지고오는 기이한 일을 수행해야하는 것이다.
하지만 반대로 연관관계를 사용하지 않고, FK 만 필드로 지정해준다면, FK 를 사용하는 것은 그저 자신의 필드명을 가져오는 것으로 처리하면 되기에, Join 이 필요 없다
따라서, 위의 명세가 전부이고, 해당 테이블에서 어떠한 기능을 수행할 때,
Member 들에 대해 추가적인 정보가 "전혀" 필요 없다면, 굳이 위와 같이 연관관계를 맺지 않고, toMember, fromMember의 PK 를
FK로써 각각 두는 것이 좋다.
하지만, 만약
frined.toMember.getName()
와 같이, friend 를 통해 toMember, fromMember의 정보들을 가져와야할 경우(대부분 그렇다...), 연관관계를 만들어서 처리하는 것이 여러모로 용이하고, 객체지향적인 설계이다. 따라서 대부분은 그냥 연관관계를 사용하면 된다.
'Spring boot' 카테고리의 다른 글
[Spring boot] 트랜잭션 설정 (0) | 2023.04.28 |
---|---|
[query Optimization] 캐싱 (Caching) (0) | 2023.04.26 |
[query Optimization] LAZY 로딩과 N+1 문제 (0) | 2023.04.26 |
[walk-talk] 걸음 수 기반 채팅 어플 데모 영상 (0) | 2023.04.11 |
스프링 시큐리티 정리 (0) | 2023.04.07 |