단방향

양방향

Team의 List members는 단지 조회를 위한 참조단방향

일(1)이 주인
다(N)에 외래키가 들어간다.
객체와 테이블 차이로 반대편 테이블의 외래 키를 관리하는 특이 구조
@JoinColumn을 꼭 사용해야 함. 그렇지 않으면 조인 테이블 방식을 사용함(중간에 테이블을 하나 추가함)
Team
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "team_id")
private List<Member> members = new ArrayList<>();
}
JpaMain
try {
Member member = new Member();
member.setUsername("member1");
em.persist(member);
Team team = new Team();
team.setName("teamA");
/**
* 뭔가 이상?
* Team 엔티티에 관해서 수정(.add())을 요청했지만
* 결국에 update query는 Member에서 발생한다.
* 문제점
* 1) 성능상 약간의 손해
* 2) (critical) 코드 상, A Entity를 손 봤는데 쿼리를 확인해보니 B Entity가 수정되었다.
* 코드가 무수히 많고 서비스가 무수히 많은 실무에서는 헷갈리기 일수.
*/
team.getMembers().add(member);
em.persist(team);
tx.commit();
}
정리
양방향

공식적으로 존재 x
Member
@OneToMany
@JoinColumn(insertable = false, updatable = false)
private Team team;
//읽기 전용
//근데 만들지 말자
//다대일 양방향 사용 지향
일대일 관계는 반대도 일대일
주 테이블이나 대상 테이블 중에 외래 키 선택 가능
💋외래키에 DB 유니크(UNI) 제약조건 추가
4가지 일대일 상황
1) 주 테이블에 외래 키 단방향

다대일 단방향과 유사
멤버
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
@Column(name = "username")
private String username;
@OneToOne
@JoinColumn(name = "locker_id")
private Locker locker;
}
락커
@Entity
public class Locker {
@Id
@GeneratedValue
@Column(name="locker_id")
private Long id;
private String name;
}
2) 주 테이블에 외래 키 양방향

다대일 양방향과 유사(외래키가 있는 객체가 연관관계 주인)
반대편 → mappedBy
멤버는 단방향 그대로, 락커만 변경
@Entity
public class Locker {
@Id
@GeneratedValue
@Column(name="locker_id")
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
}
3) 대상 테이블에 외래 키 단방향

4) 대상 테이블에 외래 키 양방향

예를 들어,, 미래에
정리
실무에서 웬만하면 안 쓴다.
관계형 DB는 정규화된 테이블 2개로 다대다 관계를 정의할 수 없다.
연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야함 (테이블)

객체는 가능

구성
@ManyToMany
@JoinTable
단방향, 양방향 가능
단방향
멤버
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
@Column(name = "username")
private String username;
@ManyToMany
@JoinTable(name = "memeber_product")
private List<Product> products = new ArrayList<>();
}
생산품
@Entity
public class Product {
@Id
@GeneratedValue
@Column(name = "product_id")
private Long id;
private String name;
}
양방향
생상품 (멤버는 그대로)
@Entity
public class Product {
@Id
@GeneratedValue
@Column(name = "product_id")
private Long id;
private String name;
@ManyToMany(mappedBy = "products")
private List<Member> members = new ArrayList<>();
}
한계
연결 테이블이 단순히 연결만 하는게 아니다.
주문시간, 수량 같은 다른 데이터가 필요할 수 있다.

한계 극복
연결 테이블을 엔티티 추가
@ManyToMany → @OneToMany + @ManyToOne

멤버
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
@Column(name = "username")
private String username;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
멤버프로덕트(오더)
@Entity
@Table(name = "order")
public class MemberProduct {
@Id
@GeneratedValue
@Column(name = "order_id")
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
private int count;
private int price;
@Column(name="orderdate")
private LocalDateTime orderDateTime;
}
프로덕트
package hellojpa;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Product {
@Id
@GeneratedValue
@Column(name = "product_id")
private Long id;
private String name;
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
주문과 배송은 1:1(@OneToOne)
상품과 카테고리는 N:M(@ManyToMany)

ERD

엔티티 상세

회원
@Entity
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> orders = new ArrayList<>();
}
주문
@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;
@OneToOne
@JoinColumn(name = "delivery_id")
private Delivery delivery;
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
}
배송
@Entity
public class Delivery {
@Id
@GeneratedValue
@Column(name = "delivery_id")
private Long id;
private String city;
private String street;
private String zipcode;
@Enumerated(EnumType.STRING)
private DeliveryStaus deliveryStaus;
@OneToOne(mappedBy = "delivery")
private Order order;
}
주문 상품
@Entity
@Table(name = "order_item")
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long id;
private int orderPrice;
private int count;
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
}
상품
@Entity
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 List<CategoryItem> categoryItems = new ArrayList<>();
}
카테고리
@Entity
public class Category {
@Id
@GeneratedValue
@Column(name = "category_id")
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Category parent;
@OneToMany(mappedBy = "parent")
private List<Category> child = new ArrayList<>();
@OneToMany(mappedBy = "category")
private List<CategoryItem> categoryItems = new ArrayList<>();
}
카테고리_아이템
@Entity
@Table(name = "category_item")
public class CategoryItem {
@Id
@GeneratedValue
@Column(name = "category_item_id")
private Long id;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
}
N:M 관계는 1:N, N:1로
@ManyToMany는 제약정리
JoinColumn : 외래키 매핑시 사용

@ManyToOne : 다대일 관계 매핑

@OneToMany : 일대다 관계 매핑
