객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다.
여기서 책 추천을 한다.
객체지향의 사실과 오해(조영호)
오브젝트(조영호)
중요한 말은 우리가 JPA를 배우고 있지만, 결국 핵심은 객체지향적 설계이다.
객체지향이라는 근본적인 것이 어렵다. 이를 위해 위 책을 읽으면 어느정도 객체지향이 무엇인지 알게 되고 설계하는데 도움이 될 것이라는 뜻.
객체지향적이라는게 뭔지 알고 객체지향적으로 코드를 짜고 싶다면, ORM에 손이 가게 된다고 한다.
대충 팀과 멤버는 1:N의 관계라는 뜻.
잘 보면 그냥 TEAM_ID
를 참조하지 않고, 그냥 외래 키로 사용하는 것을 확인할 수 있다.
보면, Setter
를 통해 직접 TEAM_ID
를 주입시키는 것을 확인할 수 있다.
테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
객체는 참조를 사용해서 연관된 객체를 찾는다.
테이블과 객체 사이에는 이런 큰 간격이 있다.
객체 지향적이 아니다.
암튼 조회가 잘된다.
객체 지향적이다.
수정하면, 이후에 커밋시점에 더티체킹(변경감지)가 되어 수정할 수 있다.
이전과 다르게 양방향은 1:N에서 1 부분에 N을 추가해준다.
그래서 1인 Team에 N인 Member가 추가된 것을 확인할 수 있다.
그러면 양방향이 좋냐 단방향이 좋냐 로 나누자면,
단뱡향이 웬만하면 좋다. 양방향은 나중에 가면 복잡해진다. 이와 관련된건 뒤에서 설명.
즉, 객체에서는 회원에서 팀으로 가는 연관관계 1개
팀에서 회원으로 가는 연관관계 1개로 해서
양방향이라고 우기는 거다.
테이블은 그냥 연관관계가 양방향으로 1개이다.
class A {
B b;
}
class B {
A a;
}
이렇게 2개
SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
SELECT *
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
외래 키 하나로 두 테입르의 연관관계를 관리
MEMBER.TEAM_ID 외래키 하나로.
그러니까 둘 중 하나를 외래 키로 관리해야 한다.
여기서 연관관계의 주인이라는게 나온다.
양방향 매핑 규칙
진짜 매핑 - 주인
가짜 매핑 - 읽기만 가능
1 : N에서 1(Member)을 주인으로 정할수도 있다.
그런데 N(Team)을 그니까, Member에 있는 Team team을 주인으로 정하는 이유는, 여러가지가 있는데
먼저 자세히 이해하지는 못했는데 Team을 수정하는데, Member에 업데이터 쿼리가 나간다던지 여러 문제가 있기 때문에,
그냥 데이터베이스에서 FK를 가지는 곳을 주인으로 정한 것 같다.
쉽게 말해 N이 주인이다.
그러므로 주인이 아닌,
@oneToMany
에 mappedBy
를 넣으면 된다.
리스트는 무조건 읽기 전용이다.
읽기 전용에 값을 넣고 저장하려니 저장이 안된것이다.
이렇게 주인에 값을 설정하고 저장해야 한다.
프로젝트를 통해 많이 겪어본 것 같다.
그런데, 강사님이 정말 객체지향적으로 하기 위해서는
양쪽에 전부 값을 넣어주는 것이 맞다고 하신다.
문제는 어디서 생기냐면,
쉽게 말해 flush를 안한 상태에서 em.find
로 값을 가져오려고 하면,
1차 캐시에서 조회된 값이 그대로 오기 때문에 List
에 값이 없다.
즉, 데이터베이스에서 값을 가져오면 상관없는데,
커밋 전에 값을 꺼내오면 문제가 된다는 것.
근데 뭐 일반적으로
Transaction
을 통해 flush가 되기 때문에 어... 문제는 없을 것 같긴 하다.
강사님은 양쪽에 값을 둘다 넣기 위해서
연관관계 메서드를 생성하라라고 하신다.
연관관계 메서드란,
Member에서
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
이렇게 setTeam메서드에서 값을 주입시켜버리면, 팀을 세팅할때마다 자동으로 List에도 추가되니 문제될 것이 없다는 말씀이다.
Setter로 해도 되지만, 특별한 로직이 들어간다는 것을 보여주기 위해
changeTeam
으로 메서드를 생성하는 것이다.
오 맞말추
Team에서는 이렇게
public void addMember(Member member) {
member.setTeam(this);
members.add(member);
}
하는데 또, 양쪽에 만드는건 문제가 발생할 수 있으므로, Member에 있는걸 지우고, Team에 addMember
를 추가하는 방향으로 한다.
물론 Team에 있는걸 지우고 Member에 changeTeam
을 이용해도 된다.
유동적으로 하면 된다는 뜻
양방향 매핑시에 무한 루프를 조심
예: toString(), lombok, JSON 생성 라이브러리