1. 심플한 테이블 디자인
요구 사항 분석
- 회원은 상품을 주문할 수 있습니다.
- 주문 시 여러 제품 유형을 선택할 수 있습니다.
도메인 모델 분석
- 회원과 주문 간의 관계: 회원은 여러 주문을 할 수 있습니다(일대다).
- 주문과 상품의 연결 : 하나의 주문으로 여러 상품을 선택할 수 있습니다. 반대로 동일한 상품을 여러 번 주문할 수도 있습니다. 다대다 관계를 일대다 관계로 변환하기 위해 주문한 제품이라는 모델을 만듭니다.

@Entity
public class Member {
@Id @GeneratedValue //생략하면 AUTO
@Column(name = "MEMBER_ID")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
//Getter,Setter 생략
}
@Entity
@Table(name = "ORDERS")
public class Order {
@Id @GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@Column(name = "MEMBER_ID")
private Long memberId;
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
//Getter,Setter 생략
}
public enum OrderStatus {
ORDER, CANCEL
}
@Entity
public class Item {
@Id @GeneratedValue
@Column(name= "ITEM_ID")
private Long id;
private String name;
private int price;
private int stockQuantity;
//Getter,Setter 생략
}
@Entity
public class OrderItem {
@Id @GeneratedValue
@Column(name= "ORDER_ITEM_ID")
private Long id;
@Column(name = "ORDER_ID")
private Long orderId;
@Column(name = "ITEM_ID")
private Long itemId;
private int orderPrice;
private int count;
//Getter,Setter 생략
}
테이블 중심 디자인의 문제 = 파트너십을 만들 수 없습니다.
- 위의 방법은 오브젝트 디자인을 테이블 디자인에 매칭 -> 외래키로 조인하여 관련 테이블을 찾아야 합니다.
- 반면 객체는 참조를 사용하여 관련 객체를 찾습니다. 테이블의 중앙은 개체 그래프를 검색할 수 없습니다.
- 참조가 없기 때문에 UML도 유효하지 않습니다.
2. 단방향 연결
@Entity
public class Member {
@Id @GeneratedValue //생략하면 AUTO
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
//Getter , Setter 생략
}
구성원(다수) 또는 팀(하나)이므로 구성원 클래스를 기준으로 ManyToOne을 사용합니다.
이렇게 하면 구성원과 일치하는 팀을 검색할 때 팀 ID를 검색할 필요 없이 바로 해당 팀을 검색할 수 있습니다.
//저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Mamner member = new Member();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);
//위의 식으로는 쿼리가 안나감
// em.persist로 영속성컨텍스트에서 서상하고 아래 find를 실행하면 1차쿼리에서 찾기때문
//확실하게 db내용을 확인하고싶다면
//em.flush();
//em.clear();
Member findMember = em.find(Memner.class, member.getId());
Team findTeam = findMember.getTeam();//getTeam으로 바로 찾기가능
System.out.println("findTeam = "+findTeam.getName());
tx.commit();
또한 관계에 있을 때 쉽게 변경할 수 있습니다.
//새로운 팀B
Team teamB = new Team();
teamB.setUsername("TeamB");
em.persist(teamB);
//회원1에 새로운 팀 B 설정
member.setTeam(teamB);
3. 양방향 관계 및 관계의 소유자

여기서 테이블과 관련하여 외래 키를 사용하여 구성원 테이블에서 팀을 가져오거나 팀 테이블에서 구성원을 가져올 수 있습니다. 즉, 테이블 연결은 이미 양방향 관계입니다.
단, 오브젝트 링크에서는 구성원 테이블에서 팀을 호출할 수 있지만 팀에 구성원이 없기 때문에 팀 테이블에서 구성원을 호출할 수 없습니다.
이때 필요한 것이 양방향 매핑이다.
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
}
mappedBy는 연결할 개체의 변수 이름을 씁니다.
그리고 일반적으로 new ArrayList<>(); 그것을 초기화
이렇게 하면 팀원을 호출할 수도 있습니다.
//저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Mamner member = new Member();
member.setUsername("member1");
member.setTeam(team);
em.persist(member);
//db에서 값을 가져와야 하므로 아래식은 필수이다.
em.flush();
em.clear();
//양방향 호출
Member findMember = em.find(Memner.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();
for(Member m : members){
System.out.println("m = "+ m.getUsername());
}
Team findTeam = findMember.getTeam();//getTeam으로 바로 찾기가능
System.out.println("findTeam = "+findTeam.getName());
tx.commit();
지도의 소유자와 mappedBy
- 개체의 양방향 관계는 실제로 양방향 관계가 아니라 두 가지 다른 단방향 관계입니다.
- 객체를 양방향으로 참조하려면 두 개의 단방향 연결을 만들어야 합니다.
- A -> B (a.getB())
- B -> A (b.getA())
- 반면 테이블은 단일 외래 키로 두 테이블 간의 관계를 관리합니다.
- SELECT * JOIN MEMBER M TEAM T T ON M.TEAM_ID = T.TEAM_ID
- SELECT * TEAM T JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
따라서 개체의 외래 키를 업데이트하려면 어떤 개체에서 업데이트해야 합니까?
=> 둘 중 하나만 외래 키를 관리해야 합니다. => 관계의 소유자
(양방향 매핑 규칙)
- 개체의 두 관계 중 하나를 연결 소유자로 지정합니다.
- 협회의 소유자만이 외래키를 관리(등록, 변경)할 수 있습니다.
- 비소유자에 의해 할당 페이지) 읽기(검색)만 가능합니다.
- 소유자는 mappedBy 속성을 사용하면 안 됩니다.
- 소유자가 아닌 경우 mappedBy 속성으로 소유자를 지정합니다.
누가 이것을 소유하고 있습니까?
- 외래 키를 호스트로 설정해야 합니다.
- 무조건적인 다대일 대 다목적 테이블
- 예) Member 및 Crew 테이블의 경우 구성원이 소유자여야 하며 Cars 및 Wheels 테이블의 경우 Wheel 테이블이 소유자여야 합니다.
