JAVA, JPA 공부 중

그래서 코드로 보면 아래와 같다.
// Member
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME") private String name;
private int age;
@ManyToOne
@JoinColumn(name = "TEAM_ID") private Team team; //mappedBy의 주인공
}
// Team
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
}
@OneToMany의 속성인 mappedBy는 반대편 객체(테이블)에는 어떤게 매칭이 되어있는가를 표시한 것.
위와 같이 한다면 team에서 member를 조회할 수 있고, member.getTeam().getMember() 와 같이 객체간의 양방향 접근 코드도 가능해진다.
이때 등장한 것이 연관관계의 주인이라는 개념.
어라?!
member의 team을 업뎃해서 테이블의 team_id를 업뎃해야하는지, team의 members를 업뎃해서 테이블의 team_id를 업뎃해야하는지 헷갈림.
➡️ 둘 중 하나만으로 외래키를 관리를 하자고 정함 : 연관관계의 주인의 등장
순수 객체 상태를 고려해서 항상 양쪽에 값을 설정해야한다.
연관관계 편의 메소드를 생성해서 사용
public class Member {
@ManyToOne
@JoinColumn(name= "TEAM_ID")
private Team team;
//연관관계 편의 메소드
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
}
//혹은
public class Team {
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
public void addMember(Member member) {
member.setTeam(this);
members.add(member);
}
}
//둘이 같이 쓰진 않고, 한 개만 골라서 쓰도록 해야한다.

위와 같은 구조를 가진 엔티티를 아래와 같이 만들어봄. 양방향 관계는 굳이 처음부터 만들 필요는 없고, 우선 단방향(1:N관계에서 N테이블에만 명시)만 우선 설정하고, 개발을 하면서 필요하면 양방향으로 추가로 관계를 설정해줘도 된다고 한다.
1:N 하면 무조건 양측에 코드를 넣어줘야한다고 생각이 들었는데 실무에서는 필요없는건 과감히 삭제한다는 말을 들었다.
package jpabook.jpashop.domain;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "MEMBER")
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
@OneToMany(mappedBy = "member")
private List<Order> order = new ArrayList<>();
}
// getter, setter 생략
package jpabook.jpashop.domain;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
}
// getter, setter 생략
package jpabook.jpashop.domain;
import jakarta.persistence.*;
@Entity
@Table(name = "ORDER_ITEM")
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "ORDER_ITEM_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "ITEM_ID")
private Item item;
@ManyToOne
@JoinColumn(name = "ORDER_ID")
private Order order;
private int orderPrice;
private int count;
}
// getter, setter 생략
package jpabook.jpashop.domain;
import jakarta.persistence.*;
@Entity
@Table(name = "ITEM")
public class Item {
@Id
@GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
// @OneToMany(mappedBy = "item")
// private OrderItem orderItem;
}
// getter, setter 생략
package jpabook.jpashop.domain;
public enum OrderStatus {
PENDING, ORDER, CANCEL
}


일대다 중 '일'의 입장에 연관관계의 주인이 있다는 가정
단방향
- 권장X. Team에 members가 있고, 변경 시 member테이블을 수정을 해줘야함.

- 테이블 일대다 관계는 항상 다 쪽에 외래 키가 있음
- 객체와 테이블 차이 때문에 반대편 테이블의 외래 키를 관리하는 특이한 구조
- @JoinColumn을 꼭 사용해야함. 그렇지 않으면 조인 테이블 방식을 사용함(중간에 테이블을 하나 추가됨)
- 단점 : 엔티티가 관리하는 외래 키가 다른 테이블에 있고, 추가로 update문이 실행됨
➡️ 일대다 단방향 매핑보다 다대일 양방향 매핑을 사용하자
양방향

- 공식적으로 존재하는건 아님
- @JoinColumn(insertable = false, updatable = false)을 넣으면 됨
- 읽기 전용 필드를 사용해서 양방향처럼 사용하는 방법
➡️ 다대일 양방향을 사용하는게 낫다

