2023. 02.07 14:30 복습 시작
일대일 [ 1: 1 ]
일대일 관계는 아래와 같은 특징이 있다.
- 일대일 관계는 그 반대도 일대일 관계다.
- 테이블 관계에서 일대다, 다대일은 항상 다쪽이 외래 키를 가진다.
- 반면에 일대일 관계는 주 테이블이나 대상 테이블 둘 중 어느 곳이나 외래 키를 가질 수 있다.
주 테이블에 외래 키
- 주 객체가 대상 객체를 참조하는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 참조한다.
- 외래 키를 객체 참조와 비슷하게 사용할 수 있어서 객체지향 개발자들이 선호한다.
- 이 방법의 장점은 주 테이블이 외래 키를 가지고 있으므로 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.
대상 테이블에 외래 키
- 전통적인 데이터베이스 개발자들은 보통 대상 테이블에 외래 키를 두는 것을 선호한다.
- 이 방법의 장점은 테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.
주 테이블에 외래 키 - 단방향
아래는 일대일 관계 예시 코드다.
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
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;
}
다대일 단방향 매핑과 유사
주 테이블에 외래 키 - 양방향
아래는 예시 코드다.
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
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;
@OneTOOne(mappedBy = "locker")
private Member member;
}
이제 대상 테이블에 외래 키가 있는 일대일 관계를 알아보자.
대상 테이블에 외래 키 - 단방향
일대일 관계 중 대상 테이블에 외래 키가 있는 단방향 관계는 JPA 지원하지 않는다.
그리고 이런 모양으로 매핑할 수 있는 방법도 없다.
이 때는 단방향 관계를 Locker에서 Member 방향으로 수정하거나, 양방향 관계로 만들고 Locker를 연관관계의 주인으로 설정해야 한다.
즉, 단방향은 지원하지 않고, 양방향을 지원한다.
대상 테이블에 외래 키 - 양방향
코드는 아래와 같다.
@Entity
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne(mappedBy = "member")
private Locker locker;
}
@Entity
public class Locker{
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
@OneTOOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
}
일대일 매핑에서 대상 테이블에 외래 키를 두고 싶으면 이렇게 양방향으로 매핑한다.
주 테이블에 외래 키가 있을 때 특징은 아래와 같다.
- 주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾는다.
- 객체지향 개발자들이 선호한다.
- JPA 매핑 편리
- 장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
- 단점 : 값이 없으면 외래 키에 null 허용
대상 테이블에 외래 키가 있을 때 특징은 아래와 같다.
- 대상 테이블에 외래 키가 존재
- 전통적인 데이터베이스 개발자 선호
- 장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
- 단점 : 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨.
다대다 [ M : N ]
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
그래서 보통 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다.
객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 기능을 구현한다.
다대다는 아래와 같은 특징을 가진다.
- @ManyTOMany
- @JoinTable로 연결 테이블 지정
- 다대다 매핑 : 단방향, 양방향 가능
@ManyToMany를 사용하면 연결 테이블을 자동으로 처리해주므로 도메인 모델이 단순해지고 여러 가지로 편하다.
그러나 실무에서 사용하기에는 한계가 있다. 연결 테이블이 단순히 연결만 하고 끝나지 않는다.
주문시간, 수량 같은 데이터가 연결 테이블에 들어가야 할 수 있다.
이렇게 컬럼을 추가하면 @ManyToMany를 사용할 수 없다. 실전에서는 고로 @ManyToMany를 사용하지 않는다.
그러므로 다대다 한계를 극복하기 위해 연결 테이블용 엔티티를 추가한다. 연결 테이블을 엔티티로 승격시키는 것이다.
@ManyToMany -> @OneToMany, @ManyToOne
다대다를 해석한 엔티티와 테이블은 아래와 이미지와 같다.
주문 엔티티 코드는 아래와 같다.
@Entity
public class Order{
@Id @GeneratedValue
@Column( name = "ORDER_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "MEBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUC_ID")
private Product product;
private int orderAmount;
}
회원 엔티티와 상품 엔티티 코드는 아래와 같다.
@Entity
public class Member{
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<Order>();
}
@Entity
public class Product{
@Id @Column(name = "PRODICT_ID")
private String id;
private String name;
}
요구 사항이 상품은 주문을 참조할 이유가 없어서 별도의 멤버 변수를 만들지 않았다.
참고자료
자바 ORM 표준 JPA 프로그래밍 - 김영한
자바 ORM 표준 JPA 프로그래밍 강의 - https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
2023. 02.07 15:00 정리 및 복습 마무리
댓글