Blog

[Spring][JPA]49 Entity 연관관계 N:1, 1:N, 1:1, N:M 맵핑 및 방향

Category
Author
Tags
PinOnMain
1 more property
연관관계 매핑시 고려사항 3가지
다중성
다대일 : @ManyToOne (가장 많이 사용)
일대다 : @OneToMany
일대일 : @OneToOne
다대다 : @ManyToMany (실무에서 사용하지 않음)
단방향, 양방향
테이블
외래키 하나로 양쪽 조인 가능
사실 방향이라는 개념이 없음
객체
참조용 필드가 있는 쪽으로만 참조 가능
한쪽만 참조하면 단방향
양쪽이 서로 참조하면 양방향 ( 사실 단방향 참조가 2개 있는 구조!)
연관관계의 주인
테이블은 외래키 하나로 두 테이블이 연관관계를 맺음
객체 양방향 관계는 A → B, B → A 처럼 참조가 2군데
객체 양방향 관계는 참조가 2군데 있음. 둘 중 테이블의 외래키를 관리할 곳을 지정해야 함
연관관계의 주인 : 외래키를 관리하는 참조
주인의 반대편 : 외래키에 영향을 주지 않음. 단순 조회만 가능(읽기)
다대일[N:1] 연관관계
다대일[N:1] 단방향
가장 많이 사용하는 연관관계
다대일의 반대는 일대다
항상 다(N)쪽에 외래키가 들어가야 함!
@Entity public class Member { @Id private Long id; @Column(name = "name") private String username; private Integer age; @ManyToOne//다대일 단방향 연관관계 @JoinColumn(name = "TEAM_ID") private Team team; } // Team Entity에는 참조가 필요하지 않음
Java
복사
@ManyToOne 주요속성
다대일 관계 매핑
속성
설명
기본값
optional
false로 설정하면 연관된 엔티티가 항상 있어야 한다.
TRUE
fetch
글로벌 페치 전략 설정
- @ManyToOne=FetchType.EAGER - @OneToMany=FetchType.LAZY
cascade
영속성 전이 기능 사용
targetEntity
연관된 엔티티의 타입 정보 설정거의 사용되지 않는 기능(컬렉션, 제네릭으로 타입 정보 알 수 있음)
다대일[N:1] 양방향
외래키가 있는 쪽이 연관관계 주인
양쪽을 서로 참조하도록 개발
@Entity public class Member { @Id private Long id; @Column(name = "name") private String username; private Integer age; @ManyToOne//다대일 단방향 연관관계 @JoinColumn(name = "TEAM_ID") private Team team; } // 양방향 매핑 - Team 엔티티는 컬렉션 추가@Entity public class Team { @Id private Long id; @Column(name = "name") private String name; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<Member>(); }
Java
복사
일대다[1:N] 연관관계
→ 권장하지 않는 모델 (운영환경에서는 두 테이블을 관리해야 해서 헷갈리기 쉬움)
일대다[1:N] 단방향
일대다 단방향은 일대다(1:N)에서 일(1)이 연관관계의 주인
테이블 일대다 관계는 항상 다(N) 쪽에 외래키가 있음
객체와 테이블의 차이 때문에 반대편 테이블의 외래키를 관리하는 특이한 구조
@JoinColumn을 꼭 사용해야 함. 그렇지 않으면 조인 테이블 방식을 사용함 (중간에 테이블 추가)
일대다 단방향 매핑의 단점
엔티티가 관리하는 외래키가 다른 테이블에 있음
연관관계 관리를 위해 추가로 UPDATE SQL 실행
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자
// 일대다 단방향 매핑 - Team 엔티티 컬렉션 추가 @Entity public class Team { @Id private Long id; @Column(name = "name") private String name; @OneToMany @JoinColumn(name = "TEAM_ID") private List<Member> members = new ArrayList<Member>(); } @Entity public class Member {// 단방향이기에 Member에는 참조 추가 안함 @Id private Long id; @Column(name = "name") private String username; private Integer age; }
Java
복사
@OneToMany 주요속성
다대일 관계 매핑
속성
설명
기본값
mappedBy
연관관계의 주인 필드를 선택
fetch
글로벌 페치 전략 설정
- @ManyToOne=FetchType.EAGER - @OneToMany=FetchType.LAZY
cascade
영속성 전이 기능 사용
targetEntity
연관된 엔티티의 타입 정보 설정거의 사용되지 않는 기능 (컬렉션, 제네릭으로 타입 정보 알 수 있음)
일대다[1:N] 양방향
이런 매핑은 공식적으로 존재하지 않음
@JoinColumn(**insertable = false, updatable = false**)
읽기 전용 필드를 사용해서 양방향처럼 사용하는 방법
다대일 양방향을 사용하자!
// 일대다 매핑 - Team 엔티티 컬렉션 추가 @Entity public class Team { @Id private Long id; @Column(name = "name") private String name; @OneToMany @JoinColumn(name = "TEAM_ID") private List<Member> members = new ArrayList<Member>(); } @Entity public class Member {// 양방향이기에 Member에는 참조 추가 (insert, update 불가 설정)@Id private Long id; @Column(name = "name") private String username; private Integer age; @ManyToOne @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false) private Team team; }
Java
복사
일대일[1:1] 연관관계
일대일 관계
일대일 관계는 그 반대도 일대일
주 테이블이나 대상 테이블 중에 외래키 선택 가능
주 테이블에 외래키
대상 테이블에 외래키
외래키에 데이터베이스 유니크(UNI) 제약조건 추가
일대일: 주 테이블에 외래키 단방향
다대일(@ManyToOne) 단방향 매핑과 유사
// 일대일 단방향 매핑 @Entity public class Member { @Id private Long id; @Column(name = "name") private String username; private Integer age; @OneToOne @JoinColumn(name = "LOCKER_ID") private Locker locker; }
Java
복사
일대일: 주 테이블에 외래키 단방향
다대일 양방향 매핑처럼 외래키가 있는 곳이 연관관계의 주인
반대편은 mappedBy 적용
// 일대일 양방향 매핑 @Entity public class Member { @Id private Long id; @Column(name = "name") private String username; private Integer age; @OneToOne @JoinColumn(name = "LOCKER_ID") private Locker locker; } @Entity public class Locker { @Id private Long id; @Column private String name; @OneToOne(mappedBy = "locker") private Member member;//읽기전용 }
Java
복사
일대일: 대상 테이블에 외래키 단방향
일대일 대상 테이블 외래키 단방향 관계는 JPA 지원 안함
양방향 관계는 지원
일대일: 대상 테이블에 외래키 양방향
사실 일대일 주 테이블에 외래키 양방향 매핑 방법은 같음
일대일 관계 정리
주 테이블에 외래 키
주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래키를 두고 대상 테이블을 찾음
객체지향 개발자 선호
JPA 매핑 편리
장점 : 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
단점 : 값이 없으면 외래키에 null 허용
대상 테이블에 외래키
대상 테이블에 외래키가 존재
전통적인 데이터베이스 개발자 선호
장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
단점 : 프록시 기능의 한계로 지연 로딩으로 설정해서 항상 즉시 로딩됨
다대다[N:M] 연관관계
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음! 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 함
객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 가능
@ManyToMany 어노테이션 사용 (연결테이블이 자동으로 생성됨 : PK, FK 지정되어 매핑 정보로 자동 생성)
*@JoinTable**로 연결 테이블 지정
다대다 매핑 : 단방향, 양방향 가능
다대다 매핑의 한계
편리해보이지만 실무에서 사용하지 않음
연결 테이블이 단순히 연결만 하고 끝나지 않음
주문시간, 수량 같은 데이터가 들어올 여지가 있음
다대다 한계 극복
연결 테이블용 엔티티 추가(연결 테이블을 엔티티로 승격)
@ManyToMany → @OneToMany, @ManyToOne
@Entity public class MemberProduct {// 연결 테블용 엔티티 @Id @GeneratedValue 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; private LocalDateTime orderDateTime; } @Entity public class Member { @Id private Long id; @Column(name = "name") private String username; private Integer age; @OneToMany(mappedBy = "member") private List<MemberProduct> memberProducts = new ArrayList<>(); } @Entity public class Product { @Id private Long id; @Column(name = "name") private String name; @OneToMany(mappedBy = "product") private List<MemberProduct> memberProducts = new ArrayList<>(); }
Java
복사
@JoinColumn
외래키 매핑할 때 사용
속성
설명
기본값
name
매핑할 외래키 이름
필드명 + ___ + 참조하는 테이블의 기본키 컬럼명
referencedColumnName
외캐키가 참조하는 대상 테이블의 컬럼명
참조하는 테이블의 기본키 컬럼명
foreignKey(DDL)
외래키 제약조건을 직접 지정할 수 있음이 속성은 테이블 생성시에만 사용
unique nullable insertable updatable column Definitiontable
@Column의 속성과 같음
연관관계 연습했던 Github 커밋마다 변화 잘볼것
master
commits