다대일
- 다대일 단방향(N:1)
@Entity public class Member { @Id @GeneratedValue private Long id; @ManyToOne @JoinColumn(name = "team_id") private Team team; }
- 다대일 양방향(N:1, 1:N)
- 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
항상 다(N)에 외래 키가 있다. -> 다 쪽이 주인 - 양방향 연관관계는 항상 서로를 참조해야 한다.
- 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
일대다
- 일대다 단방향(1:N)
- 일대다 단방향 매핑의 단점은 매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다는 점이다.
즉, 본인 테이블에 외래 키가 있으면 엔티티의 저장과 연관관계 처리를 insert SQL 한 번으로 끝낼 수 있지만, 다른 테이블에 있으면 연관관계 처리를 위해 update SQL을 추가로 실행한다. - 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하는 것이 좋다.
- 일대다 단방향 매핑의 단점은 매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다는 점이다.
- 일대다 양방향(1:N, N:1)
사실 일대다 양방향 매핑은 존재하지 않는다. 하지만 완전히 불가능한 것은 아니다.
일대다 단방향 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방향 매핑을 읽기 전용으로 하나 추가하면 된다.
@Entity public class Member { @Id @GeneratedValue private Long id; @ManyToOne @JoinColumn(name = "team_id", insertable = false, updatable, false) private Team team; }
반대편인 다대일 쪽은 insertable, updatable로 읽기만 가능하게 하면된다.@Entity public class Team { @Id @GeneratedValue private Long id; //mappedBy 속성 사용 x @OneToMany @JoinColumn(name = "team_id") private List<Member> memberList = new ArrayList<>(); }
하지만 이 방법도 일대다 단방향 매핑이 가지는 단점을 그대로 가지기 때문에 추천하지 않는다.
일대일
- 일대일 관계는 그 반대도 일대일 관계다.
- 주 테이블이나 대상 테이블 둘 중 어느곳이나 외래 키를 가질 수 있다.
다대다
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
그래서 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다.

객체는 테이블과 다르게 객체 2개로 다대다 관계를 만들 수 있다.
다대다 : 단방향
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
@ManyToMany
@JoinTable(name = "member_product",
joinColumns = @JoinColumn(name = "member_id"),
inverseJoinColumns = @JoinColumn(name = "product_id"))
private List<Product> productList = new ArrayList<>();
}
- @JoinTable.name : 연결 테이블을 지정한다.
- @JoinTable.joinColumns : 현재 방향인 엔티티와 매핑할 조인 컬럼 정보를 지정한다.
- @JoinTable.inverseJoinColumns : 반대 방향인 엔티티와 매핑할 조인 컬럼 정보를 지정한다.
다대다 : 양방향
@Entity
public class Product {
@Id
@GeneratedValue
@Column(name = "product_id")
private Long id;
@ManyToMany(mappedBy = "productList")
private List<Member> memberList = new ArrayList<>();
}
역방향도 @ManyToMany를 사용하고 mappedBy를 지정한다.
다대다 : 매핑의 한계와 극복, 연결 엔티티 사용
연결 테이블에 컬럼을 추가하게 되면 더이상 @ManyToMany를 사용할 수 없다.
왜냐하면 각각 회원, 상품 엔티티에 추가한 칼럼들을 사용할 수 없기 때문이다.

그럼 결국 연결 테이블을 매핑하는 연결 엔티티를 만들고 이곳에 추가한 컬럼들은 매핑해야 한다.
그리고 엔티티 간의 관계도 테이블 관계처럼 다대다에서 일대다, 다대일 관계로 풀어야한다.
회원 엔티티
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String memberName;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProductList
}
상품 엔티티
@Entity
public class Product {
@Id
@GeneratedValue
@Column(name = "product_id")
private Long id;
private String productName;
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProductList
}
연결 엔티티
@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {
@Id
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@Id
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
private int orderAmount;
private LocalDate orderDate;
}
회원상품 식별자 클래스
public class MemberProductId implements Serializable {
private String member;
private String product;
@Override
public boolean equals(Object o) { ... }
@Override
public int hashcode() { ... }
}
회원상품(MemberProduct.) 엔티티를 보면 기본 키를 매핑하는 @Id와 외래 키를 매핑하는 @JoinColumn을 동시에 사용해서 기본 키 + 외래 키를 한번에 매핑 했다.
그리고 @IdClass를 사용해서 복합 기본 키를 매핑했다.
복합 기본 키
회원상품 엔티티는 기본 키가 member_id와 product_id로 이루어진 복합 기본 키다.
JPA에서 복합 키를 사용하려면 별도의 식별자 클래스를 만들어야 한다.
- 복합 키는 별도의 식별자 클래스로 만들어야 한다.
- Serializable을 구현해야 한다.
- equals와 hashCode 메소드를 구현해야 한다.
- 기본 생성자가 있어야 한다.
- 식별자 클래스는 public이어야 한다.
- @IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.
다대다 : 새로운 기본 키 사용
위의 복합 키를 사용하는 방법 말고 추천하는 기본 키 생성 전략은 데이터베이스에서 자동으로 생성해주는 대리 키를 Long 값으로 하는 것이다.

회원 엔티티
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String memberName;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProductList
}
상품 엔티티
@Entity
public class Product {
@Id
@GeneratedValue
@Column(name = "product_id")
private Long id;
private String productName;
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProductList
}
회원상품 엔티티
@Entity
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 orderAmount;
private LocalDate orderDate;
}
대리키를 사용함으로써 이전에 보았던 식별 관계에 복합 키를 사용하는 것보다 매핑이 단순하고 쉽다.
'Spring JPA' 카테고리의 다른 글
프록시와 연관관계 관리 - 11 (0) | 2021.07.13 |
---|---|
고급 매핑 - 10 (0) | 2021.07.12 |
연관관계 매핑 기초 - 8 (0) | 2021.07.06 |
엔티티 매핑 - 7 (0) | 2021.07.03 |
영속성 관리 - 6 (0) | 2021.06.29 |
댓글