김영한 님의 '자바 ORM 표준 JPA 프로그래밍 - 기본편'를 듣고 적은 글 입니다.

Team의 식별자를 Member에서 직접적으로 다루게 된다. 이는 객체 지향적인 방법이 아니다.
객체를 테이블에 맞추어 데이터 중심으로 모델링하면 협력관계를 만들 수 없다.
테이블은 외래키로 조인을 사용해 연관된 테이블을 찾고 객체는 참조를 사용해 연관된 객체를 찾기에 테이블 관계에 맞춰 설계를 하게되면 이런 간극을 극복할 수 없다.

객체의 참조와 테이블의 외래키를 매핑한다.
이때 Member에서 Team 방향으로만 가능하며 Team에서 Member로 접근할 수 있는 방법은 없다.
//Member class
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne //멤버에선 여러명이고 팀은 하나
@JoinColumn(name = "TEAM_ID")
private Team team;

Member에서 Team을 지정할 수 있다. 이 관계를 단방향 연관관계라고 한다.
//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team); //단방향 연관관계 설정, 참조 저장
em.persist(member);
이때 참조를 사용해서 연관관계를 조회할 수 있다. Member 클래스에서 Team의 참조값을 저장하고 있기에 이를 통해 멤버가 소속된 팀도 조회할 수 있다.
//조회
Member findMember = em.find(Member.class, member.getId());
//영속성 컨텍스트 1차 캐시에서 값 꺼내오기에 쿼리가 나가지 않음
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();
연관관계가 없었을 때에는 멤버 따로, 팀 따로 조회했어야 했다.
//조회
Member findMember = em.find(Member.class, member.getId());
//연관관계가 없음
Team findTeam = em.find(Team.class, team.getId());
이런 방법은 객체지향적인 방법이 아니다!!

양방향 연관관계는 말 그대로 Member에서 Team클래스에 접근할 수 있고 Team 클래스에서도 Member 클래스에 접근할 수 있음을 뜻한다. 위와 다른 점이 있다면 Team에서 Member에 접근하기 위해 List<Member> member을 추가해줬다.
//Team class
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
위와 같은 코드를 추가해준다.
조회할 때에도 양방향 연관관계를 가지기에 Team에서 Member클래스에 접근해 역방향 조회가 가능하다.
//조회
Team findTeam = em.find(Team.class, team.getId());
int memberSize = findTeam.getMembers().size(); //역방향 조회
객체의 연관관계는 2개이다
Member -> Team (단방향)Team -> Member (단방향)테이블의 연관관계는 1개이다.
MEMBER <-> TEAM (양방향)그래서 객체의 연관관계 두개 중 하나로 외래키를 관리해야 한다.
객체의 두 관계 중 하나를 연관관계의 주인으로 지정해야 하며 연관관계의 주인만이 외래키를 등록하고 수정할 수 있다. 주인이 아닌 쪽은 조회만 가능하다.
즉, 주인이라면 mappedBy 속성을 사용할 수 없다.
이때 그럼 주인을 어떻게 정하는가 ??
외래키를 가지는 곳을 주인으로 지정하고 그 외래키를 기본키로 가지는 클래스에 mappedBy를 사용해주면 된다.

여기에선 Member에서 Team을 외래키로 가지고 있기에 Member 클래스를 연관관계의 주인으로 지정해준다. Team의 members는 조회만 가능하고 값을 입력할 순 없다.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
//역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
위의 코드를 보면 주인이 아닌 클래스에서 연관관계를 설정해주었기에 이때 TEAM_ID에는 NULL이 들어간다.
그렇기에 member.setTeam(team); 이와 같이 연관관계의 주인에 값을 입력해 NULL 값이 들어가지 않도록 한다.