연관관계 매핑
객체 연관관계 vs 테이블 연관관계
- 테이블은 외래키로 연관 관계를 맺는다.
create table member (id bigint not null, address varchar(255) not null, age integer not null, description varchar(255), name varchar(30) not null, nickName varchar(30) not null, primary key (id)) create table orders (id varchar(255) not null, memo clob, order_datetime TIMESTAMP, orderStatus varchar(255), member_id bigint, primary key (id)) ## 외래키를 통해 관계를 맺는다. alter table orders add constraint fk_order_member_id foreign key (member_id) references member
- 객체는 참조(주소)로 연관관계를 맺는다.
@Entity @Table(name = "orders") @Getter @Setter public class Order { @Id @Column(name = "id") private String uuid; @Column(name = "order_datetime", columnDefinition = "TIMESTAMP") private LocalDateTime orderDatetime; @Enumerated(EnumType.STRING) private OrderStatus orderStatus; @Lob private String memo; //private Long memberId; @ManyToOne private Member member; // 참조를 통해서 관계를 맺는다. }
핵심 키워드
- 방향 (단방향, 양방향)
- 회원 → 주문 또는 주문 → 회원 둘 중 한 쪽만 참조하는 것을 단방향 관계라고 한다.
- 회원 → 주문, 주문 → 회원 양쪽 모두 서로 참조하는 것을 양방향 관계라고 한다.
- 테이블에서의 관계는 항상 양방향이다.
class Member { private long id; private List<Order> orders; // 회원 -> 주문 } class Order { private String id; } Member member = new Member(); Order order = meber.getOrders().get(0); // 회원 -> 주문에 참조가 가능하다. order.getMember() // (X)
class Member { private long id; } class Order { private String id; private Member member; // 주문 -> 회원 } Order order = new Order(); Member member = order.getMember(); // 주문 -> 회원에 참조가 가능하다. member.getOrders() // (X)
class Member { private long id; private List<Order> orders; // 회원 -> 주문 } class Order { private String id; private Member member; // 주문 -> 회원 } Member member = new Member(); Order order = member.getOrders().get(0); // 회원 -> 주문 참조 (O) order.getMember(); // 주문 -> 회원 참조 (O)
SELECT * FROM member AS m JOIN orders AS o ON m.id = o.member_id; SELECT * FROM orders AS o JOIN member AS m ON o.member_id = m.id
- 다중성 (다대일, 일대다, 다대다)
- 회원은 여러 주문을 할 수 있기 때문에, 회원(1)과 주문(N)은 일대다 관계이다.
- 주문은 여러 회원에 의해 발생할 수 있기 때문에, 주문(N)과 회원(1)은 다대일 관계이다.
- 연관관계 주인 (mappedBy)
- 객체를 양방향 연관관계로 만들면, 연관관계의 주인을 정해야 한다.
- 외래키를 관리할 객체를 지정한다. (INSERT, UPDATE, DELETE)
- 연관관계 주인만이, 외래키를 등록 수정 삭제 할 수 있다. (주인이 아닌쪽은 읽기만 가능하다.)
- 테이블중 FK 가 있는 쪽이 연관관계 주인이 된다. (회원(1) - 주문(N) → 주문 엔티티가 연관관계의 주인이된다.)
객체 그래프 탐색
class Member { private long id; private List<Order> orders; } class Order { private String id; private Member member; } ... @Test void graph() { Member member1 = new Mebmer(1); Order order1 = new Order(1) member1.setOrders(Lists.newArrayList(order1)); Order findOrder= member1.getOrders().get(o); // 객체 그래프 탐색이라 한다. findOrder.getMember(); }
JPA 엔티티 객체 관계 매핑

회원(member) - 주문(orders) 단방향 연관관계 매핑
@Entity @Table(name = "member") @Getter @Setter public class Member { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; @Column(name = "name", nullable = false, length = 30) private String name; @Column(nullable = false, length = 30, unique = true) private String nickName; private int age; @Column(name = "address", nullable = false) private String address; @Column(name = "description", nullable = true) private String description; }
@Entity @Table(name = "orders") @Getter @Setter public class Order { @Id @Column(name = "id") private String uuid; @Column(name = "order_datetime", columnDefinition = "TIMESTAMP") private LocalDateTime orderDatetime; @Enumerated(EnumType.STRING) private OrderStatus orderStatus; @Lob private String memo; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", referencedColumnName = "id") private Member member; }
회원(member) - 주문(orders) 양방향 연관관계 매핑
@Entity @Table(name = "member") @Getter @Setter public class Member { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; @Column(name = "name", nullable = false, length = 30) private String name; @Column(nullable = false, length = 30, unique = true) private String nickName; private int age; @Column(name = "address", nullable = false) private String address; @Column(name = "description", nullable = true) private String description; @OneToMany(mappedBy = "member") // 연관관계 주인은 order.member private List<Order> orders; // 연관관계 편의 메소드 public void addOrder(Order order) { order.setMember(this); } }
@Entity @Table(name = "orders") @Getter @Setter public class Order { @Id @Column(name = "id") private String uuid; @Column(name = "order_datetime", columnDefinition = "TIMESTAMP") private LocalDateTime orderDatetime; @Enumerated(EnumType.STRING) private OrderStatus orderStatus; @Lob private String memo; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", referencedColumnName = "id") private Member member; // 연관관계 편의 메소드 public void setMember(Member member) { if(Objects.nonNull(this.member)) { this.member.getOrders().remove(this); } this.member = member; member.getOrders().add(this); } }
과제
order, order_item, item 의 연관관계 매핑을 실습해본다.